zapier-platform-cli 14.1.2 → 15.0.1
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.
- package/README-source.md +25 -11
- package/README.md +34 -20
- package/oclif.manifest.json +1 -1
- package/package.json +13 -12
- package/scaffold/test.template.js +0 -2
- package/src/constants.js +25 -1
- package/src/generators/index.js +1 -1
- package/src/oclif/commands/login.js +7 -1
- package/src/oclif/commands/promote.js +104 -17
- package/src/utils/changelog.js +40 -17
- package/src/utils/convert.js +49 -179
- package/src/utils/metadata.js +67 -0
- package/src/version-store.js +1 -0
- package/scaffold/convert/create-test.template.js +0 -22
- package/scaffold/convert/gitignore +0 -62
- package/scaffold/convert/package.template.json +0 -26
- package/scaffold/convert/search-test.template.js +0 -24
- package/scaffold/convert/trigger-test.template.js +0 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "15.0.1",
|
|
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/",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"/oclif.manifest.json"
|
|
20
20
|
],
|
|
21
21
|
"engines": {
|
|
22
|
-
"node": ">=
|
|
22
|
+
"node": ">=16"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"docs": "ZAPIER_BASE_ENDPOINT='' node scripts/docs.js && cp -r docs ../..",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"validate": "yarn test && yarn smoke-test && yarn lint"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@oclif/command": "1.8.
|
|
42
|
-
"@oclif/config": "1.18.
|
|
41
|
+
"@oclif/command": "1.8.27",
|
|
42
|
+
"@oclif/config": "1.18.10",
|
|
43
43
|
"@oclif/plugin-autocomplete": "0.3.0",
|
|
44
44
|
"@oclif/plugin-help": "3.2.2",
|
|
45
45
|
"@oclif/plugin-not-found": "1.2.4",
|
|
@@ -49,28 +49,29 @@
|
|
|
49
49
|
"cli-table3": "0.6.3",
|
|
50
50
|
"colors": "1.4.0",
|
|
51
51
|
"debug": "4.3.4",
|
|
52
|
-
"fs-extra": "
|
|
52
|
+
"fs-extra": "11.1.1",
|
|
53
53
|
"gulp-filter": "7.0.0",
|
|
54
54
|
"gulp-prettier": "4.0.0",
|
|
55
55
|
"ignore": "5.2.4",
|
|
56
56
|
"inquirer": "8.2.5",
|
|
57
|
-
"jscodeshift": "0.
|
|
57
|
+
"jscodeshift": "0.15.0",
|
|
58
58
|
"klaw": "4.1.0",
|
|
59
59
|
"lodash": "4.17.21",
|
|
60
60
|
"marked": "4.2.12",
|
|
61
|
-
"marked-terminal": "5.
|
|
61
|
+
"marked-terminal": "5.2.0",
|
|
62
62
|
"node-fetch": "2.6.7",
|
|
63
63
|
"ora": "5.4.0",
|
|
64
64
|
"parse-gitignore": "0.5.1",
|
|
65
|
-
"prettier": "2.8.
|
|
66
|
-
"read": "2.
|
|
67
|
-
"semver": "7.
|
|
65
|
+
"prettier": "2.8.8",
|
|
66
|
+
"read": "2.1.0",
|
|
67
|
+
"semver": "7.5.2",
|
|
68
68
|
"string-length": "4.0.2",
|
|
69
69
|
"through2": "4.0.2",
|
|
70
70
|
"tmp": "0.2.1",
|
|
71
|
+
"traverse": "0.6.7",
|
|
71
72
|
"update-notifier": "5.1.0",
|
|
72
73
|
"yeoman-environment": "3.3.0",
|
|
73
|
-
"yeoman-generator": "5.
|
|
74
|
+
"yeoman-generator": "5.9.0"
|
|
74
75
|
},
|
|
75
76
|
"devDependencies": {
|
|
76
77
|
"@oclif/dev-cli": "^1.26.10",
|
|
@@ -80,7 +81,7 @@
|
|
|
80
81
|
"litdoc": "1.5.6",
|
|
81
82
|
"markdown-toc": "^1",
|
|
82
83
|
"mock-fs": "^5.2.0",
|
|
83
|
-
"nock": "^13.3.
|
|
84
|
+
"nock": "^13.3.1",
|
|
84
85
|
"stdout-stderr": "0.1.13",
|
|
85
86
|
"yamljs": "0.3.0"
|
|
86
87
|
},
|
package/src/constants.js
CHANGED
|
@@ -26,7 +26,7 @@ const BLACKLISTED_PATHS = [
|
|
|
26
26
|
];
|
|
27
27
|
const NODE_VERSION = versionStore[versionStore.length - 1].nodeVersion;
|
|
28
28
|
const LAMBDA_VERSION = `v${NODE_VERSION}`;
|
|
29
|
-
const NODE_VERSION_CLI_REQUIRES = '>=
|
|
29
|
+
const NODE_VERSION_CLI_REQUIRES = '>=16'; // should be the oldest non-ETL version
|
|
30
30
|
const AUTH_KEY = 'deployKey';
|
|
31
31
|
const ANALYTICS_KEY = 'analyticsMode';
|
|
32
32
|
const ANALYTICS_MODES = {
|
|
@@ -59,6 +59,29 @@ const IS_TESTING =
|
|
|
59
59
|
|
|
60
60
|
const MAX_DESCRIPTION_LENGTH = 140;
|
|
61
61
|
|
|
62
|
+
const EXAMPLE_CHANGELOG = `
|
|
63
|
+
## 3.0.0
|
|
64
|
+
|
|
65
|
+
Made some changes that affect app actions
|
|
66
|
+
|
|
67
|
+
1. Update the trigger/pr_review action, as well as changes for #456
|
|
68
|
+
2. Fix trigger/new_card #208
|
|
69
|
+
3. New action! create/add_contact
|
|
70
|
+
|
|
71
|
+
However, we also addressed fixed open issues!
|
|
72
|
+
|
|
73
|
+
- Fix #123 and an issue with create/send_message
|
|
74
|
+
|
|
75
|
+
## 2.0.0
|
|
76
|
+
|
|
77
|
+
* Fix some bugs.
|
|
78
|
+
* Major docs fixes.
|
|
79
|
+
|
|
80
|
+
## 1.0.0
|
|
81
|
+
|
|
82
|
+
Initial release to public.
|
|
83
|
+
`;
|
|
84
|
+
|
|
62
85
|
module.exports = {
|
|
63
86
|
ANALYTICS_KEY,
|
|
64
87
|
ANALYTICS_MODES,
|
|
@@ -87,4 +110,5 @@ module.exports = {
|
|
|
87
110
|
SOURCE_PATH,
|
|
88
111
|
STARTER_REPO,
|
|
89
112
|
UPDATE_NOTIFICATION_INTERVAL,
|
|
113
|
+
EXAMPLE_CHANGELOG,
|
|
90
114
|
};
|
package/src/generators/index.js
CHANGED
|
@@ -19,7 +19,13 @@ const { writeFile } = require('../../utils/files');
|
|
|
19
19
|
const { prettyJSONstringify } = require('../../utils/display');
|
|
20
20
|
const { isSamlEmail } = require('../../utils/credentials');
|
|
21
21
|
|
|
22
|
-
const
|
|
22
|
+
const getDeployKeyUrl = () => {
|
|
23
|
+
const url = new URL(BASE_ENDPOINT);
|
|
24
|
+
url.hostname = `developer.${url.hostname}`;
|
|
25
|
+
url.pathname = 'partner-settings/deploy-keys/';
|
|
26
|
+
return url.href;
|
|
27
|
+
};
|
|
28
|
+
const DEPLOY_KEY_DASH_URL = getDeployKeyUrl();
|
|
23
29
|
|
|
24
30
|
const isValidTotpCode = (i) => {
|
|
25
31
|
const num = parseInt(i, 10);
|
|
@@ -8,6 +8,13 @@ const { callAPI } = require('../../utils/api');
|
|
|
8
8
|
const { flattenCheckResult } = require('../../utils/display');
|
|
9
9
|
const { getVersionChangelog } = require('../../utils/changelog');
|
|
10
10
|
const checkMissingAppInfo = require('../../utils/check-missing-app-info');
|
|
11
|
+
const { EXAMPLE_CHANGELOG } = require('../../constants');
|
|
12
|
+
|
|
13
|
+
const ACTION_TYPE_MAPPING = {
|
|
14
|
+
read: 'trigger',
|
|
15
|
+
write: 'create',
|
|
16
|
+
search: 'search',
|
|
17
|
+
};
|
|
11
18
|
|
|
12
19
|
const serializeErrors = (errors) => {
|
|
13
20
|
const opener = 'Promotion failed for the following reasons:\n\n';
|
|
@@ -25,6 +32,16 @@ const serializeErrors = (errors) => {
|
|
|
25
32
|
);
|
|
26
33
|
};
|
|
27
34
|
|
|
35
|
+
const hasAppChangeType = (metadata, changeType) => {
|
|
36
|
+
return Boolean(
|
|
37
|
+
metadata?.some(
|
|
38
|
+
// Existing property name
|
|
39
|
+
// eslint-disable-next-line camelcase
|
|
40
|
+
({ app_change_type }) => app_change_type === changeType
|
|
41
|
+
)
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
28
45
|
class PromoteCommand extends BaseCommand {
|
|
29
46
|
async perform() {
|
|
30
47
|
const app = await this.getWritableApp();
|
|
@@ -35,29 +52,88 @@ class PromoteCommand extends BaseCommand {
|
|
|
35
52
|
const assumeYes = 'yes' in this.flags;
|
|
36
53
|
|
|
37
54
|
let shouldContinue;
|
|
38
|
-
const changelog = await getVersionChangelog(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.log(`\n---\n${changelog}\n---\n`);
|
|
55
|
+
const { changelog, appMetadata, issueMetadata } = await getVersionChangelog(
|
|
56
|
+
version
|
|
57
|
+
);
|
|
42
58
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
const metadataPromptHelper = `Issues are indicated by ${colors.bold.underline(
|
|
60
|
+
'#<issueId>'
|
|
61
|
+
)}, and actions by ${colors.bold.underline(
|
|
62
|
+
'<trigger|create|search>/<key>'
|
|
63
|
+
)}. Note issue IDs must be numeric and action identifiers are case sensitive.`;
|
|
64
|
+
|
|
65
|
+
if (!changelog) {
|
|
66
|
+
this.error(`${colors.yellow(
|
|
67
|
+
'Warning!'
|
|
68
|
+
)} Changelog not found. Please create a CHANGELOG.md file with user-facing descriptions. Example:
|
|
69
|
+
${colors.cyan(EXAMPLE_CHANGELOG)}
|
|
70
|
+
If bugfixes or updates to actions are present, then should be marked on a line that begins with "Update" or "Fix" (case insensitive) and information that contains the identifier.
|
|
71
|
+
${metadataPromptHelper}`);
|
|
48
72
|
} else {
|
|
49
|
-
this.log(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
this.log(colors.green(`Changelog found for ${version}`));
|
|
74
|
+
this.log(`\n---\n${changelog}\n---`);
|
|
75
|
+
/* eslint-disable camelcase */
|
|
76
|
+
this.log(`\nParsed metadata:\n`);
|
|
77
|
+
|
|
78
|
+
const appFeatureUpdates =
|
|
79
|
+
appMetadata &&
|
|
80
|
+
appMetadata
|
|
81
|
+
.filter(({ app_change_type }) => app_change_type === 'FEATURE_UPDATE')
|
|
82
|
+
.map(
|
|
83
|
+
({ action_type, action_key }) =>
|
|
84
|
+
`${action_key}/${ACTION_TYPE_MAPPING[action_type]}`
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const issueFeatureUpdates =
|
|
88
|
+
issueMetadata &&
|
|
89
|
+
issueMetadata
|
|
90
|
+
.filter(({ app_change_type }) => app_change_type === 'FEATURE_UPDATE')
|
|
91
|
+
.map(({ issue_id }) => `#${issue_id}`);
|
|
92
|
+
|
|
93
|
+
if (appFeatureUpdates || issueFeatureUpdates) {
|
|
94
|
+
this.log(
|
|
95
|
+
`Feature updates: ${[
|
|
96
|
+
...appFeatureUpdates,
|
|
97
|
+
...issueFeatureUpdates,
|
|
98
|
+
].join(', ')}`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const appBugfixes =
|
|
103
|
+
appMetadata &&
|
|
104
|
+
appMetadata
|
|
105
|
+
.filter(({ app_change_type }) => app_change_type === 'BUGFIX')
|
|
106
|
+
.map(
|
|
107
|
+
({ action_type, action_key }) =>
|
|
108
|
+
`${action_key}/${ACTION_TYPE_MAPPING[action_type]}`
|
|
109
|
+
);
|
|
110
|
+
const issueBugfixes =
|
|
111
|
+
issueMetadata &&
|
|
112
|
+
issueMetadata
|
|
113
|
+
.filter(({ app_change_type }) => app_change_type === 'BUGFIX')
|
|
114
|
+
.map(({ issue_id }) => `#${issue_id}`);
|
|
115
|
+
|
|
116
|
+
if (appBugfixes || issueBugfixes) {
|
|
117
|
+
this.log(`Bug fixes: ${[...appBugfixes, issueBugfixes].join(', ')}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (
|
|
121
|
+
!appFeatureUpdates &&
|
|
122
|
+
!issueFeatureUpdates &&
|
|
123
|
+
!appBugfixes &&
|
|
124
|
+
!issueBugfixes
|
|
125
|
+
) {
|
|
126
|
+
this.log(
|
|
127
|
+
`No metadata was found in the changelog. Remember, you can associate the changelog with issues or triggers/actions.\n\n${metadataPromptHelper}`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
this.log();
|
|
131
|
+
/* eslint-enable camelcase */
|
|
56
132
|
|
|
57
133
|
shouldContinue =
|
|
58
134
|
assumeYes ||
|
|
59
135
|
(await this.confirm(
|
|
60
|
-
'Would you like to continue promoting
|
|
136
|
+
'Would you like to continue promoting with this changelog?'
|
|
61
137
|
));
|
|
62
138
|
}
|
|
63
139
|
|
|
@@ -69,11 +145,22 @@ class PromoteCommand extends BaseCommand {
|
|
|
69
145
|
`Preparing to promote version ${version} of your integration "${app.title}".`
|
|
70
146
|
);
|
|
71
147
|
|
|
148
|
+
const isFeatureUpdate =
|
|
149
|
+
hasAppChangeType(appMetadata, 'FEATURE_UPDATE') ||
|
|
150
|
+
hasAppChangeType(issueMetadata, 'FEATURE_UPDATE');
|
|
151
|
+
const isBugfix =
|
|
152
|
+
hasAppChangeType(appMetadata, 'BUGFIX') ||
|
|
153
|
+
hasAppChangeType(issueMetadata, 'BUGFIX');
|
|
72
154
|
const body = {
|
|
73
155
|
job: {
|
|
74
156
|
name: 'promote',
|
|
75
157
|
to_version: version,
|
|
76
158
|
changelog,
|
|
159
|
+
app_metadata: appMetadata,
|
|
160
|
+
loki_metadata: issueMetadata,
|
|
161
|
+
is_feature_update: isFeatureUpdate,
|
|
162
|
+
is_bugfix: isBugfix,
|
|
163
|
+
is_other: !isFeatureUpdate && !isBugfix,
|
|
77
164
|
},
|
|
78
165
|
};
|
|
79
166
|
|
package/src/utils/changelog.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
const _ = require('lodash');
|
|
2
1
|
const path = require('path');
|
|
3
2
|
|
|
4
3
|
const { readFile } = require('./files');
|
|
4
|
+
const { getMetadata } = require('./metadata');
|
|
5
|
+
|
|
6
|
+
const isAppMetadata = (obj) =>
|
|
7
|
+
obj?.app_change_type && obj?.action_key && obj?.action_type;
|
|
8
|
+
|
|
9
|
+
const isIssueMetadata = (obj) => obj?.app_change_type && obj?.issue_id;
|
|
10
|
+
|
|
11
|
+
// Turns an empty array into undefined so it will not be present in the body when sent
|
|
12
|
+
const absentIfEmpty = (arr) => (arr.length === 0 ? undefined : arr);
|
|
5
13
|
|
|
6
14
|
const getChangelogFromMarkdown = (version, markdown) => {
|
|
7
15
|
const lines = markdown
|
|
@@ -9,41 +17,56 @@ const getChangelogFromMarkdown = (version, markdown) => {
|
|
|
9
17
|
.replace(/\r/g, '\n')
|
|
10
18
|
.split('\n');
|
|
11
19
|
|
|
12
|
-
let startingLine =
|
|
13
|
-
RegExp(
|
|
20
|
+
let startingLine = lines.findIndex((line) =>
|
|
21
|
+
RegExp(`^#{1,4} .*${version.split('.').join('\\.')}`).test(line)
|
|
14
22
|
);
|
|
15
23
|
|
|
16
24
|
if (startingLine === -1) {
|
|
17
|
-
|
|
25
|
+
throw new Error(`Version '${version}' not found in changelog`);
|
|
18
26
|
}
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
startingLine += 2;
|
|
28
|
+
startingLine++;
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
30
|
+
// Find the next line that starts with one or more '#' chars
|
|
31
|
+
let endingLine = lines
|
|
32
|
+
.slice(startingLine)
|
|
33
|
+
.findIndex((line) => /^#{1,4} /.test(line));
|
|
28
34
|
|
|
29
35
|
if (endingLine === -1) {
|
|
30
36
|
endingLine = lines.length;
|
|
31
37
|
}
|
|
32
|
-
|
|
33
|
-
// Skip the line before the next version (expected blank)
|
|
34
|
-
endingLine -= 1;
|
|
38
|
+
endingLine += startingLine;
|
|
35
39
|
|
|
36
40
|
const changelogLines = lines.slice(startingLine, endingLine);
|
|
41
|
+
const changelog = [];
|
|
42
|
+
const appMetadata = [];
|
|
43
|
+
const issueMetadata = [];
|
|
44
|
+
|
|
45
|
+
for (const line of changelogLines) {
|
|
46
|
+
for (const metadata of getMetadata(line)) {
|
|
47
|
+
if (isAppMetadata(metadata)) {
|
|
48
|
+
appMetadata.push(metadata);
|
|
49
|
+
} else if (isIssueMetadata(metadata)) {
|
|
50
|
+
issueMetadata.push(metadata);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
changelog.push(line);
|
|
55
|
+
}
|
|
37
56
|
|
|
38
|
-
return
|
|
57
|
+
return {
|
|
58
|
+
changelog: changelog.join('\n').trim(),
|
|
59
|
+
appMetadata: absentIfEmpty(appMetadata),
|
|
60
|
+
issueMetadata: absentIfEmpty(issueMetadata),
|
|
61
|
+
};
|
|
39
62
|
};
|
|
40
63
|
|
|
41
|
-
const getVersionChangelog = (version, appDir = '.') => {
|
|
64
|
+
const getVersionChangelog = async (version, appDir = '.') => {
|
|
42
65
|
const file = path.resolve(appDir, 'CHANGELOG.md');
|
|
43
66
|
|
|
44
67
|
return readFile(file)
|
|
45
68
|
.then((buffer) => getChangelogFromMarkdown(version, buffer.toString()))
|
|
46
|
-
.catch(() => ''); // We're ignoring files that don't exist or that aren't readable
|
|
69
|
+
.catch(() => ({ changelog: '' })); // We're ignoring files that don't exist or that aren't readable
|
|
47
70
|
};
|
|
48
71
|
|
|
49
72
|
module.exports = {
|