zapier-platform-cli 16.1.1 → 16.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.
@@ -898,6 +898,13 @@
898
898
  "multiple": false,
899
899
  "type": "option"
900
900
  },
901
+ "yes": {
902
+ "char": "y",
903
+ "description": "Automatically answer \"yes\" to any prompts. Useful if you want to avoid interactive prompts to run this command in CI.",
904
+ "name": "yes",
905
+ "allowNo": false,
906
+ "type": "boolean"
907
+ },
901
908
  "debug": {
902
909
  "char": "d",
903
910
  "description": "Show extra debugging output.",
@@ -1526,88 +1533,6 @@
1526
1533
  "clear.js"
1527
1534
  ]
1528
1535
  },
1529
- "delete:integration": {
1530
- "aliases": [
1531
- "delete:app"
1532
- ],
1533
- "args": {},
1534
- "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.",
1535
- "flags": {
1536
- "debug": {
1537
- "char": "d",
1538
- "description": "Show extra debugging output.",
1539
- "name": "debug",
1540
- "allowNo": false,
1541
- "type": "boolean"
1542
- },
1543
- "invokedFromAnotherCommand": {
1544
- "hidden": true,
1545
- "name": "invokedFromAnotherCommand",
1546
- "allowNo": false,
1547
- "type": "boolean"
1548
- }
1549
- },
1550
- "hasDynamicHelp": false,
1551
- "hiddenAliases": [],
1552
- "id": "delete:integration",
1553
- "pluginAlias": "zapier-platform-cli",
1554
- "pluginName": "zapier-platform-cli",
1555
- "pluginType": "core",
1556
- "strict": true,
1557
- "enableJsonFlag": false,
1558
- "skipValidInstallCheck": true,
1559
- "isESM": false,
1560
- "relativePath": [
1561
- "src",
1562
- "oclif",
1563
- "commands",
1564
- "delete",
1565
- "integration.js"
1566
- ]
1567
- },
1568
- "delete:version": {
1569
- "aliases": [],
1570
- "args": {
1571
- "version": {
1572
- "description": "Specify the version to delete. It must have no users or Zaps.",
1573
- "name": "version",
1574
- "required": true
1575
- }
1576
- },
1577
- "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.",
1578
- "flags": {
1579
- "debug": {
1580
- "char": "d",
1581
- "description": "Show extra debugging output.",
1582
- "name": "debug",
1583
- "allowNo": false,
1584
- "type": "boolean"
1585
- },
1586
- "invokedFromAnotherCommand": {
1587
- "hidden": true,
1588
- "name": "invokedFromAnotherCommand",
1589
- "allowNo": false,
1590
- "type": "boolean"
1591
- }
1592
- },
1593
- "hasDynamicHelp": false,
1594
- "hiddenAliases": [],
1595
- "id": "delete:version",
1596
- "pluginAlias": "zapier-platform-cli",
1597
- "pluginName": "zapier-platform-cli",
1598
- "pluginType": "core",
1599
- "strict": true,
1600
- "enableJsonFlag": false,
1601
- "skipValidInstallCheck": true,
1602
- "isESM": false,
1603
- "relativePath": [
1604
- "src",
1605
- "oclif",
1606
- "commands",
1607
- "delete",
1608
- "version.js"
1609
- ]
1610
- },
1611
1536
  "canary:create": {
1612
1537
  "aliases": [],
1613
1538
  "args": {
@@ -1771,6 +1696,88 @@
1771
1696
  "list.js"
1772
1697
  ]
1773
1698
  },
