-
Notifications
You must be signed in to change notification settings - Fork 187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PDE-5321 feat(cli): zapier invoke
command
#856
Conversation
zapier invoke
command - WIPzapier invoke
command
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.
Neat! I tested the (probably) main usage patterns:
zapier invoke fakeaction fish
and got validation err (Error: Expected triggers to be one of: auth, trigger, search, create
)zapier invoke auth test
andlabel
with no .envzapier invoke auth test
andlabel
with .envzapier invoke triggers fish
and got validation error (Error: Expected triggers to be one of: auth, trigger, search, create
)zapier invoke trigger fish
zapier invoke search recipe
and it fetched required input fieldszapier invoke search recipe --inputData {"name": "eggs"}
and got validation err ( parse error near `}zapier invoke search recipe --inputData '{"name": "eggs"}'
zapier invoke create recipe --inputData '{"name": "eggs"}'
zapier invoke create recipe --inputData @test_input_data_file.json
(with correct data)zapier invoke create recipe --inputData @test_input_data_file.json
(with bad data, and got prompt with required input fields)zapier invoke create recipe
(with dynamic dropdown from fish trigger)
I tested all the supported input field options (left some comments below)
bundle: { | ||
inputData, | ||
authData, |
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 noticed in my testing - with --debug
passed in
I kind of expected to see what the final API call might look like, even if we omit authData, perhaps inputData?
staging/caroline [ zl invoke create recipe --debug ] 11:00 am
zapier:invoke argv is [ 'create', 'recipe', '--debug' ] +0ms
zapier:invoke args are { actionType: 'create', actionKey: 'recipe' } +1ms
zapier:invoke flags are {
debug: true,
isLoadingSample: false,
isFillingDynamicDropdown: false,
isPopulatingDedupe: false,
limit: -1,
page: 0,
timezone: 'America/Chicago'
} +0ms
zapier:invoke ------------ +0ms
zapier:invoke Action type: create +0ms
zapier:invoke Action key: recipe +0ms
zapier:invoke Action label: Create Recipe +0ms
⠋ Invoking creates.recipe.operation.inputFields zapier:analytics sending {
command: 'invoke',
isValidCommand: true,
numArgs: 2,
flags: {
debug: true,
isLoadingSample: false,
isFillingDynamicDropdown: false,
isPopulatingDedupe: false,
limit: -1,
page: 0,
timezone: 'America/Chicago'
},
cliVersion: '15.15.0',
os: 'darwin',
sendUserId: true
} +0ms
✔ Invoking creates.recipe.operation.inputFields
zapier:invoke inputFields: [
{ key: 'name', required: true },
{ key: 'directions', required: false },
{ key: 'style', required: false }
] +17ms
? Required input field "name" (string): zapier:api >> POST undefined +0ms
zapier:api >> {"command":"invoke","isValidCommand":true,"numArgs":2,"flags":{"debug":true,"isLoadingSample":false,"isFillingDynamicDropdown":false,"isPopulatingDedupe":false,"limit":-1,"page":0,"timezone":"America/Chicago"},"cliVersion":"15.15.0","os":"darwin"} +0ms
zapier:api << 400 +0ms
zapier:api << {"errors": ["Unknown CLI command"]} +0ms
zapier:api ------------ +0ms
zapier:analytics err: "https://zapier-staging.com/api/platform/cli/analytics" returned "400" saying "Unknown CLI command" +172ms
? Required input field "name" (string):
? Would you like to fill optional input fields? Select "DONE" when you are ready to invoke the action. DONE
✔ Invoking creates.recipe.operation.perform
{
"name": "",
"music": "pop",
"id": "bOEe2~p"
}
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 catch! Included the logs in 74da163. I haven't figured out how to make debug()
play nicely with ora
(the spinner thing), so the output is not pretty, but it's a start.
To test, you'd need to yarn link zapier-platform-core
in your integration so it uses the development version of platform-core.
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! I see it, it's helpful to debug. Thanks!
const parseInteger = (s) => { | ||
const n = parseInt(s); | ||
if (!isNaN(n)) { | ||
return n; | ||
} | ||
return Math.floor(parseDecimal(s)); | ||
}; |
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 tried putting a decimal in, but got a s is not iterable
pointing to the for loop in parseDecimal
Should s
be a string in this case?
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 expect inputData
should not contain non-string primitives (but could have a nested structure) to emulate the Zap editor. Added a check in 72dcad6.
const parseBoolean = (s) => { | ||
s = s.toLowerCase(); | ||
if (TRUE_STRINGS.has(s)) { | ||
return true; | ||
} | ||
if (FALSE_STRINGS.has(s)) { | ||
return false; | ||
} | ||
return Boolean(s); | ||
}; |
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 found this a bit unintuitive - even though it looks like it should help.
For example,
$ zl invoke create recipe --inputData '{"name": "eggs", "style": "no" }'
✔ Invoking creates.recipe.operation.perform
{
"name": "eggs",
"music": "pop",
"fish_type": "qui est esse",
"style": false,
"id": "RXU237w"
}
$ zl invoke create recipe --inputData '{"name": "eggs", "style": "noo" }'
✔ Invoking creates.recipe.operation.perform
{
"name": "eggs",
"music": "pop",
"fish_type": "qui est esse",
"style": false,
"id": "sqAM~d4"
}
$ zl invoke create recipe --inputData '{"name": "eggs", "style": "nooo" }'
✔ Invoking creates.recipe.operation.perform
{
"name": "eggs",
"music": "pop",
"fish_type": "qui est esse",
"style": true,
"id": "4dDws4N"
}
Does it make more sense to have strict true/false validation here?
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 wrote it this way to match this function in production.
timezone: flags.string({ | ||
char: 'z', | ||
description: | ||
'Set the default timezone for datetime fields. If not set, defaults to America/Chicago, which matches Zapier production behavior.', |
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 people can infer from the timezone string American/Chicago
but would it be helpful to provide a link for options?
i.e.: https://data.iana.org/time-zones/tzdb-2021a/zone1970.tab
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.
This looks good, thanks for the changes
Introducing a new command
zapier invoke
, the following is mostly copied from the help text withzapier invoke --help
.invoke
Usage:
zapier invoke [ACTIONTYPE] [ACTIONKEY]
This command emulates how Zapier production environment would invoke your integration. It runs code locally, so you can use this command to quickly test your integration without deploying it to Zapier. This is especially useful for debugging and development.
This command loads
authData
from the.env
file in the current directory. Create a.env
file with the necessary auth data before running this command. Each line in.env
should be in the formatauthData_FIELD_KEY=VALUE
. For example, an OAuth2 integration might have a.env
file like this:To test if the auth data is correct, run either one of these:
Then you can test an trigger, a search, or a create action. For example, this is how you invoke a trigger with key
new_recipe
:To add input data, use the
--inputData
flag. The input data can come from the command directly, a file, or stdin. See EXAMPLES below.The following are current limitations and may be supported in the future:
zapier invoke auth start
to help you initialize the auth data in.env
zapier invoke auth refresh
to refresh the auth data in.env
Arguments
actionType
| The action type you want to invoke.actionKey
| The trigger/action key you want to invoke. If ACTIONTYPE is "auth", this can be "test" or "label".Flags
-i, --inputData
| The input data to pass to the action. Must be a JSON-encoded object. The data can be passed from the command directly like '{"key": "value"}', read from a file like @file.json, or read from stdin like @-.--isLoadingSample
| Set bundle.meta.isLoadingSample to true. When true in production, this run is initiated by the user in the Zap editor trying to pull a sample.--isFillingDynamicDropdown
| Set bundle.meta.isFillingDynamicDropdown to true. Only makes sense for a polling trigger. When true in production, this poll is being used to populate a dynamic dropdown.--isPopulatingDedupe
| Set bundle.meta.isPopulatingDedupe to true. Only makes sense for a polling trigger. When true in production, the results of this poll will be used initialize the deduplication list rather than trigger a Zap. This happens when a user enables a Zap.--limit
| Set bundle.meta.limit. Only makes sense for a trigger. When used in production, this indicates the number of items you should fetch. -1 means no limit. Defaults to-1
.-p, --page
| Set bundle.meta.page. Only makes sense for a trigger. When used in production, this indicates which page of items you should fetch. First page is 0.-z, --timezone
| Set the default timezone for datetime fields. If not set, defaults to America/Chicago, which matches Zapier production behavior. Defaults toAmerica/Chicago
.-d, --debug
| Show extra debugging output.Examples
zapier invoke
zapier invoke auth test
zapier invoke trigger new_recipe
zapier invoke create add_recipe --inputData '{"title": "Pancakes"}'
zapier invoke search find_recipe -i @file.json
cat file.json | zapier invoke trigger new_recipe -i @-