-
Notifications
You must be signed in to change notification settings - Fork 66
Conversation
src/commands/convert.js
Outdated
@@ -2,7 +2,7 @@ const utils = require('../utils'); | |||
const constants = require('../constants'); | |||
|
|||
const convert = (context, appid, location) => { | |||
context.line('Welcome to the Zapier Platform! :-D'); | |||
context.line('Welcome to the Zapier Platform!'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we even need this message at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, not really!
package.json
Outdated
"lint-snippets": "eslint snippets --rule 'no-unused-vars: 0' --ignore-pattern snippets/next.js --ignore-pattern 'snippets/dynamic-dropdowns-*'", | ||
"lint": "eslint zapier.js src", | ||
"postlint": "npm run lint-snippets", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work @xavdid! I like the leveraging of the current convert
tool—great decision. We will still need to tweak its internals a bit. Especially for getting dynamicInputs
which are in a broken state as is. I'm marking as Request Changes for that, but the rest is suggestions, questions, and such.
A few thoughts:
- Would we want devs to run without passing a version? I would expect most would want to use the latest version to convert.
- Do we want to order the fields in
index.js
? It'd be nice if they were properly sorted like the minimal example app. - What about instead of using conditionals to fork logic, what if we had handlers for each source? (legacyHandler, vbHandler). Might be a little easier to follow, although we only have two choices right now. Other app sources could use an import command.
Still wrapping my head around what the rest of convert
is doing and where we'd need to add some new logic.
Love the tests! 💪
src/commands/convert.js
Outdated
} | ||
} | ||
utils.endSpinner(); | ||
return utils.convertVisualApp(appInfo, versionInfo, tempAppDir); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're going to throw
in the catch
why not move these two lines into the try
. Then we won't need to set empty vars.
try {
[appInfo, versionInfo] = await Promise.all([
utils.callAPI(null, { url: appInfoUrl }, true),
utils.callAPI(null, { url: versionInfoUrl }, true)
]);
utils.endSpinner();
return utils.convertVisualApp(appInfo, versionInfo, tempAppDir);
} catch (e) {
throw ...
src/utils/convert.js
Outdated
const convertApp = async (appInfo, appDefinition, newAppDir, opts = {}) => { | ||
const defaultOpts = { silent: false, legacy: true }; | ||
// need to bump babel so this works | ||
// const { silent, legacy } = { ...defaultOpts, ...opts }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spread operator works in node v8. We can either lose these comments or switch to that syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for sure. Our current version of babel throws an error here, so I think i'll:
- merge try removing babel #430
- merge develop back into this PR,
- uncomment this
i'll do that after we're 👍 though to keep this PR cleaner. I think the babel one will make it loud
src/utils/convert.js
Outdated
}; | ||
|
||
const convertApp = async (appInfo, appDefinition, newAppDir, opts = {}) => { | ||
const defaultOpts = { silent: false, legacy: true }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason to even have silent? I may be missing where it's actually used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the only reason is the tests.
with silent:
$ NODE_ENV=test mocha -t 50000 --recursive lib/tests
convert
visual apps apps
✓ should create separate files (110ms)
1 passing (125ms)
✨ Done in 3.65s.
without silent:
$ NODE_ENV=test mocha -t 50000 --recursive lib/tests
convert
visual apps apps
✔ Writing .gitignore
✔ Writing triggers/project.js
✔ Writing package.json
✔ Writing creates/create_project.js
✔ Writing .env
✔ Writing authentication.js
✔ Writing .zapierapprc
✔ Writing .zapierapprc
✔ Writing triggers/codemode.js
✔ Writing index.js
✔ Writing test/creates/create_project.js
✔ Writing test/triggers/project.js
✔ Writing test/triggers/codemode.js
✓ should create separate files (115ms)
1 passing (132ms)
✨ Done in 3.66s.
Could get a similar effect by only logging if NODE_ENV !== 'TEST'
if we wanted to simplify it a little bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @xavdid! That makes sense.
NODE_ENV
could be a good option. No strong feelings one way or the other.
src/tests/utils/convert.js
Outdated
}); | ||
}); | ||
|
||
describe.only('visual apps apps', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to add eslint-jest
to prevent these from making it into PRs. I've snuck those into PRs a few times and didn't catch until later.
src/tests/utils/convert.js
Outdated
params: {}, | ||
method: 'POST' | ||
}, | ||
inputFields: [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you clarify what you mean by dynamic input field? I know in CLI we can have custom fields, but I didn't think that was something that was possible in godzilla
was only looking in triggers, not actions. found it and fixed it
src/commands/convert.js
Outdated
utils.callAPI(null, { url: cliDumpUrl }) | ||
]); | ||
utils.startSpinner('Downloading app from Zapier'); | ||
let [legacyApp, appDefinition] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here as the vb-way above.
src/tests/utils/convert.js
Outdated
create_project: { | ||
operation: { | ||
perform: { | ||
body: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to keep shorthand requests in a CLI integration? Do we care about encouraging using curlies within CLI? Not a big deal now that we support it because of Godzilla. Just wanted to point out that we'll be encouraging devs to rely on curly string replacement rather in core than regular ol' JS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we do want to keep the shorthand requests. They provide some nice auto error-handling and other sugar that are perfectly reasonable to rely on if you don't need a more complex request. Curlies should also be fine, though #428 makes me a little worried about that.
src/utils/convert.js
Outdated
|
||
return await Promise.all(promises); | ||
}; | ||
|
||
const convertVisualApp = async ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would you say to re-organizing this slightly? This assumes we drop silent
, but we could still keep it if we really wanted. We could pass in definition_override
rather than versionInfo
and use partial application to simplify these to functions:
const makeConvertApp = options => (info, def, dir) => ..stuff
const convertVisual = makeConvertApp({ legacy: false });
const convertLegacy = makeConvertApp({ legacy: true });
or if we thought we might want to call convertApp
directly in the future, we could still change the signature of convertApp
and move options to the front
const convertApp = (options, info, def, dir) => ...stuff
const convertVisual = convertApp.bind(null, { legacy: false });
// or with lodash
const convertLegacy = _.partial(convertApp, { legacy: true });
Also, no need to wrap in async
since we're not await
ing anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do you one better - we can _.partialRight
and not move any of the args!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And boom goes the dynamite 💥
|
||
return await utils.convertApp(legacyApp, appDefinition, tempAppDir); | ||
return utils.convertLegacyApp(legacyApp, appDefinition, tempAppDir); | ||
} | ||
}; | ||
|
||
return utils.initApp(context, location, createApp).then(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not instead of asking for the project location, we use the same string that we put in name
for the package.json
? (kebab-cased app title) I think it'd be rare that a dev would want those names to be different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mostly so that devs can run the command from anywhere. zapier convert 1234 ../../projects
. Since we're writing (and potentially overwriting) files, seems good to be explicit about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hear you. I wonder if that's what most do?
It'd be nice to have the option to just run zapier convert
, get a list of integrations, pick the integration I want, and confirm things like version and/or location. Not for this PR—just thinking out loud.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
totally. I think this is good to get it out and we can revisit it at some point.
}); | ||
|
||
describe.only('visual apps apps', () => { | ||
it('should create separate files', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if we need tests to verify the output of files 🤔 For instance, to ensure we get dynamic inputs, functions are correctly written, files are ordered correctly, etc.
Maybe overkill?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nah, more tests are good! I can cover a couple of key cases in there.
Great questions!
const convertLegacyApp(...) => {
a()
b()
c()
d()
}
const convertVisualApp(...) => {
a()
b()
j()
k()
d()
} where we move a lot of the logic into the reused functions. I like that, but worry that if we decide we want to add something after |
ok, addressed most of those. let me know what you feel strongly about and we can get this over the line! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes and tests @xavdid! I think this is looking good. Couple more questions, but nothing I'd call a blocker.
Re the handler approach, I was thinking more instead of:
if (isVb) {
const preprocessed = ...doSomeVbStuff
convertVb(preprocessed);
} else {
const preprocessed = ...doSomeWbStuff
convertLegacy(preprocessed);
}
we might do something like (total pseudo-code):
const convert = getConvertHandler(sourceType);
convert(appData);
The idea being, we'd encapsulate what would be a separate conditional block in each handler. Maybe a pre-mature optimization at this point.
const args = maybeFunc.args || ['z', 'bundle']; | ||
// always increment the number, but only return a value if it's > 0 | ||
const funcName = `get${_.upperFirst(key)}${ | ||
funcNum ? funcNum++ : ++funcNum && '' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. So it would go as getInputFields
, getInputField1
, getInputFields2
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep! read then increment.
> let i = 0
undefined
> console.log(i++)
0
undefined
> i
1
> i
1
> console.log(i++)
1
undefined
> i
2
> console.log(++i)
3
undefined
> i
3
> console.log(++i)
4
undefined
> i
4
@@ -2,11 +2,7 @@ const utils = require('../utils'); | |||
const constants = require('../constants'); | |||
|
|||
const convert = (context, appid, location) => { | |||
context.line('Welcome to the Zapier Platform! :-D'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be really cool here to clear out the location folder if it exists. I forgot to pass version to the tool, and it converted my vb app as if it was WB. When I ran it again, it just added to folder rather than replace it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good call out. there's another place we check for an empty folder- we can borrow that behavior.
Do we still have a separate ticket to build out the interface for this command? I thought there was also a ticket that would output a list of integration you had before executing the convert. It's PDE-797 |
We still have a separate ticket, but a lot of that work is in this one. We can launch this as is ASAP, but for the next major we could change the UI to have a nice selection setup. So many plates in the air! |
Ah, so it turns out sorting keys is possible, but non-trivial if you have nested objects (which we do, in spades): https://stackoverflow.com/a/16168003/1825390 I'll skip for now but it'd be a nice cleanup thing to come back to (or render manually sometime). I'm going to go ahead and merge this as is. |
Standing on the shoulders of other great work, this ended up being pretty straightforward!
I liked the idea of re-using the command. That, plus adding the
version
option, makes it pretty straightforward.There are a couple of different methods based on differences between what we need for visual/legacy, but the similarity made that part really easy.
I've been testing with the following:
zapier convert 17741 a --version=1.0.1
, which is a dev-app-school wistia app. I've confirmed that you can convert, push a new version, and make a new zap (auth + trigger) successfully.