zapier-platform-cli 16.1.1 → 16.3.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.",
@@ -1054,6 +1061,13 @@
1054
1061
  "name": "invokedFromAnotherCommand",
1055
1062
  "allowNo": false,
1056
1063
  "type": "boolean"
1064
+ },
1065
+ "overwrite-partner-changes": {
1066
+ "description": "(Internal Use Only) Allows Zapier Staff to push changes to integrations in certain situations.",
1067
+ "hidden": true,
1068
+ "name": "overwrite-partner-changes",
1069
+ "allowNo": false,
1070
+ "type": "boolean"
1057
1071
  }
1058
1072
  },
1059
1073
  "hasDynamicHelp": false,
@@ -1608,44 +1622,20 @@
1608
1622
  "version.js"
1609
1623
  ]
1610
1624
  },
1611
- "canary:create": {
1625
+ "env:get": {
1612
1626
  "aliases": [],
1613
1627
  "args": {
1614
- "versionFrom": {
1615
- "description": "Version to route traffic from",
1616
- "name": "versionFrom",
1617
- "required": true
1618
- },
1619
- "versionTo": {
1620
- "description": "Version to canary traffic to",
1621
- "name": "versionTo",
1628
+ "version": {
1629
+ "description": "The version to get the environment for.",
1630
+ "name": "version",
1622
1631
  "required": true
1623
1632
  }
1624
1633
  },
1625
- "description": "Create a new canary deployment, diverting a specified percentage of traffic from one version to another for a specified duration.\n\nOnly one canary can be active at the same time. You can run `zapier canary:list` to check. If you would like to create a new canary with different parameters, you can wait for the canary to finish, or delete it using `zapier canary:delete a.b.c x.y.z`.\n\nNote: this is similar to `zapier migrate` but different in that this is temporary and will \"revert\" the changes once the specified duration is expired.\n\n**Only use this command to canary traffic between non-breaking versions!**",
1634
+ "description": "Get environment variables for a version.",
1626
1635
  "examples": [
1627
- "zapier canary:create 1.0.0 1.1.0 -p 25 -d 720",
1628
- "zapier canary:create 2.0.0 2.1.0 --percent 50 --duration 300"
1636
+ "zapier env:get 1.2.3"
1629
1637
  ],
1630
1638
  "flags": {
1631
- "percent": {
1632
- "char": "p",
1633
- "description": "Percent of traffic to route to new version",
1634
- "name": "percent",
1635
- "required": true,
1636
- "hasDynamicHelp": false,
1637
- "multiple": false,
1638
- "type": "option"
1639
- },
1640
- "duration": {
1641
- "char": "d",
1642
- "description": "Duration of the canary in seconds",
1643
- "name": "duration",
1644
- "required": true,
1645
- "hasDynamicHelp": false,
1646
- "multiple": false,
1647
- "type": "option"
1648
- },
1649
1639
  "debug": {
1650
1640
  "char": "d",
1651
1641
  "description": "Show extra debugging output.",
@@ -1653,6 +1643,22 @@
1653
1643
  "allowNo": false,
1654
1644
  "type": "boolean"
1655
1645
  },
1646
+ "format": {
1647
+ "char": "f",
1648
+ "description": "Change the way structured data is presented. If \"json\" or \"raw\", you can pipe the output of the command into other tools, such as jq.",
1649
+ "name": "format",
1650
+ "default": "table",
1651
+ "hasDynamicHelp": false,
1652
+ "multiple": false,
1653
+ "options": [
1654
+ "plain",
1655
+ "json",
1656
+ "raw",
1657
+ "row",
1658
+ "table"
1659
+ ],
1660
+ "type": "option"
1661
+ },
1656
1662
  "invokedFromAnotherCommand": {
1657
1663
  "hidden": true,
1658
1664
  "name": "invokedFromAnotherCommand",
@@ -1662,7 +1668,7 @@
1662
1668
  },
1663
1669
  "hasDynamicHelp": false,
1664
1670
  "hiddenAliases": [],
1665
- "id": "canary:create",
1671
+ "id": "env:get",
1666
1672
  "pluginAlias": "zapier-platform-cli",
1667
1673
  "pluginName": "zapier-platform-cli",
1668
1674
  "pluginType": "core",
@@ -1674,55 +1680,35 @@
1674
1680
  "src",
1675
1681
  "oclif",
1676
1682
  "commands",
1677
- "canary",
1678
- "create.js"
1683
+ "env",
1684
+ "get.js"
1679
1685
  ]
1680
1686
  },
1681
- "canary:delete": {
1687
+ "env:set": {
1682
1688
  "aliases": [],
1683
1689
  "args": {
1684
- "versionFrom": {
1685
- "description": "Version to route traffic from",
1686
- "name": "versionFrom",
1690
+ "version": {
1691
+ "description": "The version to set the environment for. Values are copied forward when a new version is created, but this command will only ever affect the specified version.",
1692
+ "name": "version",
1687
1693
  "required": true
1688
1694
  },
1689
- "versionTo": {
1690
- "description": "Version canary traffic is routed to",
1691
- "name": "versionTo",
1692
- "required": true
1695
+ "key-value pairs...": {
1696
+ "description": "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`",
1697
+ "name": "key-value pairs..."
1693
1698
  }
1694
1699
  },
1695
- "description": "Delete an active canary deployment",
1696
- "examples": [
1697
- "zapier canary:delete 1.0.0 1.1.0"
1698
- ],
1699
- "flags": {},
1700
- "hasDynamicHelp": false,
1701
- "hiddenAliases": [],
1702
- "id": "canary:delete",
1703
- "pluginAlias": "zapier-platform-cli",
1704
- "pluginName": "zapier-platform-cli",
1705
- "pluginType": "core",
1706
- "strict": true,
1707
- "enableJsonFlag": false,
1708
- "skipValidInstallCheck": true,
1709
- "isESM": false,
1710
- "relativePath": [
1711
- "src",
1712
- "oclif",
1713
- "commands",
1714
- "canary",
1715
- "delete.js"
1716
- ]
1717
- },
1718
- "canary:list": {
1719
- "aliases": [],
1720
- "args": {},
1721
- "description": "List all active canary deployments",
1700
+ "description": "Set environment variables for a version.",
1722
1701
  "examples": [
1723
- "zapier canary:list"
1702
+ "zapier env:set 1.2.3 SECRET=12345 OTHER=4321"
1724
1703
  ],
1725
1704
  "flags": {
1705
+ "force": {
1706
+ "char": "f",
1707
+ "description": "Force the update of environment variables regardless if the app version is production or not. Use with caution.",
1708
+ "name": "force",
1709
+ "allowNo": false,
1710
+ "type": "boolean"
1711
+ },
1726
1712
  "debug": {
1727
1713
  "char": "d",
1728
1714
  "description": "Show extra debugging output.",
@@ -1730,22 +1716,6 @@
1730
1716
  "allowNo": false,
1731
1717
  "type": "boolean"
1732
1718
  },
1733
- "format": {
1734
- "char": "f",
1735
- "description": "Change the way structured data is presented. If \"json\" or \"raw\", you can pipe the output of the command into other tools, such as jq.",
1736
- "name": "format",
1737
- "default": "table",
1738
- "hasDynamicHelp": false,
1739
- "multiple": false,
1740
- "options": [
1741
- "plain",
1742
- "json",
1743
- "raw",
1744
- "row",
1745
- "table"
1746
- ],
1747
- "type": "option"
1748
- },
1749
1719
  "invokedFromAnotherCommand": {
1750
1720
  "hidden": true,
1751
1721
  "name": "invokedFromAnotherCommand",
@@ -1755,11 +1725,11 @@
1755
1725
  },
1756
1726
  "hasDynamicHelp": false,
1757
1727
  "hiddenAliases": [],
1758
- "id": "canary:list",
1728
+ "id": "env:set",
1759
1729
  "pluginAlias": "zapier-platform-cli",
1760
1730
  "pluginName": "zapier-platform-cli",
1761
1731
  "pluginType": "core",
1762
- "strict": true,
1732
+ "strict": false,
1763
1733
  "enableJsonFlag": false,
1764
1734
  "skipValidInstallCheck": true,
1765
1735
  "isESM": false,
@@ -1767,24 +1737,35 @@
1767
1737
  "src",
1768
1738
  "oclif",
1769
1739
  "commands",
1770
- "canary",
1771
- "list.js"
1740
+ "env",
1741
+ "set.js"
1772
1742
  ]
1773
1743
  },
1774
- "env:get": {
1744
+ "env:unset": {
1775
1745
  "aliases": [],
1776
1746
  "args": {
1777
1747
  "version": {
1778
- "description": "The version to get the environment for.",
1748
+ "description": "The version to set the environment for.",
1779
1749
  "name": "version",
1780
1750
  "required": true
1751
+ },
1752
+ "keys...": {
1753
+ "description": "The keys to unset. Keys are case-insensitive.",
1754
+ "name": "keys..."
1781
1755
  }
1782
1756
  },
1783
- "description": "Get environment variables for a version.",
1757
+ "description": "Unset environment variables for a version.",
1784
1758
  "examples": [
1785
- "zapier env:get 1.2.3"
1759
+ "zapier env:unset 1.2.3 SECRET OTHER"
1786
1760
  ],
1787
1761
  "flags": {
1762
+ "force": {
1763
+ "char": "f",
1764
+ "description": "Force the update of environment variables regardless if the app version is production or not. Use with caution.",
1765
+ "name": "force",
1766
+ "allowNo": false,
1767
+ "type": "boolean"
1768
+ },
1788
1769
  "debug": {
1789
1770
  "char": "d",
1790
1771
  "description": "Show extra debugging output.",
@@ -1792,22 +1773,6 @@
1792
1773
  "allowNo": false,
1793
1774
  "type": "boolean"
1794
1775
  },
1795
- "format": {
1796
- "char": "f",
1797
- "description": "Change the way structured data is presented. If \"json\" or \"raw\", you can pipe the output of the command into other tools, such as jq.",
1798
- "name": "format",
1799
- "default": "table",
1800
- "hasDynamicHelp": false,
1801
- "multiple": false,
1802
- "options": [
1803
- "plain",
1804
- "json",
1805
- "raw",
1806
- "row",
1807
- "table"
1808
- ],
1809
- "type": "option"
1810
- },
1811
1776
  "invokedFromAnotherCommand": {
1812
1777
  "hidden": true,
1813
1778
  "name": "invokedFromAnotherCommand",
@@ -1817,11 +1782,11 @@
1817
1782
  },
1818
1783
  "hasDynamicHelp": false,
1819
1784
  "hiddenAliases": [],
1820
- "id": "env:get",
1785
+ "id": "env:unset",
1821
1786
  "pluginAlias": "zapier-platform-cli",
1822
1787
  "pluginName": "zapier-platform-cli",
1823
1788
  "pluginType": "core",
1824
- "strict": true,
1789
+ "strict": false,
1825
1790
  "enableJsonFlag": false,
1826
1791
  "skipValidInstallCheck": true,
1827
1792
  "isESM": false,
@@ -1830,27 +1795,47 @@
1830
1795
  "oclif",
1831
1796
  "commands",
1832
1797
  "env",
1833
- "get.js"
1798
+ "unset.js"
1834
1799
  ]
1835
1800
  },
1836
- "env:set": {
1801
+ "canary:create": {
1837
1802
  "aliases": [],
1838
1803
  "args": {
1839
- "version": {
1840
- "description": "The version to set the environment for. Values are copied forward when a new version is created, but this command will only ever affect the specified version.",
1841
- "name": "version",
1804
+ "versionFrom": {
1805
+ "description": "Version to route traffic from",
1806
+ "name": "versionFrom",
1842
1807
  "required": true
1843
1808
  },
1844
- "key-value pairs...": {
1845
- "description": "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`",
1846
- "name": "key-value pairs..."
1809
+ "versionTo": {
1810
+ "description": "Version to canary traffic to",
1811
+ "name": "versionTo",
1812
+ "required": true
1847
1813
  }
1848
1814
  },
1849
- "description": "Set environment variables for a version.",
1815
+ "description": "Create a new canary deployment, diverting a specified percentage of traffic from one version to another for a specified duration.\n\nOnly one canary can be active at the same time. You can run `zapier canary:list` to check. If you would like to create a new canary with different parameters, you can wait for the canary to finish, or delete it using `zapier canary:delete a.b.c x.y.z`.\n\nNote: this is similar to `zapier migrate` but different in that this is temporary and will \"revert\" the changes once the specified duration is expired.\n\n**Only use this command to canary traffic between non-breaking versions!**",
1850
1816
  "examples": [
1851
- "zapier env:set 1.2.3 SECRET=12345 OTHER=4321"
1817
+ "zapier canary:create 1.0.0 1.1.0 -p 25 -d 720",
1818
+ "zapier canary:create 2.0.0 2.1.0 --percent 50 --duration 300"
1852
1819
  ],
1853
1820
  "flags": {
1821
+ "percent": {
1822
+ "char": "p",
1823
+ "description": "Percent of traffic to route to new version",
1824
+ "name": "percent",
1825
+ "required": true,
1826
+ "hasDynamicHelp": false,
1827
+ "multiple": false,
1828
+ "type": "option"
1829
+ },
1830
+ "duration": {
1831
+ "char": "d",
1832
+ "description": "Duration of the canary in seconds",
1833
+ "name": "duration",
1834
+ "required": true,
1835
+ "hasDynamicHelp": false,
1836
+ "multiple": false,
1837
+ "type": "option"
1838
+ },
1854
1839
  "debug": {
1855
1840
  "char": "d",
1856
1841
  "description": "Show extra debugging output.",
@@ -1867,11 +1852,11 @@
1867
1852
  },
1868
1853
  "hasDynamicHelp": false,
1869
1854
  "hiddenAliases": [],
1870
- "id": "env:set",
1855
+ "id": "canary:create",
1871
1856
  "pluginAlias": "zapier-platform-cli",
1872
1857
  "pluginName": "zapier-platform-cli",
1873
1858
  "pluginType": "core",
1874
- "strict": false,
1859
+ "strict": true,
1875
1860
  "enableJsonFlag": false,
1876
1861
  "skipValidInstallCheck": true,
1877
1862
  "isESM": false,
@@ -1879,26 +1864,53 @@
1879
1864
  "src",
1880
1865
  "oclif",
1881
1866
  "commands",
1882
- "env",
1883
- "set.js"
1867
+ "canary",
1868
+ "create.js"
1884
1869
  ]
1885
1870
  },
1886
- "env:unset": {
1871
+ "canary:delete": {
1887
1872
  "aliases": [],
1888
1873
  "args": {
1889
- "version": {
1890
- "description": "The version to set the environment for.",
1891
- "name": "version",
1874
+ "versionFrom": {
1875
+ "description": "Version to route traffic from",
1876
+ "name": "versionFrom",
1892
1877
  "required": true
1893
1878
  },
1894
- "keys...": {
1895
- "description": "The keys to unset. Keys are case-insensitive.",
1896
- "name": "keys..."
1879
+ "versionTo": {
1880
+ "description": "Version canary traffic is routed to",
1881
+ "name": "versionTo",
1882
+ "required": true
1897
1883
  }
1898
1884
  },
1899
- "description": "Unset environment variables for a version.",
1885
+ "description": "Delete an active canary deployment",
1900
1886
  "examples": [
1901
- "zapier env:unset 1.2.3 SECRET OTHER"
1887
+ "zapier canary:delete 1.0.0 1.1.0"
1888
+ ],
1889
+ "flags": {},
1890
+ "hasDynamicHelp": false,
1891
+ "hiddenAliases": [],
1892
+ "id": "canary:delete",
1893
+ "pluginAlias": "zapier-platform-cli",
1894
+ "pluginName": "zapier-platform-cli",
1895
+ "pluginType": "core",
1896
+ "strict": true,
1897
+ "enableJsonFlag": false,
1898
+ "skipValidInstallCheck": true,
1899
+ "isESM": false,
1900
+ "relativePath": [
1901
+ "src",
1902
+ "oclif",
1903
+ "commands",
1904
+ "canary",
1905
+ "delete.js"
1906
+ ]
1907
+ },
1908
+ "canary:list": {
1909
+ "aliases": [],
1910
+ "args": {},
1911
+ "description": "List all active canary deployments",
1912
+ "examples": [
1913
+ "zapier canary:list"
1902
1914
  ],
1903
1915
  "flags": {
1904
1916
  "debug": {
@@ -1908,6 +1920,22 @@
1908
1920
  "allowNo": false,
1909
1921
  "type": "boolean"
1910
1922
  },
1923
+ "format": {
1924
+ "char": "f",
1925
+ "description": "Change the way structured data is presented. If \"json\" or \"raw\", you can pipe the output of the command into other tools, such as jq.",
1926
+ "name": "format",
1927
+ "default": "table",
1928
+ "hasDynamicHelp": false,
1929
+ "multiple": false,
1930
+ "options": [
1931
+ "plain",
1932
+ "json",
1933
+ "raw",
1934
+ "row",
1935
+ "table"
1936
+ ],
1937
+ "type": "option"
1938
+ },
1911
1939
  "invokedFromAnotherCommand": {
1912
1940
  "hidden": true,
1913
1941
  "name": "invokedFromAnotherCommand",
@@ -1917,11 +1945,11 @@
1917
1945
  },
1918
1946
  "hasDynamicHelp": false,
1919
1947
  "hiddenAliases": [],
1920
- "id": "env:unset",
1948
+ "id": "canary:list",
1921
1949
  "pluginAlias": "zapier-platform-cli",
1922
1950
  "pluginName": "zapier-platform-cli",
1923
1951
  "pluginType": "core",
1924
- "strict": false,
1952
+ "strict": true,
1925
1953
  "enableJsonFlag": false,
1926
1954
  "skipValidInstallCheck": true,
1927
1955
  "isESM": false,
@@ -1929,8 +1957,8 @@
1929
1957
  "src",
1930
1958
  "oclif",
1931
1959
  "commands",
1932
- "env",
1933
- "unset.js"
1960
+ "canary",
1961
+ "list.js"
1934
1962
  ]
1935
1963
  },
1936
1964
  "team:add": {
@@ -2312,5 +2340,5 @@
2312
2340
  ]
2313
2341
  }
2314
2342
  },
2315
- "version": "16.1.1"
2343
+ "version": "16.3.0"
2316
2344
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapier-platform-cli",
3
- "version": "16.1.1",
3
+ "version": "16.3.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/",
@@ -24,7 +24,10 @@ module.exports = class PullGenerator extends Generator {
24
24
  name: 'confirm',
25
25
  message: `Warning: You are about to overwrite existing files.
26
26
 
27
- Before proceeding, please make sure you have saved your work. Consider creating a backup or saving your current state in a git branch. During the process, you may abort anytime by pressing 'x'.
27
+ Before proceeding, please make sure you have saved your work. Consider creating a backup or saving your current state in a git branch.
28
+
29
+ If presented with a series of options ('ynarxdeiH'), you may
30
+ press Enter to view more details about each option. For example, 'x' will abort the process.
28
31
 
29
32
  Do you want to continue?`,
30
33
  default: 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
  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`;
@@ -1,5 +1,6 @@
1
1
  const ZapierBaseCommand = require('../ZapierBaseCommand');
2
2
  const { BUILD_PATH, SOURCE_PATH } = require('../../constants');
3
+ const { Flags } = require('@oclif/core');
3
4
 
4
5
  const BuildCommand = require('./build');
5
6
 
@@ -13,6 +14,7 @@ class PushCommand extends ZapierBaseCommand {
13
14
  skipNpmInstall: this.flags['skip-npm-install'],
14
15
  disableDependencyDetection: this.flags['disable-dependency-detection'],
15
16
  skipValidation: this.flags['skip-validation'],
17
+ overwritePartnerChanges: this.flags['overwrite-partner-changes'],
16
18
  },
17
19
  );
18
20
  this.log(
@@ -21,7 +23,14 @@ class PushCommand extends ZapierBaseCommand {
21
23
  }
22
24
  }
23
25
 
24
- PushCommand.flags = BuildCommand.flags;
26
+ PushCommand.flags = {
27
+ ...BuildCommand.flags,
28
+ 'overwrite-partner-changes': Flags.boolean({
29
+ description:
30
+ '(Internal Use Only) Allows Zapier Staff to push changes to integrations in certain situations.',
31
+ hidden: true,
32
+ }),
33
+ };
25
34
  PushCommand.description = `Build and upload the current integration.
26
35
 
27
36
  This command is the same as running \`zapier build\` and \`zapier upload\` in sequence. See those for more info.`;
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}`,
@@ -421,7 +422,10 @@ const downloadSourceZip = async (dst) => {
421
422
  }
422
423
  };
423
424
 
424
- const upload = async (app, { skipValidation = false } = {}) => {
425
+ const upload = async (
426
+ app,
427
+ { skipValidation = false, overwritePartnerChanges = false } = {},
428
+ ) => {
425
429
  const zipPath = constants.BUILD_PATH;
426
430
  const sourceZipPath = constants.SOURCE_PATH;
427
431
  const appDir = process.cwd();
@@ -448,17 +452,42 @@ const upload = async (app, { skipValidation = false } = {}) => {
448
452
  const binarySourceZip = fs.readFileSync(fullSourceZipPath);
449
453
  const sourceBuffer = Buffer.from(binarySourceZip).toString('base64');
450
454
 
455
+ const headers = {};
456
+ if (overwritePartnerChanges) {
457
+ headers['X-Overwrite-Partner-Changes'] = 'true';
458
+ }
459
+
451
460
  startSpinner(`Uploading version ${definition.version}`);
452
- await callAPI(`/apps/${app.id}/versions/${definition.version}`, {
453
- method: 'PUT',
454
- body: {
455
- zip_file: buffer,
456
- source_zip_file: sourceBuffer,
457
- skip_validation: skipValidation,
458
- },
459
- });
461
+ try {
462
+ await callAPI(
463
+ `/apps/${app.id}/versions/${definition.version}`,
464
+ {
465
+ method: 'PUT',
466
+ body: {
467
+ zip_file: buffer,
468
+ source_zip_file: sourceBuffer,
469
+ skip_validation: skipValidation,
470
+ },
471
+ extraHeaders: headers,
472
+ },
473
+ true,
474
+ );
475
+ } catch (err) {
476
+ endSpinner({ success: false });
477
+ // 409 from the backend specifically signals that the last changes were from a partner
478
+ // and this is a staff user which could unintentionally overwrite those changes
479
+ if (err.status === 409) {
480
+ throw new Error(
481
+ `The latest integration changes appear to be from a partner. OK to overwrite?` +
482
+ ` If so, run this command again using the '--overwrite-partner-changes' flag.`,
483
+ );
484
+ }
460
485
 
461
- endSpinner();
486
+ // Don't ignore other errors, re-throw them with a user-friendly message
487
+ throw new Error(err.errText);
488
+ } finally {
489
+ endSpinner();
490
+ }
462
491
  };
463
492
 
464
493
  module.exports = {