@redocly/cli 1.10.6 → 1.12.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.
- package/CHANGELOG.md +24 -0
- package/lib/__tests__/commands/bundle.test.js +3 -32
- package/lib/__tests__/commands/join.test.js +0 -11
- package/lib/__tests__/utils.test.js +3 -3
- package/lib/cms/api/types.d.ts +22 -11
- package/lib/cms/commands/__tests__/push-status.test.js +338 -29
- package/lib/cms/commands/__tests__/push.test.js +32 -2
- package/lib/cms/commands/__tests__/utils.test.d.ts +1 -0
- package/lib/cms/commands/__tests__/utils.test.js +60 -0
- package/lib/cms/commands/push-status.d.ts +14 -4
- package/lib/cms/commands/push-status.js +160 -90
- package/lib/cms/commands/push.d.ts +6 -2
- package/lib/cms/commands/push.js +8 -2
- package/lib/cms/commands/utils.d.ts +22 -0
- package/lib/cms/commands/utils.js +53 -0
- package/lib/commands/bundle.d.ts +1 -4
- package/lib/commands/bundle.js +2 -32
- package/lib/commands/join.d.ts +0 -3
- package/lib/commands/join.js +13 -36
- package/lib/index.js +69 -27
- package/lib/utils/miscellaneous.js +5 -4
- package/lib/wrapper.d.ts +1 -1
- package/package.json +2 -2
- package/src/__tests__/commands/bundle.test.ts +4 -37
- package/src/__tests__/commands/join.test.ts +0 -17
- package/src/__tests__/utils.test.ts +3 -3
- package/src/cms/api/types.ts +19 -12
- package/src/cms/commands/__tests__/push-status.test.ts +473 -47
- package/src/cms/commands/__tests__/push.test.ts +40 -2
- package/src/cms/commands/__tests__/utils.test.ts +62 -0
- package/src/cms/commands/push-status.ts +242 -120
- package/src/cms/commands/push.ts +21 -5
- package/src/cms/commands/utils.ts +52 -0
- package/src/commands/bundle.ts +3 -53
- package/src/commands/join.ts +13 -49
- package/src/index.ts +89 -28
- package/src/utils/miscellaneous.ts +5 -4
- package/src/wrapper.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -14,10 +14,10 @@ const colors = require("colorette");
|
|
|
14
14
|
const miscellaneous_1 = require("../../utils/miscellaneous");
|
|
15
15
|
const spinner_1 = require("../../utils/spinner");
|
|
16
16
|
const utils_1 = require("../utils");
|
|
17
|
-
const colorette_1 = require("colorette");
|
|
18
17
|
const api_1 = require("../api");
|
|
19
18
|
const js_utils_1 = require("../../utils/js-utils");
|
|
20
|
-
const
|
|
19
|
+
const utils_2 = require("./utils");
|
|
20
|
+
const RETRY_INTERVAL_MS = 5000; // 5 sec
|
|
21
21
|
function handlePushStatus(argv, config) {
|
|
22
22
|
return __awaiter(this, void 0, void 0, function* () {
|
|
23
23
|
const startedAt = performance.now();
|
|
@@ -25,97 +25,154 @@ function handlePushStatus(argv, config) {
|
|
|
25
25
|
const { organization, project: projectId, pushId, wait } = argv;
|
|
26
26
|
const orgId = organization || config.organization;
|
|
27
27
|
if (!orgId) {
|
|
28
|
-
|
|
28
|
+
(0, miscellaneous_1.exitWithError)(`No organization provided, please use --organization option or specify the 'organization' field in the config file.`);
|
|
29
|
+
return;
|
|
29
30
|
}
|
|
30
31
|
const domain = argv.domain || (0, api_1.getDomain)();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const maxExecutionTime = argv['max-execution-time'] || 1200; // 20 min
|
|
33
|
+
const retryIntervalMs = argv['retry-interval']
|
|
34
|
+
? argv['retry-interval'] * 1000
|
|
35
|
+
: RETRY_INTERVAL_MS;
|
|
36
|
+
const startTime = argv['start-time'] || Date.now();
|
|
37
|
+
const retryTimeoutMs = maxExecutionTime * 1000;
|
|
38
|
+
const continueOnDeployFailures = argv['continue-on-deploy-failures'] || false;
|
|
35
39
|
try {
|
|
36
40
|
const apiKey = (0, api_1.getApiKeys)(domain);
|
|
37
41
|
const client = new api_1.ReuniteApiClient(domain, apiKey);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
let pushResponse;
|
|
43
|
+
pushResponse = yield (0, utils_2.retryUntilConditionMet)({
|
|
44
|
+
operation: () => client.remotes.getPush({
|
|
45
|
+
organizationId: orgId,
|
|
46
|
+
projectId,
|
|
47
|
+
pushId,
|
|
48
|
+
}),
|
|
49
|
+
condition: wait
|
|
50
|
+
? // Keep retrying if status is "pending" or "running" (returning false, so the operation will be retried)
|
|
51
|
+
(result) => !['pending', 'running'].includes(result.status['preview'].deploy.status)
|
|
52
|
+
: null,
|
|
53
|
+
onConditionNotMet: (lastResult) => {
|
|
54
|
+
displayDeploymentAndBuildStatus({
|
|
55
|
+
status: lastResult.status['preview'].deploy.status,
|
|
56
|
+
url: lastResult.status['preview'].deploy.url,
|
|
57
|
+
spinner,
|
|
58
|
+
buildType: 'preview',
|
|
59
|
+
continueOnDeployFailures,
|
|
60
|
+
wait,
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
onRetry: (lastResult) => {
|
|
64
|
+
if (argv.onRetry) {
|
|
65
|
+
argv.onRetry({
|
|
66
|
+
preview: lastResult.status.preview,
|
|
67
|
+
production: lastResult.isMainBranch ? lastResult.status.production : null,
|
|
68
|
+
commit: lastResult.commit,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
startTime,
|
|
73
|
+
retryTimeoutMs,
|
|
74
|
+
retryIntervalMs,
|
|
75
|
+
});
|
|
76
|
+
printPushStatus({
|
|
77
|
+
buildType: 'preview',
|
|
78
|
+
spinner,
|
|
79
|
+
wait,
|
|
80
|
+
push: pushResponse,
|
|
81
|
+
continueOnDeployFailures,
|
|
82
|
+
});
|
|
83
|
+
printScorecard(pushResponse.status.preview.scorecard);
|
|
84
|
+
const shouldWaitForProdDeployment = pushResponse.isMainBranch &&
|
|
85
|
+
(wait ? pushResponse.status.preview.deploy.status === 'success' : true);
|
|
86
|
+
if (shouldWaitForProdDeployment) {
|
|
87
|
+
pushResponse = yield (0, utils_2.retryUntilConditionMet)({
|
|
88
|
+
operation: () => client.remotes.getPush({
|
|
89
|
+
organizationId: orgId,
|
|
90
|
+
projectId,
|
|
91
|
+
pushId,
|
|
92
|
+
}),
|
|
93
|
+
condition: wait
|
|
94
|
+
? // Keep retrying if status is "pending" or "running" (returning false, so the operation will be retried)
|
|
95
|
+
(result) => !['pending', 'running'].includes(result.status['production'].deploy.status)
|
|
96
|
+
: null,
|
|
97
|
+
onConditionNotMet: (lastResult) => {
|
|
98
|
+
displayDeploymentAndBuildStatus({
|
|
99
|
+
status: lastResult.status['production'].deploy.status,
|
|
100
|
+
url: lastResult.status['production'].deploy.url,
|
|
101
|
+
spinner,
|
|
102
|
+
buildType: 'production',
|
|
103
|
+
continueOnDeployFailures,
|
|
104
|
+
wait,
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
onRetry: (lastResult) => {
|
|
108
|
+
if (argv.onRetry) {
|
|
109
|
+
argv.onRetry({
|
|
110
|
+
preview: lastResult.status.preview,
|
|
111
|
+
production: lastResult.isMainBranch ? lastResult.status.production : null,
|
|
112
|
+
commit: lastResult.commit,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
startTime,
|
|
117
|
+
retryTimeoutMs,
|
|
118
|
+
retryIntervalMs,
|
|
119
|
+
});
|
|
45
120
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
121
|
+
if (pushResponse.isMainBranch) {
|
|
122
|
+
printPushStatus({
|
|
123
|
+
buildType: 'production',
|
|
124
|
+
spinner,
|
|
125
|
+
wait,
|
|
126
|
+
push: pushResponse,
|
|
127
|
+
continueOnDeployFailures,
|
|
128
|
+
});
|
|
129
|
+
printScorecard(pushResponse.status.production.scorecard);
|
|
51
130
|
}
|
|
52
|
-
printPushStatusInfo();
|
|
131
|
+
printPushStatusInfo({ orgId, projectId, pushId, startedAt });
|
|
132
|
+
const summary = {
|
|
133
|
+
preview: pushResponse.status.preview,
|
|
134
|
+
production: pushResponse.isMainBranch ? pushResponse.status.production : null,
|
|
135
|
+
commit: pushResponse.commit,
|
|
136
|
+
};
|
|
137
|
+
return summary;
|
|
53
138
|
}
|
|
54
139
|
catch (err) {
|
|
140
|
+
spinner.stop(); // Spinner can block process exit, so we need to stop it explicitly.
|
|
55
141
|
const message = err instanceof utils_1.DeploymentError
|
|
56
142
|
? err.message
|
|
57
143
|
: `✗ Failed to get push status. Reason: ${err.message}\n`;
|
|
58
144
|
(0, miscellaneous_1.exitWithError)(message);
|
|
145
|
+
return;
|
|
59
146
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
(0, miscellaneous_1.printExecutionTime)('push-status', startedAt, 'Finished');
|
|
63
|
-
}
|
|
64
|
-
function waitForDeployment(client, buildType) {
|
|
65
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
-
return new Promise((resolve, reject) => {
|
|
67
|
-
if (performance.now() - startedAt > maxExecutionTime * 1000) {
|
|
68
|
-
spinner.stop();
|
|
69
|
-
reject(new Error(`Time limit exceeded.`));
|
|
70
|
-
}
|
|
71
|
-
getAndPrintPushStatus(client, buildType)
|
|
72
|
-
.then((push) => {
|
|
73
|
-
if (!['pending', 'running'].includes(push.status[buildType].deploy.status)) {
|
|
74
|
-
printScorecard(push.status[buildType].scorecard);
|
|
75
|
-
resolve(push);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
79
|
-
try {
|
|
80
|
-
const pushResponse = yield waitForDeployment(client, buildType);
|
|
81
|
-
resolve(pushResponse);
|
|
82
|
-
}
|
|
83
|
-
catch (e) {
|
|
84
|
-
reject(e);
|
|
85
|
-
}
|
|
86
|
-
}), INTERVAL);
|
|
87
|
-
})
|
|
88
|
-
.catch(reject);
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
function getAndPrintPushStatus(client, buildType) {
|
|
93
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
94
|
-
const push = yield client.remotes.getPush({
|
|
95
|
-
organizationId: orgId,
|
|
96
|
-
projectId,
|
|
97
|
-
pushId,
|
|
98
|
-
});
|
|
99
|
-
if (push.isOutdated || !push.hasChanges) {
|
|
100
|
-
process.stderr.write((0, colorette_1.yellow)(`Files not uploaded. Reason: ${push.isOutdated ? 'outdated' : 'no changes'}.\n`));
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
displayDeploymentAndBuildStatus({
|
|
104
|
-
status: push.status[buildType].deploy.status,
|
|
105
|
-
previewUrl: push.status[buildType].deploy.url,
|
|
106
|
-
buildType,
|
|
107
|
-
spinner,
|
|
108
|
-
wait,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
return push;
|
|
112
|
-
});
|
|
147
|
+
finally {
|
|
148
|
+
spinner.stop(); // Spinner can block process exit, so we need to stop it explicitly.
|
|
113
149
|
}
|
|
114
150
|
});
|
|
115
151
|
}
|
|
116
152
|
exports.handlePushStatus = handlePushStatus;
|
|
153
|
+
function printPushStatusInfo({ orgId, projectId, pushId, startedAt, }) {
|
|
154
|
+
process.stderr.write(`\nProcessed push-status for ${colors.yellow(orgId)}, ${colors.yellow(projectId)} and pushID ${colors.yellow(pushId)}.\n`);
|
|
155
|
+
(0, miscellaneous_1.printExecutionTime)('push-status', startedAt, 'Finished');
|
|
156
|
+
}
|
|
157
|
+
function printPushStatus({ buildType, spinner, push, continueOnDeployFailures, }) {
|
|
158
|
+
if (!push) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (push.isOutdated || !push.hasChanges) {
|
|
162
|
+
process.stderr.write(colors.yellow(`Files not added to your project. Reason: ${push.isOutdated ? 'outdated' : 'no changes'}.\n`));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
displayDeploymentAndBuildStatus({
|
|
166
|
+
status: push.status[buildType].deploy.status,
|
|
167
|
+
url: push.status[buildType].deploy.url,
|
|
168
|
+
buildType,
|
|
169
|
+
spinner,
|
|
170
|
+
continueOnDeployFailures,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
117
174
|
function printScorecard(scorecard) {
|
|
118
|
-
if (!scorecard.length) {
|
|
175
|
+
if (!scorecard || scorecard.length === 0) {
|
|
119
176
|
return;
|
|
120
177
|
}
|
|
121
178
|
process.stdout.write(`\n${colors.magenta('Scorecard')}:`);
|
|
@@ -128,24 +185,37 @@ function printScorecard(scorecard) {
|
|
|
128
185
|
}
|
|
129
186
|
process.stdout.write(`\n`);
|
|
130
187
|
}
|
|
131
|
-
function displayDeploymentAndBuildStatus({ status,
|
|
188
|
+
function displayDeploymentAndBuildStatus({ status, url, spinner, buildType, continueOnDeployFailures, wait, }) {
|
|
189
|
+
const message = getMessage({ status, url, buildType, wait });
|
|
190
|
+
if (status === 'failed' && !continueOnDeployFailures) {
|
|
191
|
+
spinner.stop();
|
|
192
|
+
throw new utils_1.DeploymentError(message);
|
|
193
|
+
}
|
|
194
|
+
if (wait && (status === 'pending' || status === 'running')) {
|
|
195
|
+
return spinner.start(message);
|
|
196
|
+
}
|
|
197
|
+
spinner.stop();
|
|
198
|
+
return process.stdout.write(message);
|
|
199
|
+
}
|
|
200
|
+
function getMessage({ status, url, buildType, wait, }) {
|
|
132
201
|
switch (status) {
|
|
202
|
+
case 'skipped':
|
|
203
|
+
return `${colors.yellow(`Skipped ${buildType}`)}\n`;
|
|
204
|
+
case 'pending': {
|
|
205
|
+
const message = `${colors.yellow(`Pending ${buildType}`)}`;
|
|
206
|
+
return wait ? message : `Status: ${message}\n`;
|
|
207
|
+
}
|
|
208
|
+
case 'running': {
|
|
209
|
+
const message = `${colors.yellow(`Running ${buildType}`)}`;
|
|
210
|
+
return wait ? message : `Status: ${message}\n`;
|
|
211
|
+
}
|
|
133
212
|
case 'success':
|
|
134
|
-
|
|
135
|
-
return process.stdout.write(`${colors.green(`🚀 ${(0, js_utils_1.capitalize)(buildType)} deploy success.`)}\n${colors.magenta(`${(0, js_utils_1.capitalize)(buildType)} URL`)}: ${colors.cyan(previewUrl)}\n`);
|
|
213
|
+
return `${colors.green(`🚀 ${(0, js_utils_1.capitalize)(buildType)} deploy success.`)}\n${colors.magenta(`${(0, js_utils_1.capitalize)(buildType)} URL`)}: ${colors.cyan(url || 'No URL yet.')}\n`;
|
|
136
214
|
case 'failed':
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return wait
|
|
141
|
-
|
|
142
|
-
: process.stdout.write(`Status: ${colors.yellow(`Pending ${buildType}`)}\n`);
|
|
143
|
-
case 'skipped':
|
|
144
|
-
spinner.stop();
|
|
145
|
-
return process.stdout.write(`${colors.yellow(`Skipped ${buildType}`)}\n`);
|
|
146
|
-
case 'running':
|
|
147
|
-
return wait
|
|
148
|
-
? spinner.start(`${colors.yellow(`Running ${buildType}`)}`)
|
|
149
|
-
: process.stdout.write(`Status: ${colors.yellow(`Running ${buildType}`)}\n`);
|
|
215
|
+
return `${colors.red(`❌ ${(0, js_utils_1.capitalize)(buildType)} deploy fail.`)}\n${colors.magenta(`${(0, js_utils_1.capitalize)(buildType)} URL`)}: ${colors.cyan(url || 'No URL yet.')}`;
|
|
216
|
+
default: {
|
|
217
|
+
const message = `${colors.yellow(`No status yet for ${buildType} deploy`)}`;
|
|
218
|
+
return wait ? message : `Status: ${message}\n`;
|
|
219
|
+
}
|
|
150
220
|
}
|
|
151
221
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Config } from '@redocly/openapi-core';
|
|
1
|
+
import type { OutputFormat, Config } from '@redocly/openapi-core';
|
|
2
2
|
export type PushOptions = {
|
|
3
3
|
apis?: string[];
|
|
4
4
|
organization?: string;
|
|
@@ -18,6 +18,10 @@ export type PushOptions = {
|
|
|
18
18
|
config?: string;
|
|
19
19
|
'wait-for-deployment'?: boolean;
|
|
20
20
|
'max-execution-time': number;
|
|
21
|
+
'continue-on-deploy-failures'?: boolean;
|
|
21
22
|
verbose?: boolean;
|
|
23
|
+
format?: Extract<OutputFormat, 'stylish'>;
|
|
22
24
|
};
|
|
23
|
-
export declare function handlePush(argv: PushOptions, config: Config): Promise<
|
|
25
|
+
export declare function handlePush(argv: PushOptions, config: Config): Promise<{
|
|
26
|
+
pushId: string;
|
|
27
|
+
} | void>;
|
package/lib/cms/commands/push.js
CHANGED
|
@@ -13,14 +13,15 @@ exports.handlePush = void 0;
|
|
|
13
13
|
const fs = require("fs");
|
|
14
14
|
const path = require("path");
|
|
15
15
|
const openapi_core_1 = require("@redocly/openapi-core");
|
|
16
|
-
const miscellaneous_1 = require("../../utils/miscellaneous");
|
|
17
16
|
const colorette_1 = require("colorette");
|
|
18
17
|
const pluralize = require("pluralize");
|
|
18
|
+
const miscellaneous_1 = require("../../utils/miscellaneous");
|
|
19
19
|
const push_status_1 = require("./push-status");
|
|
20
20
|
const api_1 = require("../api");
|
|
21
21
|
function handlePush(argv, config) {
|
|
22
22
|
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
-
const startedAt = performance.now();
|
|
23
|
+
const startedAt = performance.now(); // for printing execution time
|
|
24
|
+
const startTime = Date.now(); // for push-status command
|
|
24
25
|
const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
|
|
25
26
|
const orgId = organization || config.organization;
|
|
26
27
|
if (!argv.message || !argv.author || !argv.branch) {
|
|
@@ -76,10 +77,15 @@ function handlePush(argv, config) {
|
|
|
76
77
|
wait: true,
|
|
77
78
|
domain,
|
|
78
79
|
'max-execution-time': maxExecutionTime,
|
|
80
|
+
'start-time': startTime,
|
|
81
|
+
'continue-on-deploy-failures': argv['continue-on-deploy-failures'],
|
|
79
82
|
}, config);
|
|
80
83
|
}
|
|
81
84
|
verbose &&
|
|
82
85
|
(0, miscellaneous_1.printExecutionTime)('push', startedAt, `${pluralize('file', filesToUpload.length)} uploaded to organization ${orgId}, project ${projectId}. Push ID: ${id}.`);
|
|
86
|
+
return {
|
|
87
|
+
pushId: id,
|
|
88
|
+
};
|
|
83
89
|
}
|
|
84
90
|
catch (err) {
|
|
85
91
|
const message = err instanceof miscellaneous_1.HandledError ? '' : `✗ File upload failed. Reason: ${err.message}`;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This function retries an operation until a condition is met or a timeout is exceeded.
|
|
3
|
+
* If the condition is not met within the timeout, an error is thrown.
|
|
4
|
+
* @operation The operation to retry.
|
|
5
|
+
* @condition The condition to check after each operation result. Return false to continue retrying. Return true to stop retrying.
|
|
6
|
+
* If not provided, the first result will be returned.
|
|
7
|
+
* @param onConditionNotMet Will be called with the last result right after checking condition and before timeout and retrying.
|
|
8
|
+
* @param onRetry Will be called right before retrying operation with the last result before retrying.
|
|
9
|
+
* @param startTime The start time of the operation. Default is the current time.
|
|
10
|
+
* @param retryTimeoutMs The maximum time to retry the operation. Default is 10 minutes.
|
|
11
|
+
* @param retryIntervalMs The interval between retries. Default is 5 seconds.
|
|
12
|
+
*/
|
|
13
|
+
export declare function retryUntilConditionMet<T>({ operation, condition, onConditionNotMet, onRetry, startTime, retryTimeoutMs, // 10 min
|
|
14
|
+
retryIntervalMs, }: {
|
|
15
|
+
operation: () => Promise<T>;
|
|
16
|
+
condition?: ((result: T) => boolean) | null;
|
|
17
|
+
onConditionNotMet?: (lastResult: T) => void;
|
|
18
|
+
onRetry?: (lastResult: T) => void | Promise<void>;
|
|
19
|
+
startTime?: number;
|
|
20
|
+
retryTimeoutMs?: number;
|
|
21
|
+
retryIntervalMs?: number;
|
|
22
|
+
}): Promise<T>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.retryUntilConditionMet = void 0;
|
|
13
|
+
const openapi_core_1 = require("@redocly/openapi-core");
|
|
14
|
+
/**
|
|
15
|
+
* This function retries an operation until a condition is met or a timeout is exceeded.
|
|
16
|
+
* If the condition is not met within the timeout, an error is thrown.
|
|
17
|
+
* @operation The operation to retry.
|
|
18
|
+
* @condition The condition to check after each operation result. Return false to continue retrying. Return true to stop retrying.
|
|
19
|
+
* If not provided, the first result will be returned.
|
|
20
|
+
* @param onConditionNotMet Will be called with the last result right after checking condition and before timeout and retrying.
|
|
21
|
+
* @param onRetry Will be called right before retrying operation with the last result before retrying.
|
|
22
|
+
* @param startTime The start time of the operation. Default is the current time.
|
|
23
|
+
* @param retryTimeoutMs The maximum time to retry the operation. Default is 10 minutes.
|
|
24
|
+
* @param retryIntervalMs The interval between retries. Default is 5 seconds.
|
|
25
|
+
*/
|
|
26
|
+
function retryUntilConditionMet({ operation, condition, onConditionNotMet, onRetry, startTime = Date.now(), retryTimeoutMs = 600000, // 10 min
|
|
27
|
+
retryIntervalMs = 5000, // 5 sec
|
|
28
|
+
}) {
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
function attempt() {
|
|
31
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
+
const result = yield operation();
|
|
33
|
+
if (!condition) {
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
if (condition(result)) {
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
else if (Date.now() - startTime > retryTimeoutMs) {
|
|
40
|
+
throw new Error('Timeout exceeded');
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
onConditionNotMet === null || onConditionNotMet === void 0 ? void 0 : onConditionNotMet(result);
|
|
44
|
+
yield (0, openapi_core_1.pause)(retryIntervalMs);
|
|
45
|
+
yield (onRetry === null || onRetry === void 0 ? void 0 : onRetry(result));
|
|
46
|
+
return attempt();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return attempt();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
exports.retryUntilConditionMet = retryUntilConditionMet;
|
package/lib/commands/bundle.d.ts
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import { Config
|
|
1
|
+
import { Config } from '@redocly/openapi-core';
|
|
2
2
|
import type { OutputExtensions, Skips } from '../types';
|
|
3
3
|
export type BundleOptions = {
|
|
4
4
|
apis?: string[];
|
|
5
|
-
'max-problems'?: number;
|
|
6
5
|
extends?: string[];
|
|
7
6
|
config?: string;
|
|
8
|
-
format?: OutputFormat;
|
|
9
7
|
output?: string;
|
|
10
8
|
ext: OutputExtensions;
|
|
11
9
|
dereferenced?: boolean;
|
|
12
10
|
force?: boolean;
|
|
13
|
-
lint?: boolean;
|
|
14
11
|
metafile?: string;
|
|
15
12
|
'remove-unused-components'?: boolean;
|
|
16
13
|
'keep-url-references'?: boolean;
|
package/lib/commands/bundle.js
CHANGED
|
@@ -34,44 +34,15 @@ function handleBundle(argv, config, version) {
|
|
|
34
34
|
((_c = (_b = (_a = config.rawConfig) === null || _a === void 0 ? void 0 : _a.styleguide) === null || _b === void 0 ? void 0 : _b.decorators) === null || _c === void 0 ? void 0 : _c.hasOwnProperty('remove-unused-components'));
|
|
35
35
|
const apis = yield (0, miscellaneous_1.getFallbackApisOrExit)(argv.apis, config);
|
|
36
36
|
const totals = { errors: 0, warnings: 0, ignored: 0 };
|
|
37
|
-
const
|
|
38
|
-
const deprecatedOptions = [
|
|
39
|
-
'lint',
|
|
40
|
-
'format',
|
|
41
|
-
'skip-rule',
|
|
42
|
-
'extends',
|
|
43
|
-
'max-problems',
|
|
44
|
-
];
|
|
37
|
+
const deprecatedOptions = [];
|
|
45
38
|
(0, miscellaneous_2.checkForDeprecatedOptions)(argv, deprecatedOptions);
|
|
46
39
|
for (const { path, alias } of apis) {
|
|
47
40
|
try {
|
|
48
41
|
const startedAt = perf_hooks_1.performance.now();
|
|
49
42
|
const resolvedConfig = (0, openapi_core_1.getMergedConfig)(config, alias);
|
|
50
43
|
const { styleguide } = resolvedConfig;
|
|
51
|
-
styleguide.skipRules(argv['skip-rule']);
|
|
52
44
|
styleguide.skipPreprocessors(argv['skip-preprocessor']);
|
|
53
45
|
styleguide.skipDecorators(argv['skip-decorator']);
|
|
54
|
-
if (argv.lint) {
|
|
55
|
-
(0, miscellaneous_1.checkIfRulesetExist)(styleguide.rules);
|
|
56
|
-
if (config.styleguide.recommendedFallback) {
|
|
57
|
-
process.stderr.write(`No configurations were provided -- using built in ${(0, colorette_1.blue)('recommended')} configuration by default.\n\n`);
|
|
58
|
-
}
|
|
59
|
-
const results = yield (0, openapi_core_1.lint)({
|
|
60
|
-
ref: path,
|
|
61
|
-
config: resolvedConfig,
|
|
62
|
-
});
|
|
63
|
-
const fileLintTotals = (0, openapi_core_1.getTotals)(results);
|
|
64
|
-
totals.errors += fileLintTotals.errors;
|
|
65
|
-
totals.warnings += fileLintTotals.warnings;
|
|
66
|
-
totals.ignored += fileLintTotals.ignored;
|
|
67
|
-
(0, openapi_core_1.formatProblems)(results, {
|
|
68
|
-
format: argv.format || 'codeframe',
|
|
69
|
-
totals: fileLintTotals,
|
|
70
|
-
version,
|
|
71
|
-
maxProblems: maxProblems,
|
|
72
|
-
});
|
|
73
|
-
(0, miscellaneous_1.printLintTotals)(fileLintTotals, 2);
|
|
74
|
-
}
|
|
75
46
|
process.stderr.write((0, colorette_1.gray)(`bundling ${path}...\n`));
|
|
76
47
|
const _f = yield (0, openapi_core_1.bundle)({
|
|
77
48
|
config: resolvedConfig,
|
|
@@ -96,8 +67,7 @@ function handleBundle(argv, config, version) {
|
|
|
96
67
|
totals.warnings += fileTotals.warnings;
|
|
97
68
|
totals.ignored += fileTotals.ignored;
|
|
98
69
|
(0, openapi_core_1.formatProblems)(problems, {
|
|
99
|
-
format:
|
|
100
|
-
maxProblems: maxProblems,
|
|
70
|
+
format: 'codeframe',
|
|
101
71
|
totals: fileTotals,
|
|
102
72
|
version,
|
|
103
73
|
});
|
package/lib/commands/join.d.ts
CHANGED
|
@@ -2,9 +2,6 @@ import { Config } from '@redocly/openapi-core';
|
|
|
2
2
|
import type { RuleSeverity } from '@redocly/openapi-core';
|
|
3
3
|
export type JoinOptions = {
|
|
4
4
|
apis: string[];
|
|
5
|
-
lint?: boolean;
|
|
6
|
-
decorate?: boolean;
|
|
7
|
-
preprocess?: boolean;
|
|
8
5
|
'prefix-tags-with-info-prop'?: string;
|
|
9
6
|
'prefix-tags-with-filename'?: boolean;
|
|
10
7
|
'prefix-components-with-info-prop'?: string;
|
package/lib/commands/join.js
CHANGED
|
@@ -28,7 +28,6 @@ function handleJoin(argv, config, packageVersion) {
|
|
|
28
28
|
if (argv.apis.length < 2) {
|
|
29
29
|
return (0, miscellaneous_1.exitWithError)(`At least 2 apis should be provided. \n\n`);
|
|
30
30
|
}
|
|
31
|
-
(0, miscellaneous_1.checkForDeprecatedOptions)(argv, ['lint']);
|
|
32
31
|
const fileExtension = (0, miscellaneous_1.getAndValidateFileExtension)(argv.output || argv.apis[0]);
|
|
33
32
|
const { 'prefix-components-with-info-prop': prefixComponentsWithInfoProp, 'prefix-tags-with-filename': prefixTagsWithFilename, 'prefix-tags-with-info-prop': prefixTagsWithInfoProp, 'without-x-tag-groups': withoutXTagGroups, output: specFilename = `openapi.${fileExtension}`, } = argv;
|
|
34
33
|
const usedTagsOptions = [
|
|
@@ -42,22 +41,18 @@ function handleJoin(argv, config, packageVersion) {
|
|
|
42
41
|
const apis = yield (0, miscellaneous_1.getFallbackApisOrExit)(argv.apis, config);
|
|
43
42
|
const externalRefResolver = new openapi_core_1.BaseResolver(config.resolve);
|
|
44
43
|
const documents = yield Promise.all(apis.map(({ path }) => externalRefResolver.resolveDocument(null, path, true)));
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
...Object.keys(config.styleguide.preprocessors.oas2),
|
|
58
|
-
]);
|
|
59
|
-
config.styleguide.skipPreprocessors(Array.from(preprocessors));
|
|
60
|
-
}
|
|
44
|
+
const decorators = new Set([
|
|
45
|
+
...Object.keys(config.styleguide.decorators.oas3_0),
|
|
46
|
+
...Object.keys(config.styleguide.decorators.oas3_1),
|
|
47
|
+
...Object.keys(config.styleguide.decorators.oas2),
|
|
48
|
+
]);
|
|
49
|
+
config.styleguide.skipDecorators(Array.from(decorators));
|
|
50
|
+
const preprocessors = new Set([
|
|
51
|
+
...Object.keys(config.styleguide.preprocessors.oas3_0),
|
|
52
|
+
...Object.keys(config.styleguide.preprocessors.oas3_1),
|
|
53
|
+
...Object.keys(config.styleguide.preprocessors.oas2),
|
|
54
|
+
]);
|
|
55
|
+
config.styleguide.skipPreprocessors(Array.from(preprocessors));
|
|
61
56
|
const bundleResults = yield Promise.all(documents.map((document) => (0, openapi_core_1.bundleDocument)({
|
|
62
57
|
document,
|
|
63
58
|
config: config.styleguide,
|
|
@@ -70,7 +65,7 @@ function handleJoin(argv, config, packageVersion) {
|
|
|
70
65
|
if (fileTotals.errors) {
|
|
71
66
|
(0, openapi_core_1.formatProblems)(problems, {
|
|
72
67
|
totals: fileTotals,
|
|
73
|
-
version:
|
|
68
|
+
version: packageVersion,
|
|
74
69
|
});
|
|
75
70
|
(0, miscellaneous_1.exitWithError)(`❌ Errors encountered while bundling ${(0, colorette_1.blue)(document.source.absoluteRef)}: join will not proceed.\n`);
|
|
76
71
|
}
|
|
@@ -91,11 +86,6 @@ function handleJoin(argv, config, packageVersion) {
|
|
|
91
86
|
return (0, miscellaneous_1.exitWithError)(`${e.message}: ${(0, colorette_1.blue)(document.source.absoluteRef)}`);
|
|
92
87
|
}
|
|
93
88
|
}
|
|
94
|
-
if (argv.lint) {
|
|
95
|
-
for (const document of documents) {
|
|
96
|
-
yield validateApi(document, config.styleguide, externalRefResolver, packageVersion);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
89
|
const joinedDef = {};
|
|
100
90
|
const potentialConflicts = {
|
|
101
91
|
tags: {},
|
|
@@ -561,19 +551,6 @@ function getInfoPrefix(info, prefixArg, type) {
|
|
|
561
551
|
(0, miscellaneous_1.exitWithError)(`${(0, colorette_1.yellow)(`prefix-${type}-with-info-prop`)} argument value length should not exceed 50 characters. \n\n`);
|
|
562
552
|
return info[prefixArg].replaceAll(/\s/g, '_');
|
|
563
553
|
}
|
|
564
|
-
function validateApi(document, config, externalRefResolver, packageVersion) {
|
|
565
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
566
|
-
try {
|
|
567
|
-
const results = yield (0, openapi_core_1.lintDocument)({ document, config, externalRefResolver });
|
|
568
|
-
const fileTotals = (0, openapi_core_1.getTotals)(results);
|
|
569
|
-
(0, openapi_core_1.formatProblems)(results, { format: 'stylish', totals: fileTotals, version: packageVersion });
|
|
570
|
-
(0, miscellaneous_1.printLintTotals)(fileTotals, 2);
|
|
571
|
-
}
|
|
572
|
-
catch (err) {
|
|
573
|
-
(0, miscellaneous_1.handleError)(err, document.parsed);
|
|
574
|
-
}
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
554
|
function replace$Refs(obj, componentsPrefix) {
|
|
578
555
|
(0, split_1.crawl)(obj, (node) => {
|
|
579
556
|
if (node.$ref && typeof node.$ref === 'string' && (0, split_1.startsWithComponents)(node.$ref)) {
|