1699
+ "delete:integration": {
1700
+ "aliases": [
1701
+ "delete:app"
1702
+ ],
1703
+ "args": {},
1704
+ "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.",
1705
+ "flags": {
1706
+ "debug": {
1707
+ "char": "d",
1708
+ "description": "Show extra debugging output.",
1709
+ "name": "debug",
1710
+ "allowNo": false,
1711
+ "type": "boolean"
1712
+ },
1713
+ "invokedFromAnotherCommand": {
1714
+ "hidden": true,
1715
+ "name": "invokedFromAnotherCommand",
1716
+ "allowNo": false,
1717
+ "type": "boolean"
1718
+ }
1719
+ },
1720
+ "hasDynamicHelp": false,
1721
+ "hiddenAliases": [],
1722
+ "id": "delete:integration",
1723
+ "pluginAlias": "zapier-platform-cli",
1724
+ "pluginName": "zapier-platform-cli",
1725
+ "pluginType": "core",
1726
+ "strict": true,
1727
+ "enableJsonFlag": false,
1728
+ "skipValidInstallCheck": true,
1729
+ "isESM": false,
1730
+ "relativePath": [
1731
+ "src",
1732
+ "oclif",
1733
+ "commands",
1734
+ "delete",
1735
+ "integration.js"
1736
+ ]
1737
+ },
1738
+ "delete:version": {
1739
+ "aliases": [],
1740
+ "args": {
1741
+ "version": {
1742
+ "description": "Specify the version to delete. It must have no users or Zaps.",
1743
+ "name": "version",
1744
+ "required": true
1745
+ }
1746
+ },
1747
+ "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.",
1748
+ "flags": {
1749
+ "debug": {
1750
+ "char": "d",
1751
+ "description": "Show extra debugging output.",
1752
+ "name": "debug",
1753
+ "allowNo": false,
1754
+ "type": "boolean"
1755
+ },
1756
+ "invokedFromAnotherCommand": {
1757
+ "hidden": true,
1758
+ "name": "invokedFromAnotherCommand",
1759
+ "allowNo": false,
1760
+ "type": "boolean"
1761
+ }
1762
+ },
1763
+ "hasDynamicHelp": false,
1764
+ "hiddenAliases": [],
1765
+ "id": "delete:version",
1766
+ "pluginAlias": "zapier-platform-cli",
1767
+ "pluginName": "zapier-platform-cli",
1768
+ "pluginType": "core",
1769
+ "strict": true,
1770
+ "enableJsonFlag": false,
1771
+ "skipValidInstallCheck": true,
1772
+ "isESM": false,
1773
+ "relativePath": [
1774
+ "src",
1775
+ "oclif",
1776
+ "commands",
1777
+ "delete",
1778
+ "version.js"
1779
+ ]
1780
+ },
1774
1781
  "env:get": {
1775
1782
  "aliases": [],
1776
1783
  "args": {
@@ -1851,6 +1858,13 @@
1851
1858
  "zapier env:set 1.2.3 SECRET=12345 OTHER=4321"
1852
1859
  ],
1853
1860
  "flags": {
1861
+ "force": {
1862
+ "char": "f",
1863
+ "description": "Force the update of environment variables regardless if the app version is production or not. Use with caution.",
1864
+ "name": "force",
1865
+ "allowNo": false,
1866
+ "type": "boolean"
1867
+ },
1854
1868
  "debug": {
1855
1869
  "char": "d",
1856
1870
  "description": "Show extra debugging output.",
@@ -1901,6 +1915,13 @@
1901
1915
  "zapier env:unset 1.2.3 SECRET OTHER"
1902
1916
  ],
1903
1917
  "flags": {
1918
+ "force": {
1919
+ "char": "f",
1920
+ "description": "Force the update of environment variables regardless if the app version is production or not. Use with caution.",
1921
+ "name": "force",
1922
+ "allowNo": false,
1923
+ "type": "boolean"
1924
+ },
1904
1925
  "debug": {
1905
1926
  "char": "d",
1906
1927
  "description": "Show extra debugging output.",
@@ -2312,5 +2333,5 @@
2312
2333
  ]
2313
2334
  }
2314
2335
  },
2315
- "version": "16.1.1"
2336
+ "version": "16.2.0"
2316
2337
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapier-platform-cli",
3
- "version": "16.1.1",
3
+ "version": "16.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,4 +1,4 @@
1
- const { Args } = require('@oclif/core');
1
+ const { Args, Flags } = require('@oclif/core');
2
2
  const { cyan } = require('colors/safe');
3
3
  const { omit } = require('lodash');
4
4
 
@@ -45,21 +45,30 @@ class SetEnvCommand extends BaseCommand {
45
45
  }
46
46
 
47
47
  const url = `/apps/${app.id}/versions/${version}/multi-environment`;
48
+ const requestOptions = {
49
+ body: payload,
50
+ method: 'POST',
51
+ };
52
+
53
+ if (this.flags.force) {
54
+ requestOptions.extraHeaders = {
55
+ 'X-Force-Env-Var-Update': 'true',
56
+ };
57
+ }
48
58
 
49
59
  try {
50
- // currently, this returns nothing
51
- await callAPI(
52
- url,
53
- {
54
- body: payload,
55
- method: 'POST',
56
- },
57
- true,
58
- );
60
+ await callAPI(url, requestOptions, true);
59
61
 
60
62
  this.log(successMessage(version));
61
63
  this.logJSON(payload);
62
64
  } catch (e) {
65
+ if (e.status === 409) {
66
+ this.error(
67
+ `App version ${version} is the production version. Are you sure you want to set potentially live environment variables?` +
68
+ ` If so, run this command again with the --force flag.`,
69
+ );
70
+ }
71
+
63
72
  // comes back as json: { errors: [ 'The following keys failed to update: 3QER, 4WER' ] },
64
73
  const failedKeys = e.json.errors[0].split('update: ')[1].split(', ');
65
74
  const successfulResult = omit(payload, failedKeys);
@@ -85,7 +94,15 @@ SetEnvCommand.args = {
85
94
  'The key-value pairs to set. Keys are case-insensitive. Each pair should be space separated and pairs should be separated by an `=`. For example: `A=123 B=456`',
86
95
  }),
87
96
  };
