zapier-platform-cli 17.0.4 → 17.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -111,11 +111,6 @@
111
111
  "convert": {
112
112
  "aliases": [],
113
113
  "args": {
114
- "integrationId": {
115
- "description": "To get the integration/app ID, go to \"https://developer.zapier.com\", click on an integration, and copy the number directly after \"/app/\" in the URL.",
116
- "name": "integrationId",
117
- "required": true
118
- },
119
114
  "path": {
120
115
  "description": "Relative to your current path - IE: `.` for current directory.",
121
116
  "name": "path",
@@ -124,11 +119,64 @@
124
119
  },
125
120
  "description": "Convert a Visual Builder integration to a CLI integration.\n\nThe resulting CLI integration will be identical to its Visual Builder version and ready to push and use immediately!\n\nIf you re-run this command on an existing directory it will leave existing files alone and not clobber them.\n\nYou'll need to do a `zapier push` before the new version is visible in the editor, but otherwise you're good to go.",
126
121
  "flags": {
122
+ "integrationId": {
123
+ "char": "i",
124
+ "dependsOn": [
125
+ "version"
126
+ ],
127
+ "description": "To get the integration/app ID, go to \"https://developer.zapier.com\", click on an integration, and copy the number directly after \"/app/\" in the URL.",
128
+ "exclusive": [
129
+ "definition"
130
+ ],
131
+ "name": "integrationId",
132
+ "required": false,
133
+ "hasDynamicHelp": false,
134
+ "type": "option"
135
+ },
127
136
  "version": {
128
137
  "char": "v",
138
+ "dependsOn": [
139
+ "integrationId"
140
+ ],
129
141
  "description": "Convert a specific version. Required when converting a Visual Builder integration.",
130
142
  "name": "version",
131
- "required": true,
143
+ "required": false,
144
+ "hasDynamicHelp": false,
145
+ "multiple": false,
146
+ "type": "option"
147
+ },
148
+ "json": {
149
+ "char": "j",
150
+ "description": "The JSON definition to use, as alternative for reading from a Visual Builder integration. 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 @-.",
151
+ "exclusive": [
152
+ "integrationId"
153
+ ],
154
+ "name": "json",
155
+ "required": false,
156
+ "hasDynamicHelp": false,
157
+ "multiple": false,
158
+ "type": "option"
159
+ },
160
+ "title": {
161
+ "char": "t",
162
+ "dependsOn": [
163
+ "json"
164
+ ],
165
+ "description": "The integration title, which will be snake-cased for the package.json name.",
166
+ "name": "title",
167
+ "required": false,
168
+ "hasDynamicHelp": false,
169
+ "multiple": false,
170
+ "type": "option"
171
+ },
172
+ "description": {
173
+ "char": "d",
174
+ "dependsOn": [
175
+ "json"
176
+ ],
177
+ "description": "The integration description, which will be used for the package.json description.",
178
+ "name": "description",
179
+ "required": false,
132
180
  "hasDynamicHelp": false,
133
181
  "multiple": false,
134
182
  "type": "option"
@@ -178,9 +226,11 @@
178
226
  "required": true
179
227
  }
180
228
  },
181
- "description": "Mark a non-production version of your integration as deprecated, with removal by a certain date.\n\nUse this when an integration version will not be supported or start breaking at a known date.\n\nZapier will immediately send emails warning users of the deprecation if a date less than 30 days in the future is set, otherwise the emails will be sent exactly 30 days before the configured deprecation date.\n\nThere are other side effects: they'll start seeing it as \"Deprecated\" in the UI, and once the deprecation date arrives, if the Zaps weren't updated, they'll be paused and the users will be emailed again explaining what happened.\n\nDo not use deprecation if you only have non-breaking changes, such as:\n- Fixing help text\n- Adding new triggers/actions\n- Improving existing functionality\n- other bug fixes that don't break existing automations.",
229
+ "description": "Mark a non-production version of your integration as deprecated, with removal by a certain date.\n\nUse this when an integration version will not be supported or start breaking at a known date.\n\nWhen deprecating a version, you must provide a reason for the deprecation. You can either specify the reason using the --reason flag or you will be prompted to select from the following options:\n- API endpoint deprecated\n- Security vulnerability\n- Critical bug\n- Legal requirement\n- Other\n\nZapier will immediately send emails warning users of the deprecation if a date less than 30 days in the future is set, otherwise the emails will be sent exactly 30 days before the configured deprecation date.\n\nThere are other side effects: they'll start seeing it as \"Deprecated\" in the UI, and once the deprecation date arrives, if the Zaps weren't updated, they'll be paused and the users will be emailed again explaining what happened.\n\nDo not use deprecation if you only have non-breaking changes, such as:\n- Fixing help text\n- Adding new triggers/actions\n- Improving existing functionality\n- other bug fixes that don't break existing automations.",
182
230
  "examples": [
183
- "zapier deprecate 1.2.3 2011-10-01"
231
+ "zapier deprecate 1.2.3 2011-10-01",
232
+ "zapier deprecate 1.2.3 2011-10-01 --reason=security_vulnerability",
233
+ "zapier deprecate 1.2.3 2011-10-01 -r critical_bug"
184
234
  ],
185
235
  "flags": {
186
236
  "force": {
@@ -190,6 +240,21 @@
190
240
  "allowNo": false,
191
241
  "type": "boolean"
192
242
  },
243
+ "reason": {
244
+ "char": "r",
245
+ "description": "Reason for deprecation.",
246
+ "name": "reason",
247
+ "hasDynamicHelp": false,
248
+ "multiple": false,
249
+ "options": [
250
+ "api endpoint deprecated",
251
+ "security vulnerability",
252
+ "critical bug",
253
+ "legal requirement",
254
+ "other"
255
+ ],
256
+ "type": "option"
257
+ },
193
258
  "debug": {
194
259
  "char": "d",
195
260
  "description": "Show extra debugging output.",
@@ -1630,6 +1695,88 @@
1630
1695
  "clear.js"
1631
1696
  ]
1632
1697
  },
1698
+ "delete:integration": {
1699
+ "aliases": [
1700
+ "delete:app"
1701
+ ],
1702
+ "args": {},
1703
+ "description": "Delete your integration (including all versions).\n\nThis only works if there are no active users or Zaps on any version. If you only want to delete certain versions, use the `zapier delete:version` command instead. It's unlikely that you'll be able to run this on an app that you've pushed publicly, since there are usually still users.",
1704
+ "flags": {
1705
+ "debug": {
1706
+ "char": "d",
1707
+ "description": "Show extra debugging output.",
1708
+ "name": "debug",
1709
+ "allowNo": false,
1710
+ "type": "boolean"
1711
+ },
1712
+ "invokedFromAnotherCommand": {
1713
+ "hidden": true,
1714
+ "name": "invokedFromAnotherCommand",
1715
+ "allowNo": false,
1716
+ "type": "boolean"
1717
+ }
1718
+ },
1719
+ "hasDynamicHelp": false,
1720
+ "hiddenAliases": [],
1721
+ "id": "delete:integration",
1722
+ "pluginAlias": "zapier-platform-cli",
1723
+ "pluginName": "zapier-platform-cli",
1724
+ "pluginType": "core",
1725
+ "strict": true,
1726
+ "enableJsonFlag": false,
1727
+ "skipValidInstallCheck": true,
1728
+ "isESM": false,
1729
+ "relativePath": [
1730
+ "src",
1731
+ "oclif",
1732
+ "commands",
1733
+ "delete",
1734
+ "integration.js"
1735
+ ]
1736
+ },
1737
+ "delete:version": {
1738
+ "aliases": [],
1739
+ "args": {
1740
+ "version": {
1741
+ "description": "Specify the version to delete. It must have no users or Zaps.",
1742
+ "name": "version",
1743
+ "required": true
1744
+ }
1745
+ },
1746
+ "description": "Delete a specific version of your integration.\n\nThis only works if there are no users or Zaps on that version. You will probably need to have run `zapier migrate` and `zapier deprecate` before this command will work.",
1747
+ "flags": {
1748
+ "debug": {
1749
+ "char": "d",
1750
+ "description": "Show extra debugging output.",
1751
+ "name": "debug",
1752
+ "allowNo": false,
1753
+ "type": "boolean"
1754
+ },
1755
+ "invokedFromAnotherCommand": {
1756
+ "hidden": true,
1757
+ "name": "invokedFromAnotherCommand",
1758
+ "allowNo": false,
1759
+ "type": "boolean"
1760
+ }
1761
+ },
1762
+ "hasDynamicHelp": false,
1763
+ "hiddenAliases": [],
1764
+ "id": "delete:version",
1765
+ "pluginAlias": "zapier-platform-cli",
1766
+ "pluginName": "zapier-platform-cli",
1767
+ "pluginType": "core",
1768
+ "strict": true,
1769
+ "enableJsonFlag": false,
1770
+ "skipValidInstallCheck": true,
1771
+ "isESM": false,
1772
+ "relativePath": [
1773
+ "src",
1774
+ "oclif",
1775
+ "commands",
1776
+ "delete",
1777
+ "version.js"
1778
+ ]
1779
+ },
1633
1780
  "canary:create": {
1634
1781
  "aliases": [],
1635
1782
  "args": {
@@ -1793,88 +1940,6 @@
1793
1940
  "list.js"
1794
1941
  ]
1795
1942
  },
1796
- "delete:integration": {
1797
- "aliases": [
1798
- "delete:app"
1799
- ],
1800
- "args": {},
1801
- "description": "Delete your integration (including all versions).\n\nThis only works if there are no active users or Zaps on any version. If you only want to delete certain versions, use the `zapier delete:version` command instead. It's unlikely that you'll be able to run this on an app that you've pushed publicly, since there are usually still users.",
1802
- "flags": {
1803
- "debug": {
1804
- "char": "d",
1805
- "description": "Show extra debugging output.",
1806
- "name": "debug",
1807
- "allowNo": false,
1808
- "type": "boolean"
1809
- },
1810
- "invokedFromAnotherCommand": {
1811
- "hidden": true,
1812
- "name": "invokedFromAnotherCommand",
1813
- "allowNo": false,
1814
- "type": "boolean"
1815
- }
1816
- },
1817
- "hasDynamicHelp": false,
1818
- "hiddenAliases": [],
1819
- "id": "delete:integration",
1820
- "pluginAlias": "zapier-platform-cli",
1821
- "pluginName": "zapier-platform-cli",
1822
- "pluginType": "core",
1823
- "strict": true,
1824
- "enableJsonFlag": false,
1825
- "skipValidInstallCheck": true,
1826
- "isESM": false,
1827
- "relativePath": [
1828
- "src",
1829
- "oclif",
1830
- "commands",
1831
- "delete",
1832
- "integration.js"
1833
- ]
1834
- },
1835
- "delete:version": {
1836
- "aliases": [],
1837
- "args": {
1838
- "version": {
1839
- "description": "Specify the version to delete. It must have no users or Zaps.",
1840
- "name": "version",
1841
- "required": true
1842
- }
1843
- },
1844
- "description": "Delete a specific version of your integration.\n\nThis only works if there are no users or Zaps on that version. You will probably need to have run `zapier migrate` and `zapier deprecate` before this command will work.",
1845
- "flags": {
1846
- "debug": {
1847
- "char": "d",
1848
- "description": "Show extra debugging output.",
1849
- "name": "debug",
1850
- "allowNo": false,
1851
- "type": "boolean"
1852
- },
1853
- "invokedFromAnotherCommand": {
1854
- "hidden": true,
1855
- "name": "invokedFromAnotherCommand",
1856
- "allowNo": false,
1857
- "type": "boolean"
1858
- }
1859
- },
1860
- "hasDynamicHelp": false,
1861
- "hiddenAliases": [],
1862
- "id": "delete:version",
1863
- "pluginAlias": "zapier-platform-cli",
1864
- "pluginName": "zapier-platform-cli",
1865
- "pluginType": "core",
1866
- "strict": true,
1867
- "enableJsonFlag": false,
1868
- "skipValidInstallCheck": true,
1869
- "isESM": false,
1870
- "relativePath": [
1871
- "src",
1872
- "oclif",
1873
- "commands",
1874
- "delete",
1875
- "version.js"
1876
- ]
1877
- },
1878
1943
  "env:get": {
1879
1944
  "aliases": [],
1880
1945
  "args": {
@@ -2430,5 +2495,5 @@
2430
2495
  ]
2431
2496
  }
2432
2497
  },
2433
- "version": "17.0.4"
2498
+ "version": "17.2.0"
2434
2499
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapier-platform-cli",
3
- "version": "17.0.4",
3
+ "version": "17.2.0",
4
4
  "description": "The CLI for managing integrations in Zapier Developer Platform.",
5
5
  "repository": "zapier/zapier-platform",
6
6
  "homepage": "https://platform.zapier.com/",
@@ -1,3 +1,5 @@
1
+ const fs = require('node:fs/promises');
2
+
1
3
  const { Args, Flags } = require('@oclif/core');
2
4
 
3
5
  const BaseCommand = require('../ZapierBaseCommand');
@@ -8,9 +10,40 @@ const { convertApp } = require('../../utils/convert');
8
10
  const { isExistingEmptyDir } = require('../../utils/files');
9
11
  const { initApp } = require('../../utils/init');
10
12
 
13
+ const readStream = async (stream) => {
14
+ const chunks = [];
15
+ for await (const chunk of stream) {
16
+ chunks.push(chunk);
17
+ }
18
+ return chunks.join('');
19
+ };
20
+
11
21
  class ConvertCommand extends BaseCommand {
12
- generateCreateFunc(appId, version) {
22
+ generateCreateFunc(appId, version, json, title, description) {
13
23
  return async (tempAppDir) => {
24
+ if (json) {
25
+ const appInfo = {
26
+ title,
27
+ description,
28
+ };
29
+
30
+ let parsedDefinition = json;
31
+ if (parsedDefinition.startsWith('@')) {
32
+ const filePath = parsedDefinition.substr(1);
33
+ let definitionStream;
34
+ if (filePath === '-') {
35
+ definitionStream = process.stdin;
36
+ } else {
37
+ const fd = await fs.open(filePath);
38
+ definitionStream = fd.createReadStream({ encoding: 'utf8' });
39
+ }
40
+ parsedDefinition = await readStream(definitionStream);
41
+ }
42
+ parsedDefinition = JSON.parse(parsedDefinition);
43
+
44
+ return convertApp(appInfo, parsedDefinition, tempAppDir);
45
+ }
46
+
14
47
  // has info about the app, such as title
15
48
  // has a CLI version of the actual app implementation
16
49
  this.throwForInvalidVersion(version);
@@ -41,13 +74,14 @@ class ConvertCommand extends BaseCommand {
41
74
  }
42
75
 
43
76
  async perform() {
44
- const { integrationId: appId, path } = this.args;
45
- const { version } = this.flags;
46
- if (!appId) {
47
- this.error(
48
- 'You must provide an integrationId. See zapier convert --help for more info.',
49
- );
50
- }
77
+ const { path } = this.args;
78
+ const {
79
+ integrationId: appId,
80
+ version,
81
+ json,
82
+ title,
83
+ description,
84
+ } = this.flags;
51
85
 
52
86
  if (
53
87
  (await isExistingEmptyDir(path)) &&
@@ -56,16 +90,18 @@ class ConvertCommand extends BaseCommand {
56
90
  this.exit();
57
91
  }
58
92
 
59
- await initApp(path, this.generateCreateFunc(appId, version));
93
+ if (!appId && !json) {
94
+ this.error('You must provide either an integrationId or json.');
95
+ }
96
+
97
+ await initApp(
98
+ path,
99
+ this.generateCreateFunc(appId, version, json, title, description),
100
+ );
60
101
  }
61
102
  }
62
103
 
63
104
  ConvertCommand.args = {
64
- integrationId: Args.string({
65
- description: `To get the integration/app ID, go to "https://developer.zapier.com", click on an integration, and copy the number directly after "/app/" in the URL.`,
66
- required: true,
67
- parse: (input) => Number(input),
68
- }),
69
105
  path: Args.string({
70
106
  description:
71
107
  'Relative to your current path - IE: `.` for current directory.',
@@ -75,11 +111,41 @@ ConvertCommand.args = {
75
111
 
76
112
  ConvertCommand.flags = buildFlags({
77
113
  commandFlags: {
114
+ integrationId: Args.string({
115
+ char: 'i',
116
+ description: `To get the integration/app ID, go to "https://developer.zapier.com", click on an integration, and copy the number directly after "/app/" in the URL.`,
117
+ required: false,
118
+ dependsOn: ['version'],
119
+ exclusive: ['definition'],
120
+ parse: (input) => Number(input),
121
+ }),
78
122
  version: Flags.string({
79
123
  char: 'v',
80
124
  description:
81
125
  'Convert a specific version. Required when converting a Visual Builder integration.',
82
- required: true,
126
+ required: false,
127
+ dependsOn: ['integrationId'],
128
+ }),
129
+ json: Flags.string({
130
+ char: 'j',
131
+ description:
132
+ 'The JSON definition to use, as alternative for reading from a Visual Builder integration. 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 @-.',
133
+ required: false,
134
+ exclusive: ['integrationId'],
135
+ }),
136
+ title: Flags.string({
137
+ char: 't',
138
+ description:
139
+ 'The integration title, which will be snake-cased for the package.json name.',
140
+ required: false,
141
+ dependsOn: ['json'],
142
+ }),
143
+ description: Flags.string({
144
+ char: 'd',
145
+ description:
146
+ 'The integration description, which will be used for the package.json description.',
147
+ required: false,
148
+ dependsOn: ['json'],
83
149
  }),
84
150
  },
85
151
  });
@@ -5,6 +5,14 @@ const colors = require('colors/safe');
5
5
 
6
6
  const { callAPI, getSpecificVersionInfo } = require('../../utils/api');
7
7
 
8
+ const DEPRECATION_REASONS = [
9
+ { name: 'API endpoint deprecated', value: 'api endpoint deprecated' },
10
+ { name: 'Security vulnerability', value: 'security vulnerability' },
11
+ { name: 'Critical bug', value: 'critical bug' },
12
+ { name: 'Legal requirement', value: 'legal requirement' },
13
+ { name: 'Other', value: 'other' },
14
+ ];
15
+
8
16
  class DeprecateCommand extends BaseCommand {
9
17
  async perform() {
10
18
  const app = await this.getWritableApp();
@@ -18,6 +26,40 @@ class DeprecateCommand extends BaseCommand {
18
26
  `${colors.yellow('If all your changes are non-breaking, use `zapier migrate` instead to move users over to a newer version.')}\n`,
19
27
  );
20
28
 
29
+ // Get deprecation reason - either from flag or prompt user
30
+ let deprecationReason = this.flags.reason;
31
+
32
+ if (!deprecationReason) {
33
+ deprecationReason = await this.promptWithList(
34
+ 'Please select a reason for deprecating this version:',
35
+ DEPRECATION_REASONS,
36
+ {
37
+ useStderr: true,
38
+ },
39
+ );
40
+ } else {
41
+ // Validate the provided reason
42
+ const validReasons = DEPRECATION_REASONS.map((r) => r.value);
43
+ if (!validReasons.includes(deprecationReason)) {
44
+ this.error(
45
+ `Invalid deprecation reason: ${deprecationReason}. Valid options are: ${validReasons.join(', ')}`,
46
+ );
47
+ }
48
+ }
49
+
50
+ let customReason = null;
51
+ if (deprecationReason === 'other') {
52
+ customReason = await this.prompt(
53
+ 'Please provide a brief user-facing reason (50 characters max):',
54
+ {
55
+ required: true,
56
+ charLimit: 50,
57
+ useStderr: true,
58
+ },
59
+ );
60
+ customReason = 'other: ' + customReason;
61
+ }
62
+
21
63
  if (
22
64
  !this.flags.force &&
23
65
  !(await this.confirm(
@@ -32,14 +74,16 @@ class DeprecateCommand extends BaseCommand {
32
74
  }
33
75
 
34
76
  this.log(
35
- `\nPreparing to deprecate version ${version} your app "${app.title}".\n`,
77
+ `\nPreparing to deprecate version ${version} your app "${app.title}" due to: ${customReason || DEPRECATION_REASONS.find((r) => r.value === deprecationReason)?.name}.\n`,
36
78
  );
79
+
37
80
  const url = `/apps/${app.id}/versions/${version}/deprecate`;
38
81
  this.startSpinner(`Deprecating ${version}`);
39
82
  await callAPI(url, {
40
83
  method: 'PUT',
41
84
  body: {
42
85
  deprecation_date: date,
86
+ deprecation_reason: customReason || deprecationReason,
43
87
  },
44
88
  });
45
89
  this.stopSpinner();
@@ -55,6 +99,11 @@ DeprecateCommand.flags = buildFlags({
55
99
  char: 'f',
56
100
  description: 'Skip confirmation prompt. Use with caution.',
57
101
  }),
102
+ reason: Flags.string({
103
+ char: 'r',
104
+ description: 'Reason for deprecation.',
105
+ options: DEPRECATION_REASONS.map((r) => r.value),
106
+ }),
58
107
  },
59
108
  });
60
109
  DeprecateCommand.args = {
@@ -68,11 +117,18 @@ DeprecateCommand.args = {
68
117
  required: true,
69
118
  }),
70
119
  };
71
- DeprecateCommand.examples = ['zapier deprecate 1.2.3 2011-10-01'];
120
+ DeprecateCommand.examples = [
121
+ 'zapier deprecate 1.2.3 2011-10-01',
122
+ 'zapier deprecate 1.2.3 2011-10-01 --reason=security_vulnerability',
123
+ 'zapier deprecate 1.2.3 2011-10-01 -r critical_bug',
124
+ ];
72
125
  DeprecateCommand.description = `Mark a non-production version of your integration as deprecated, with removal by a certain date.
73
126
 
74
127
  Use this when an integration version will not be supported or start breaking at a known date.
75
128
 
129
+ When deprecating a version, you must provide a reason for the deprecation. You can either specify the reason using the --reason flag or you will be prompted to select from the following options:
130
+ ${DEPRECATION_REASONS.map((r) => `- ${r.name}`).join('\n')}
131
+
76
132
  Zapier will immediately send emails warning users of the deprecation if a date less than 30 days in the future is set, otherwise the emails will be sent exactly 30 days before the configured deprecation date.
77
133
 
78
134
  There are other side effects: they'll start seeing it as "Deprecated" in the UI, and once the deprecation date arrives, if the Zaps weren't updated, they'll be paused and the users will be emailed again explaining what happened.
@@ -101,7 +101,7 @@ const getAuthFieldKeys = (appDefinition) => {
101
101
 
102
102
  const renderPackageJson = async (appInfo, appDefinition) => {
103
103
  const name = _.kebabCase(
104
- appInfo.title || _.get(appInfo, ['general', 'title']),
104
+ appInfo.title || _.get(appInfo, ['general', 'title']) || '',
105
105
  );
106
106
 
107
107
  // Not using escapeSpecialChars because we don't want to escape single quotes (not
@@ -366,10 +366,10 @@ const writeGitIgnore = async (newAppDir) => {
366
366
  };
367
367
 
368
368
  const writeZapierAppRc = async (appInfo, appDefinition, newAppDir) => {
369
- const json = {};
370
- if (appInfo.id) {
371
- json.id = appInfo.id;
369
+ if (!appInfo.id) {
370
+ return;
372
371
  }
372
+ const json = { id: appInfo.id };
373
373
  if (appInfo.key) {
374
374
  json.key = appInfo.key;
375
375
  }