88
- SetEnvCommand.flags = buildFlags();
97
+ SetEnvCommand.flags = buildFlags({
98
+ commandFlags: {
99
+ force: Flags.boolean({
100
+ char: 'f',
101
+ description:
102
+ 'Force the update of environment variables regardless if the app version is production or not. Use with caution.',
103
+ }),
104
+ },
105
+ });
89
106
  SetEnvCommand.description = `Set environment variables for a version.`;
90
107
  SetEnvCommand.examples = [`zapier env:set 1.2.3 SECRET=12345 OTHER=4321`];
91
108
  SetEnvCommand.strict = false;
@@ -1,4 +1,4 @@
1
- const { Args } = require('@oclif/core');
1
+ const { Args, Flags } = require('@oclif/core');
2
2
  const { cyan } = require('colors/safe');
3
3
 
4
4
  const BaseCommand = require('../../ZapierBaseCommand');
@@ -42,13 +42,29 @@ class UnsetEnvCommand extends BaseCommand {
42
42
  }
43
43
 
44
44
  const url = `/apps/${app.id}/versions/${version}/multi-environment`;
45
-
46
- // currently, this returns nothing
47
- // also, no need to cath errors here, since invalid keys don't get tripped over if the env var didn't exist in the first place
48
- await callAPI(url, {
45
+ const requestOptions = {
49
46
  body: payload,
50
47
  method: 'POST',
51
- });
48
+ };
49
+
50
+ if (this.flags.force) {
51
+ requestOptions.extraHeaders = {
52
+ 'X-Force-Env-Var-Update': 'true',
53
+ };
54
+ }
55
+
56
+ try {
57
+ await callAPI(url, requestOptions, true);
58
+ } catch (e) {
59
+ if (e.status === 409) {
60
+ this.error(
61
+ `App version ${version} is the production version. Are you sure you want to unset potentially live environment variables?` +
62
+ ` If so, run this command again with the --force flag.`,
63
+ );
64
+ } else {
65
+ throw e;
66
+ }
67
+ }
52
68
 
53
69
  this.log(successMessage(version));
54
70
  this.logJSON(keysToUnset);
@@ -64,7 +80,15 @@ UnsetEnvCommand.args = {
64
80
  description: 'The keys to unset. Keys are case-insensitive.',
65
81
  }),
66
82
  };
67
- UnsetEnvCommand.flags = buildFlags();
83
+ UnsetEnvCommand.flags = buildFlags({
84
+ commandFlags: {
85
+ force: Flags.boolean({
86
+ char: 'f',
87
+ description:
88
+ 'Force the update of environment variables regardless if the app version is production or not. Use with caution.',
89
+ }),
90
+ },
91
+ });
68
92
  UnsetEnvCommand.description = `Unset environment variables for a version.`;
69
93
  UnsetEnvCommand.examples = [`zapier env:unset 1.2.3 SECRET OTHER`];
70
94
  UnsetEnvCommand.strict = false;
@@ -1,3 +1,5 @@
1
+ const _ = require('lodash');
2
+ const debug = require('debug')('zapier:migrate');
1
3
  const { Args, Flags } = require('@oclif/core');
2
4
 
3
5
  const BaseCommand = require('../ZapierBaseCommand');
@@ -6,6 +8,51 @@ const { callAPI } = require('../../utils/api');
6
8
  const { buildFlags } = require('../buildFlags');
7
9
 
8
10
  class MigrateCommand extends BaseCommand {
11
+ async run_require_confirmation_pre_checks(app, requestBody) {
12
+ const assumeYes = 'yes' in this.flags;
13
+ const url = `/apps/${app.id}/pre-migration-require-confirmation-checks`;
14
+
15
+ this.startSpinner(`Running pre-checks before migration...`);
16
+
17
+ try {
18
+ await callAPI(
19
+ url,
20
+ {
21
+ method: 'POST',
22
+ body: requestBody,
23
+ },
24
+ true,
25
+ );
26
+ } catch (response) {
27
+ this.stopSpinner({ success: false });
28
+
29
+ // 409 from the backend specifically signals pre-checks failed
30
+ if (response.status === 409) {
31
+ const softCheckErrors = _.get(response, 'json.errors', []);
32
+ const formattedErrors = softCheckErrors.map((e) => `* ${e}`).join('\n');
33
+
34
+ this.log();
35
+ this.log('Non-blocking checks prior to migration returned warnings:');
36
+ this.log(formattedErrors);
37
+ this.log();
38
+
39
+ const shouldContinuePreChecks =
40
+ assumeYes ||
41
+ (await this.confirm(
42
+ 'Would you like to continue with the migration regardless?',
43
+ ));
44
+
45
+ if (!shouldContinuePreChecks) {
46
+ this.error('Cancelled migration.');
47
+ }
48
+ } else {
49
+ debug('Soft pre-checks before migration failed:', response.errText);
50
+ }
51
+ } finally {
52
+ this.stopSpinner();
53
+ }
54
+ }
55
+
9
56
  async perform() {
10
57
  const percent = this.args.percent;
11
58
  if (isNaN(percent) || percent < 1 || percent > 100) {
@@ -14,6 +61,7 @@ class MigrateCommand extends BaseCommand {
14
61
 
15
62
  const account = this.flags.account;
16
63
  const user = this.flags.user;
64
+
17
65
  const fromVersion = this.args.fromVersion;
18
66
  const toVersion = this.args.toVersion;
19
67
  let flagType;
@@ -67,6 +115,9 @@ class MigrateCommand extends BaseCommand {
67
115
  email_type: flagType,
68
116
  },
69
117
  };
118
+
119
+ await this.run_require_confirmation_pre_checks(app, body);
120
+
70
121
  if (user || account) {
71
122
  this.startSpinner(
72
123
  `Starting migration from ${fromVersion} to ${toVersion} for ${
@@ -106,6 +157,11 @@ MigrateCommand.flags = buildFlags({
106
157
  description:
107
158
  "Migrates all of a users' Zaps, Private & Shared, within all accounts for which the specified user is a member",
108
159
  }),
160
+ yes: Flags.boolean({
161
+ char: 'y',
162
+ description:
163
+ 'Automatically answer "yes" to any prompts. Useful if you want to avoid interactive prompts to run this command in CI.',
164
+ }),
109
165
  },
110
166
  });
111
167
 
@@ -1,4 +1,5 @@
1
1
  const _ = require('lodash');
2
+ const debug = require('debug')('zapier:promote');
2
3
  const colors = require('colors/safe');
3
4
  const { Args, Flags } = require('@oclif/core');
4
5
 
@@ -43,6 +44,52 @@ const hasAppChangeType = (metadata, changeType) => {
43
44
  };
44
45
 
45
46
  class PromoteCommand extends BaseCommand {
47
+ async run_require_confirmation_pre_checks(app, requestBody) {
48
+ const assumeYes = 'yes' in this.flags;
49
+ const url = `/apps/${app.id}/pre-migration-require-confirmation-checks`;
50
+
51
+ this.startSpinner(`Running pre-checks before promoting...`);
52
+
53
+ try {
54
+ await callAPI(
55
+ url,
56
+ {
57
+ method: 'POST',
58
+ body: requestBody,
59
+ },
60
+ true,
61
+ );
62
+ } catch (response) {
63
+ this.stopSpinner({ success: false });
64
+ // 409 from the backend specifically signals pre-checks failed
65
+ if (response.status === 409) {
66
+ const softCheckErrors = _.get(response, 'json.errors', []);
67
+ const formattedErrors = softCheckErrors.map((e) => `* ${e}`).join('\n');
68
+
69
+ this.log();
70
+ this.log(
71
+ 'Non-blocking checks prior to promoting the integration returned warnings:',
72
+ );
73
+ this.log(formattedErrors);
74
+ this.log();
75
+
76
+ const shouldContinuePreChecks =
77
+ assumeYes ||
78
+ (await this.confirm(
79
+ 'Would you like to continue with the promotion process regardless?',
80
+ ));
81
+
82
+ if (!shouldContinuePreChecks) {
83
+ this.error('Cancelled promote.');
84
+ }
85
+ } else {
86
+ debug('Soft pre-checks before promotion failed:', response.errText);
87
+ }
88
+ } finally {
89
+ this.stopSpinner();
90
+ }
91
+ }
92
+
46
93
  async perform() {
47
94
  const app = await this.getWritableApp();
48
95
 
@@ -51,7 +98,8 @@ class PromoteCommand extends BaseCommand {
51
98
  const version = this.args.version;
52
99
  const assumeYes = 'yes' in this.flags;
53
100
 
54
- let shouldContinue;
101
+ let shouldContinueChangelog;
102
+
55
103
  const { changelog, appMetadata, issueMetadata } =
56
104
  await getVersionChangelog(version);
57
105
 
@@ -133,15 +181,15 @@ ${metadataPromptHelper}`);
133
181
  this.log();
134
182
  /* eslint-enable camelcase */
135
183
 
136
- shouldContinue =
184
+ shouldContinueChangelog =
137
185
  assumeYes ||
138
186
  (await this.confirm(
139
187
  'Would you like to continue promoting with this changelog?',
140
188
  ));
141
- }
142
189
 
143
- if (!shouldContinue) {
144
- this.error('Cancelled promote.');
190
+ if (!shouldContinueChangelog) {
191
+ this.error('Cancelled promote.');
192
+ }
145
193
  }
146
194
 
147
195
  this.log(
@@ -167,6 +215,8 @@ ${metadataPromptHelper}`);
167
215
  },
168
216
  };
169
217
 
218
+ await this.run_require_confirmation_pre_checks(app, body);
219
+
170
220
  this.startSpinner(`Verifying and promoting ${version}`);
171
221
 
172
222
  const url = `/apps/${app.id}/migrations`;
package/src/utils/api.js CHANGED
@@ -68,6 +68,7 @@ const callAPI = async (
68
68
  method: options.method || 'GET',
69
69
  body: options.body ? JSON.stringify(options.body) : null,
70
70
  headers: {
71
+ ...options.extraHeaders, // extra headers first so they don't override defaults
71
72
  Accept: 'application/json',
72
73
  'Content-Type': 'application/json; charset=utf-8',
73
74
  'User-Agent': `${constants.PACKAGE_NAME}/${constants.PACKAGE_VERSION}`,