@redocly/cli 1.22.1 → 1.23.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 +12 -0
- package/lib/__tests__/commands/bundle.test.js +110 -1
- package/lib/__tests__/fetch-with-timeout.test.js +29 -5
- package/lib/__tests__/utils.test.js +54 -32
- package/lib/cms/api/__tests__/api.client.test.js +17 -9
- package/lib/cms/api/api-client.d.ts +26 -7
- package/lib/cms/api/api-client.js +103 -72
- package/lib/cms/commands/__tests__/push-status.test.js +1 -1
- package/lib/cms/commands/__tests__/push.test.js +41 -1
- package/lib/cms/commands/__tests__/utils.test.js +1 -1
- package/lib/cms/commands/push-status.d.ts +1 -1
- package/lib/cms/commands/push-status.js +3 -7
- package/lib/cms/commands/push.js +4 -4
- package/lib/cms/commands/utils.d.ts +3 -0
- package/lib/cms/commands/utils.js +8 -1
- package/lib/commands/bundle.d.ts +1 -1
- package/lib/commands/bundle.js +9 -9
- package/lib/commands/eject.d.ts +1 -1
- package/lib/commands/eject.js +1 -1
- package/lib/commands/preview-project/index.js +1 -1
- package/lib/index.js +1 -2
- package/lib/types.d.ts +1 -0
- package/lib/utils/__mocks__/miscellaneous.d.ts +1 -0
- package/lib/utils/__mocks__/miscellaneous.js +2 -1
- package/lib/utils/fetch-with-timeout.d.ts +6 -1
- package/lib/utils/fetch-with-timeout.js +16 -14
- package/lib/utils/miscellaneous.d.ts +4 -1
- package/lib/utils/miscellaneous.js +24 -29
- package/lib/utils/update-version-notifier.js +8 -4
- package/package.json +2 -2
- package/src/__tests__/commands/bundle.test.ts +131 -4
- package/src/__tests__/fetch-with-timeout.test.ts +36 -6
- package/src/__tests__/utils.test.ts +58 -33
- package/src/cms/api/__tests__/api.client.test.ts +20 -11
- package/src/cms/api/api-client.ts +158 -91
- package/src/cms/commands/__tests__/push-status.test.ts +1 -1
- package/src/cms/commands/__tests__/push.test.ts +49 -2
- package/src/cms/commands/__tests__/utils.test.ts +1 -1
- package/src/cms/commands/push-status.ts +5 -9
- package/src/cms/commands/push.ts +5 -6
- package/src/cms/commands/utils.ts +15 -1
- package/src/commands/bundle.ts +14 -12
- package/src/commands/eject.ts +2 -2
- package/src/commands/preview-project/index.ts +1 -1
- package/src/index.ts +1 -2
- package/src/types.ts +1 -0
- package/src/utils/__mocks__/miscellaneous.ts +1 -0
- package/src/utils/fetch-with-timeout.ts +23 -14
- package/src/utils/miscellaneous.ts +32 -37
- package/src/utils/update-version-notifier.ts +11 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,63 +1,89 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ReuniteApiClient = void 0;
|
|
4
|
-
const node_fetch_1 = require("node-fetch");
|
|
3
|
+
exports.ReuniteApiClient = exports.ReuniteApiError = void 0;
|
|
5
4
|
const FormData = require("form-data");
|
|
6
|
-
const openapi_core_1 = require("@redocly/openapi-core");
|
|
7
5
|
const fetch_with_timeout_1 = require("../../utils/fetch-with-timeout");
|
|
8
|
-
class
|
|
9
|
-
constructor(
|
|
10
|
-
|
|
11
|
-
this.
|
|
6
|
+
class ReuniteApiError extends Error {
|
|
7
|
+
constructor(message, status) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.status = status;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.ReuniteApiError = ReuniteApiError;
|
|
13
|
+
class ReuniteBaseApiClient {
|
|
14
|
+
constructor(version, command) {
|
|
15
|
+
this.version = version;
|
|
16
|
+
this.command = command;
|
|
12
17
|
}
|
|
13
18
|
async getParsedResponse(response) {
|
|
14
19
|
const responseBody = await response.json();
|
|
15
20
|
if (response.ok) {
|
|
16
21
|
return responseBody;
|
|
17
22
|
}
|
|
18
|
-
throw new
|
|
23
|
+
throw new ReuniteApiError(`${responseBody.title || response.statusText || 'Unknown error'}.`, response.status);
|
|
19
24
|
}
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
request(url, options) {
|
|
26
|
+
const headers = {
|
|
27
|
+
...options.headers,
|
|
28
|
+
'user-agent': `redocly-cli/${this.version.trim()} ${this.command}`,
|
|
29
|
+
};
|
|
30
|
+
return (0, fetch_with_timeout_1.default)(url, {
|
|
31
|
+
...options,
|
|
32
|
+
headers,
|
|
27
33
|
});
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class RemotesApiClient extends ReuniteBaseApiClient {
|
|
37
|
+
constructor(domain, apiKey, version, command) {
|
|
38
|
+
super(version, command);
|
|
39
|
+
this.domain = domain;
|
|
40
|
+
this.apiKey = apiKey;
|
|
41
|
+
}
|
|
42
|
+
async getDefaultBranch(organizationId, projectId) {
|
|
31
43
|
try {
|
|
44
|
+
const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/source`, {
|
|
45
|
+
timeout: fetch_with_timeout_1.DEFAULT_FETCH_TIMEOUT,
|
|
46
|
+
method: 'GET',
|
|
47
|
+
headers: {
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
32
52
|
const source = await this.getParsedResponse(response);
|
|
33
53
|
return source.branchName;
|
|
34
54
|
}
|
|
35
55
|
catch (err) {
|
|
36
|
-
|
|
56
|
+
const message = `Failed to fetch default branch. ${err.message}`;
|
|
57
|
+
if (err instanceof ReuniteApiError) {
|
|
58
|
+
throw new ReuniteApiError(message, err.status);
|
|
59
|
+
}
|
|
60
|
+
throw new Error(message);
|
|
37
61
|
}
|
|
38
62
|
}
|
|
39
63
|
async upsert(organizationId, projectId, remote) {
|
|
40
|
-
const response = await (0, fetch_with_timeout_1.default)(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes`, {
|
|
41
|
-
method: 'POST',
|
|
42
|
-
headers: {
|
|
43
|
-
'Content-Type': 'application/json',
|
|
44
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
45
|
-
},
|
|
46
|
-
body: JSON.stringify({
|
|
47
|
-
mountPath: remote.mountPath,
|
|
48
|
-
mountBranchName: remote.mountBranchName,
|
|
49
|
-
type: 'CICD',
|
|
50
|
-
autoMerge: true,
|
|
51
|
-
}),
|
|
52
|
-
});
|
|
53
|
-
if (!response) {
|
|
54
|
-
throw new Error(`Failed to upsert.`);
|
|
55
|
-
}
|
|
56
64
|
try {
|
|
65
|
+
const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes`, {
|
|
66
|
+
timeout: fetch_with_timeout_1.DEFAULT_FETCH_TIMEOUT,
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
mountPath: remote.mountPath,
|
|
74
|
+
mountBranchName: remote.mountBranchName,
|
|
75
|
+
type: 'CICD',
|
|
76
|
+
autoMerge: true,
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
57
79
|
return await this.getParsedResponse(response);
|
|
58
80
|
}
|
|
59
81
|
catch (err) {
|
|
60
|
-
|
|
82
|
+
const message = `Failed to upsert remote. ${err.message}`;
|
|
83
|
+
if (err instanceof ReuniteApiError) {
|
|
84
|
+
throw new ReuniteApiError(message, err.status);
|
|
85
|
+
}
|
|
86
|
+
throw new Error(message);
|
|
61
87
|
}
|
|
62
88
|
}
|
|
63
89
|
async push(organizationId, projectId, payload, files) {
|
|
@@ -76,63 +102,68 @@ class RemotesApiClient {
|
|
|
76
102
|
formData.append(`files[${file.path}]`, file.stream);
|
|
77
103
|
}
|
|
78
104
|
payload.isMainBranch && formData.append('isMainBranch', 'true');
|
|
79
|
-
const response = await (0, node_fetch_1.default)(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes`, {
|
|
80
|
-
method: 'POST',
|
|
81
|
-
headers: {
|
|
82
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
83
|
-
},
|
|
84
|
-
body: formData,
|
|
85
|
-
agent: (0, openapi_core_1.getProxyAgent)(),
|
|
86
|
-
});
|
|
87
105
|
try {
|
|
106
|
+
const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes`, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: {
|
|
109
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
110
|
+
},
|
|
111
|
+
body: formData,
|
|
112
|
+
});
|
|
88
113
|
return await this.getParsedResponse(response);
|
|
89
114
|
}
|
|
90
115
|
catch (err) {
|
|
91
|
-
|
|
116
|
+
const message = `Failed to push. ${err.message}`;
|
|
117
|
+
if (err instanceof ReuniteApiError) {
|
|
118
|
+
throw new ReuniteApiError(message, err.status);
|
|
119
|
+
}
|
|
120
|
+
throw new Error(message);
|
|
92
121
|
}
|
|
93
122
|
}
|
|
94
|
-
async getRemotesList(organizationId, projectId, mountPath) {
|
|
95
|
-
const response = await (0, fetch_with_timeout_1.default)(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes?filter=mountPath:/${mountPath}/`, {
|
|
96
|
-
method: 'GET',
|
|
97
|
-
headers: {
|
|
98
|
-
'Content-Type': 'application/json',
|
|
99
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
if (!response) {
|
|
103
|
-
throw new Error(`Failed to get remotes list.`);
|
|
104
|
-
}
|
|
123
|
+
async getRemotesList({ organizationId, projectId, mountPath, }) {
|
|
105
124
|
try {
|
|
125
|
+
const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes?filter=mountPath:/${mountPath}/`, {
|
|
126
|
+
timeout: fetch_with_timeout_1.DEFAULT_FETCH_TIMEOUT,
|
|
127
|
+
method: 'GET',
|
|
128
|
+
headers: {
|
|
129
|
+
'Content-Type': 'application/json',
|
|
130
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
106
133
|
return await this.getParsedResponse(response);
|
|
107
134
|
}
|
|
108
135
|
catch (err) {
|
|
109
|
-
|
|
136
|
+
const message = `Failed to get remote list. ${err.message}`;
|
|
137
|
+
if (err instanceof ReuniteApiError) {
|
|
138
|
+
throw new ReuniteApiError(message, err.status);
|
|
139
|
+
}
|
|
140
|
+
throw new Error(message);
|
|
110
141
|
}
|
|
111
142
|
}
|
|
112
143
|
async getPush({ organizationId, projectId, pushId, }) {
|
|
113
|
-
const response = await (0, fetch_with_timeout_1.default)(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes/${pushId}`, {
|
|
114
|
-
method: 'GET',
|
|
115
|
-
headers: {
|
|
116
|
-
'Content-Type': 'application/json',
|
|
117
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
if (!response) {
|
|
121
|
-
throw new Error(`Failed to get push status.`);
|
|
122
|
-
}
|
|
123
144
|
try {
|
|
145
|
+
const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes/${pushId}`, {
|
|
146
|
+
timeout: fetch_with_timeout_1.DEFAULT_FETCH_TIMEOUT,
|
|
147
|
+
method: 'GET',
|
|
148
|
+
headers: {
|
|
149
|
+
'Content-Type': 'application/json',
|
|
150
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
124
153
|
return await this.getParsedResponse(response);
|
|
125
154
|
}
|
|
126
155
|
catch (err) {
|
|
127
|
-
|
|
156
|
+
const message = `Failed to get push status. ${err.message}`;
|
|
157
|
+
if (err instanceof ReuniteApiError) {
|
|
158
|
+
throw new ReuniteApiError(message, err.status);
|
|
159
|
+
}
|
|
160
|
+
throw new Error(message);
|
|
128
161
|
}
|
|
129
162
|
}
|
|
130
163
|
}
|
|
131
164
|
class ReuniteApiClient {
|
|
132
|
-
constructor(domain, apiKey) {
|
|
133
|
-
this.
|
|
134
|
-
this.apiKey = apiKey;
|
|
135
|
-
this.remotes = new RemotesApiClient(this.domain, this.apiKey);
|
|
165
|
+
constructor({ domain, apiKey, version, command, }) {
|
|
166
|
+
this.remotes = new RemotesApiClient(domain, apiKey, version, command);
|
|
136
167
|
}
|
|
137
168
|
}
|
|
138
169
|
exports.ReuniteApiClient = ReuniteApiClient;
|
|
@@ -554,7 +554,7 @@ describe('handlePushStatus()', () => {
|
|
|
554
554
|
config: mockConfig,
|
|
555
555
|
version: 'cli-version',
|
|
556
556
|
})).rejects.toThrowErrorMatchingInlineSnapshot(`
|
|
557
|
-
"✗ Failed to get push status. Reason: Timeout exceeded
|
|
557
|
+
"✗ Failed to get push status. Reason: Timeout exceeded.
|
|
558
558
|
"
|
|
559
559
|
`);
|
|
560
560
|
});
|
|
@@ -269,6 +269,46 @@ describe('handlePush()', () => {
|
|
|
269
269
|
config: mockConfig,
|
|
270
270
|
version: 'cli-version',
|
|
271
271
|
});
|
|
272
|
-
expect(api_1.ReuniteApiClient).toBeCalledWith(
|
|
272
|
+
expect(api_1.ReuniteApiClient).toBeCalledWith({
|
|
273
|
+
domain: 'test-domain-from-env',
|
|
274
|
+
apiKey: 'test-api-key',
|
|
275
|
+
version: 'cli-version',
|
|
276
|
+
command: 'push',
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
it('should print error message', async () => {
|
|
280
|
+
const mockConfig = { apis: {} };
|
|
281
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
282
|
+
remotes.push.mockRestore();
|
|
283
|
+
remotes.push.mockRejectedValueOnce(new api_1.ReuniteApiError('Deprecated.', 412));
|
|
284
|
+
fsStatSyncSpy.mockReturnValueOnce({
|
|
285
|
+
isDirectory() {
|
|
286
|
+
return false;
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
pathResolveSpy.mockImplementationOnce((p) => p);
|
|
290
|
+
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
|
291
|
+
pathDirnameSpy.mockImplementation((_) => '.');
|
|
292
|
+
expect((0, push_1.handlePush)({
|
|
293
|
+
argv: {
|
|
294
|
+
domain: 'test-domain',
|
|
295
|
+
'mount-path': 'test-mount-path',
|
|
296
|
+
organization: 'test-org',
|
|
297
|
+
project: 'test-project',
|
|
298
|
+
branch: 'test-branch',
|
|
299
|
+
namespace: 'test-namespace',
|
|
300
|
+
repository: 'test-repository',
|
|
301
|
+
'commit-sha': 'test-commit-sha',
|
|
302
|
+
'commit-url': 'test-commit-url',
|
|
303
|
+
'default-branch': 'test-branch',
|
|
304
|
+
'created-at': 'test-created-at',
|
|
305
|
+
author: 'TestAuthor <test-author@mail.com>',
|
|
306
|
+
message: 'Test message',
|
|
307
|
+
files: ['test-file'],
|
|
308
|
+
'max-execution-time': 10,
|
|
309
|
+
},
|
|
310
|
+
config: mockConfig,
|
|
311
|
+
version: 'cli-version',
|
|
312
|
+
})).rejects.toThrow('✗ File upload failed. Reason: Deprecated.');
|
|
273
313
|
});
|
|
274
314
|
});
|
|
@@ -26,7 +26,7 @@ describe('retryUntilConditionMet()', () => {
|
|
|
26
26
|
condition: (result) => result?.status === 'done',
|
|
27
27
|
retryIntervalMs: 100,
|
|
28
28
|
retryTimeoutMs: 1000,
|
|
29
|
-
})).rejects.toThrow('Timeout exceeded');
|
|
29
|
+
})).rejects.toThrow('Timeout exceeded.');
|
|
30
30
|
});
|
|
31
31
|
it('should call "onConditionNotMet" and "onRetry" callbacks', async () => {
|
|
32
32
|
const operation = jest
|
|
@@ -20,4 +20,4 @@ export interface PushStatusSummary {
|
|
|
20
20
|
production: DeploymentStatusResponse | null;
|
|
21
21
|
commit: PushResponse['commit'];
|
|
22
22
|
}
|
|
23
|
-
export declare function handlePushStatus({ argv, config, }: CommandArgs<PushStatusOptions>): Promise<PushStatusSummary |
|
|
23
|
+
export declare function handlePushStatus({ argv, config, version, }: CommandArgs<PushStatusOptions>): Promise<PushStatusSummary | void>;
|
|
@@ -9,7 +9,7 @@ const api_1 = require("../api");
|
|
|
9
9
|
const js_utils_1 = require("../../utils/js-utils");
|
|
10
10
|
const utils_2 = require("./utils");
|
|
11
11
|
const RETRY_INTERVAL_MS = 5000; // 5 sec
|
|
12
|
-
async function handlePushStatus({ argv, config, }) {
|
|
12
|
+
async function handlePushStatus({ argv, config, version, }) {
|
|
13
13
|
const startedAt = performance.now();
|
|
14
14
|
const spinner = new spinner_1.Spinner();
|
|
15
15
|
const { organization, project: projectId, pushId, wait } = argv;
|
|
@@ -28,7 +28,7 @@ async function handlePushStatus({ argv, config, }) {
|
|
|
28
28
|
const continueOnDeployFailures = argv['continue-on-deploy-failures'] || false;
|
|
29
29
|
try {
|
|
30
30
|
const apiKey = (0, api_1.getApiKeys)(domain);
|
|
31
|
-
const client = new api_1.ReuniteApiClient(domain, apiKey);
|
|
31
|
+
const client = new api_1.ReuniteApiClient({ domain, apiKey, version, command: 'push-status' });
|
|
32
32
|
let pushResponse;
|
|
33
33
|
pushResponse = await (0, utils_2.retryUntilConditionMet)({
|
|
34
34
|
operation: () => client.remotes.getPush({
|
|
@@ -128,11 +128,7 @@ async function handlePushStatus({ argv, config, }) {
|
|
|
128
128
|
}
|
|
129
129
|
catch (err) {
|
|
130
130
|
spinner.stop(); // Spinner can block process exit, so we need to stop it explicitly.
|
|
131
|
-
|
|
132
|
-
? err.message
|
|
133
|
-
: `✗ Failed to get push status. Reason: ${err.message}\n`;
|
|
134
|
-
(0, miscellaneous_1.exitWithError)(message);
|
|
135
|
-
return;
|
|
131
|
+
(0, utils_2.handleReuniteError)('✗ Failed to get push status.', err);
|
|
136
132
|
}
|
|
137
133
|
finally {
|
|
138
134
|
spinner.stop(); // Spinner can block process exit, so we need to stop it explicitly.
|
package/lib/cms/commands/push.js
CHANGED
|
@@ -9,13 +9,14 @@ const colorette_1 = require("colorette");
|
|
|
9
9
|
const miscellaneous_1 = require("../../utils/miscellaneous");
|
|
10
10
|
const push_status_1 = require("./push-status");
|
|
11
11
|
const api_1 = require("../api");
|
|
12
|
+
const utils_2 = require("./utils");
|
|
12
13
|
async function handlePush({ argv, config, version, }) {
|
|
13
14
|
const startedAt = performance.now(); // for printing execution time
|
|
14
15
|
const startTime = Date.now(); // for push-status command
|
|
15
16
|
const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
|
|
16
17
|
const orgId = organization || config.organization;
|
|
17
18
|
if (!argv.message || !argv.author || !argv.branch) {
|
|
18
|
-
(0, miscellaneous_1.exitWithError)('Error: message, author and branch are required for push to the
|
|
19
|
+
(0, miscellaneous_1.exitWithError)('Error: message, author and branch are required for push to the Reunite.');
|
|
19
20
|
}
|
|
20
21
|
if (!orgId) {
|
|
21
22
|
return (0, miscellaneous_1.exitWithError)(`No organization provided, please use --organization option or specify the 'organization' field in the config file.`);
|
|
@@ -32,7 +33,7 @@ async function handlePush({ argv, config, version, }) {
|
|
|
32
33
|
if (!filesToUpload.length) {
|
|
33
34
|
return (0, miscellaneous_1.printExecutionTime)('push', startedAt, `No files to upload`);
|
|
34
35
|
}
|
|
35
|
-
const client = new api_1.ReuniteApiClient(domain, apiKey);
|
|
36
|
+
const client = new api_1.ReuniteApiClient({ domain, apiKey, version, command: 'push' });
|
|
36
37
|
const projectDefaultBranch = await client.remotes.getDefaultBranch(orgId, projectId);
|
|
37
38
|
const remote = await client.remotes.upsert(orgId, projectId, {
|
|
38
39
|
mountBranchName: projectDefaultBranch,
|
|
@@ -82,8 +83,7 @@ async function handlePush({ argv, config, version, }) {
|
|
|
82
83
|
};
|
|
83
84
|
}
|
|
84
85
|
catch (err) {
|
|
85
|
-
|
|
86
|
-
(0, miscellaneous_1.exitWithError)(message);
|
|
86
|
+
(0, utils_2.handleReuniteError)('✗ File upload failed.', err);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
function parseCommitAuthor(author) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DeploymentError } from '../utils';
|
|
2
|
+
import type { ReuniteApiError } from '../api';
|
|
1
3
|
/**
|
|
2
4
|
* This function retries an operation until a condition is met or a timeout is exceeded.
|
|
3
5
|
* If the condition is not met within the timeout, an error is thrown.
|
|
@@ -20,3 +22,4 @@ retryIntervalMs, }: {
|
|
|
20
22
|
retryTimeoutMs?: number;
|
|
21
23
|
retryIntervalMs?: number;
|
|
22
24
|
}): Promise<T>;
|
|
25
|
+
export declare function handleReuniteError(message: string, error: ReuniteApiError | DeploymentError | Error): void;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.retryUntilConditionMet = retryUntilConditionMet;
|
|
4
|
+
exports.handleReuniteError = handleReuniteError;
|
|
4
5
|
const openapi_core_1 = require("@redocly/openapi-core");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
const miscellaneous_1 = require("../../utils/miscellaneous");
|
|
5
8
|
/**
|
|
6
9
|
* This function retries an operation until a condition is met or a timeout is exceeded.
|
|
7
10
|
* If the condition is not met within the timeout, an error is thrown.
|
|
@@ -26,7 +29,7 @@ retryIntervalMs = 5000, // 5 sec
|
|
|
26
29
|
return result;
|
|
27
30
|
}
|
|
28
31
|
else if (Date.now() - startTime > retryTimeoutMs) {
|
|
29
|
-
throw new Error('Timeout exceeded');
|
|
32
|
+
throw new Error('Timeout exceeded.');
|
|
30
33
|
}
|
|
31
34
|
else {
|
|
32
35
|
onConditionNotMet?.(result);
|
|
@@ -37,3 +40,7 @@ retryIntervalMs = 5000, // 5 sec
|
|
|
37
40
|
}
|
|
38
41
|
return attempt();
|
|
39
42
|
}
|
|
43
|
+
function handleReuniteError(message, error) {
|
|
44
|
+
const errorMessage = error instanceof utils_1.DeploymentError ? error.message : `${message} Reason: ${error.message}\n`;
|
|
45
|
+
return (0, miscellaneous_1.exitWithError)(errorMessage);
|
|
46
|
+
}
|
package/lib/commands/bundle.d.ts
CHANGED
package/lib/commands/bundle.js
CHANGED
|
@@ -13,7 +13,7 @@ async function handleBundle({ argv, config, version, collectSpecData, }) {
|
|
|
13
13
|
const totals = { errors: 0, warnings: 0, ignored: 0 };
|
|
14
14
|
const deprecatedOptions = [];
|
|
15
15
|
(0, miscellaneous_1.checkForDeprecatedOptions)(argv, deprecatedOptions);
|
|
16
|
-
for (const { path, alias } of apis) {
|
|
16
|
+
for (const { path, alias, output } of apis) {
|
|
17
17
|
try {
|
|
18
18
|
const startedAt = perf_hooks_1.performance.now();
|
|
19
19
|
const resolvedConfig = (0, openapi_core_1.getMergedConfig)(config, alias);
|
|
@@ -30,15 +30,15 @@ async function handleBundle({ argv, config, version, collectSpecData, }) {
|
|
|
30
30
|
collectSpecData,
|
|
31
31
|
});
|
|
32
32
|
const fileTotals = (0, openapi_core_1.getTotals)(problems);
|
|
33
|
-
const { outputFile, ext } = (0, miscellaneous_1.getOutputFileName)(path,
|
|
33
|
+
const { outputFile, ext } = (0, miscellaneous_1.getOutputFileName)(path, output || argv.output, argv.ext);
|
|
34
34
|
if (fileTotals.errors === 0 || argv.force) {
|
|
35
|
-
if (!
|
|
36
|
-
const
|
|
37
|
-
process.stdout.write(
|
|
35
|
+
if (!outputFile) {
|
|
36
|
+
const bundled = (0, miscellaneous_1.dumpBundle)((0, miscellaneous_1.sortTopLevelKeysForOas)(result.parsed), argv.ext || 'yaml', argv.dereferenced);
|
|
37
|
+
process.stdout.write(bundled);
|
|
38
38
|
}
|
|
39
39
|
else {
|
|
40
|
-
const
|
|
41
|
-
(0, miscellaneous_1.saveBundle)(outputFile,
|
|
40
|
+
const bundled = (0, miscellaneous_1.dumpBundle)((0, miscellaneous_1.sortTopLevelKeysForOas)(result.parsed), ext, argv.dereferenced);
|
|
41
|
+
(0, miscellaneous_1.saveBundle)(outputFile, bundled);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
totals.errors += fileTotals.errors;
|
|
@@ -60,14 +60,14 @@ async function handleBundle({ argv, config, version, collectSpecData, }) {
|
|
|
60
60
|
const elapsed = (0, miscellaneous_1.getExecutionTime)(startedAt);
|
|
61
61
|
if (fileTotals.errors > 0) {
|
|
62
62
|
if (argv.force) {
|
|
63
|
-
process.stderr.write(`❓ Created a bundle for ${(0, colorette_1.blue)(path)} at ${(0, colorette_1.blue)(outputFile)} with errors ${(0, colorette_1.green)(elapsed)}.\n${(0, colorette_1.yellow)('Errors ignored because of --force')}.\n`);
|
|
63
|
+
process.stderr.write(`❓ Created a bundle for ${(0, colorette_1.blue)(path)} at ${(0, colorette_1.blue)(outputFile || 'stdout')} with errors ${(0, colorette_1.green)(elapsed)}.\n${(0, colorette_1.yellow)('Errors ignored because of --force')}.\n`);
|
|
64
64
|
}
|
|
65
65
|
else {
|
|
66
66
|
process.stderr.write(`❌ Errors encountered while bundling ${(0, colorette_1.blue)(path)}: bundle not created (use --force to ignore errors).\n`);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
else {
|
|
70
|
-
process.stderr.write(`📦 Created a bundle for ${(0, colorette_1.blue)(path)} at ${(0, colorette_1.blue)(outputFile)} ${(0, colorette_1.green)(elapsed)}.\n`);
|
|
70
|
+
process.stderr.write(`📦 Created a bundle for ${(0, colorette_1.blue)(path)} at ${(0, colorette_1.blue)(outputFile || 'stdout')} ${(0, colorette_1.green)(elapsed)}.\n`);
|
|
71
71
|
}
|
|
72
72
|
const removedCount = meta.visitorsData?.['remove-unused-components']?.removedCount;
|
|
73
73
|
if (removedCount) {
|
package/lib/commands/eject.d.ts
CHANGED
package/lib/commands/eject.js
CHANGED
|
@@ -17,7 +17,7 @@ const previewProject = async ({ argv }) => {
|
|
|
17
17
|
const packageName = constants_1.PRODUCT_PACKAGES[product];
|
|
18
18
|
process.stdout.write(`\nLaunching preview of ${productName} ${plan} using NPX.\n\n`);
|
|
19
19
|
const npxExecutableName = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
20
|
-
(0, child_process_1.spawn)(npxExecutableName, ['-y', packageName, '
|
|
20
|
+
(0, child_process_1.spawn)(npxExecutableName, ['-y', packageName, 'preview', `--plan=${plan}`, `--port=${port || 4000}`], {
|
|
21
21
|
stdio: 'inherit',
|
|
22
22
|
cwd: projectDir,
|
|
23
23
|
});
|
package/lib/index.js
CHANGED
|
@@ -688,7 +688,7 @@ yargs
|
|
|
688
688
|
process.env.REDOCLY_CLI_COMMAND = 'translate';
|
|
689
689
|
(0, wrapper_1.commandWrapper)(translations_1.handleTranslations)(argv);
|
|
690
690
|
})
|
|
691
|
-
.command('eject <type>
|
|
691
|
+
.command('eject <type> [path]', 'Helper function to eject project elements for customization.', (yargs) => yargs
|
|
692
692
|
.positional('type', {
|
|
693
693
|
description: 'Specifies what type of project element to eject. Currently, it could be only `component`.',
|
|
694
694
|
demandOption: true,
|
|
@@ -697,7 +697,6 @@ yargs
|
|
|
697
697
|
.positional('path', {
|
|
698
698
|
description: 'Filepath to a component or filepath with glob pattern.',
|
|
699
699
|
type: 'string',
|
|
700
|
-
demandOption: true,
|
|
701
700
|
})
|
|
702
701
|
.options({
|
|
703
702
|
'project-dir': {
|
package/lib/types.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export type Totals = {
|
|
|
22
22
|
export type Entrypoint = {
|
|
23
23
|
path: string;
|
|
24
24
|
alias?: string;
|
|
25
|
+
output?: string;
|
|
25
26
|
};
|
|
26
27
|
export declare const outputExtensions: ReadonlyArray<BundleOutputFormat>;
|
|
27
28
|
export type OutputExtensions = 'json' | 'yaml' | 'yml' | undefined;
|
|
@@ -39,3 +39,4 @@ export declare const sortTopLevelKeysForOas: jest.Mock<any, [document: any]>;
|
|
|
39
39
|
export declare const getAndValidateFileExtension: jest.Mock<string | undefined, [fileName: string]>;
|
|
40
40
|
export declare const writeToFileByExtension: jest.Mock<any, any>;
|
|
41
41
|
export declare const checkForDeprecatedOptions: jest.Mock<any, any>;
|
|
42
|
+
export declare const saveBundle: jest.Mock<any, any>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkForDeprecatedOptions = exports.writeToFileByExtension = exports.getAndValidateFileExtension = exports.sortTopLevelKeysForOas = exports.checkIfRulesetExist = exports.loadConfigAndHandleErrors = exports.writeYaml = exports.exitWithError = exports.handleError = exports.getOutputFileName = exports.printLintTotals = exports.printUnusedWarnings = exports.printExecutionTime = exports.getExecutionTime = exports.pluralize = exports.slash = exports.dumpBundle = exports.getFallbackApisOrExit = void 0;
|
|
3
|
+
exports.saveBundle = exports.checkForDeprecatedOptions = exports.writeToFileByExtension = exports.getAndValidateFileExtension = exports.sortTopLevelKeysForOas = exports.checkIfRulesetExist = exports.loadConfigAndHandleErrors = exports.writeYaml = exports.exitWithError = exports.handleError = exports.getOutputFileName = exports.printLintTotals = exports.printUnusedWarnings = exports.printExecutionTime = exports.getExecutionTime = exports.pluralize = exports.slash = exports.dumpBundle = exports.getFallbackApisOrExit = void 0;
|
|
4
4
|
const config_1 = require("../../__tests__/fixtures/config");
|
|
5
5
|
exports.getFallbackApisOrExit = jest.fn((entrypoints) => entrypoints.map((path) => ({ path })));
|
|
6
6
|
exports.dumpBundle = jest.fn(() => '');
|
|
@@ -20,3 +20,4 @@ exports.sortTopLevelKeysForOas = jest.fn((document) => document);
|
|
|
20
20
|
exports.getAndValidateFileExtension = jest.fn((fileName) => fileName.split('.').pop());
|
|
21
21
|
exports.writeToFileByExtension = jest.fn();
|
|
22
22
|
exports.checkForDeprecatedOptions = jest.fn();
|
|
23
|
+
exports.saveBundle = jest.fn();
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { type RequestInit } from 'node-fetch';
|
|
2
|
+
export declare const DEFAULT_FETCH_TIMEOUT = 3000;
|
|
3
|
+
export type FetchWithTimeoutOptions = RequestInit & {
|
|
4
|
+
timeout?: number;
|
|
5
|
+
};
|
|
6
|
+
declare const _default: (url: string, { timeout, ...options }?: FetchWithTimeoutOptions) => Promise<import("node-fetch").Response>;
|
|
2
7
|
export default _default;
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_FETCH_TIMEOUT = void 0;
|
|
3
4
|
const node_fetch_1 = require("node-fetch");
|
|
4
5
|
const abort_controller_1 = require("abort-controller");
|
|
5
6
|
const openapi_core_1 = require("@redocly/openapi-core");
|
|
6
|
-
|
|
7
|
-
exports.default = async (url, options = {}) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const timeout = setTimeout(() => {
|
|
11
|
-
controller.abort();
|
|
12
|
-
}, TIMEOUT);
|
|
13
|
-
const res = await (0, node_fetch_1.default)(url, {
|
|
14
|
-
signal: controller.signal,
|
|
7
|
+
exports.DEFAULT_FETCH_TIMEOUT = 3000;
|
|
8
|
+
exports.default = async (url, { timeout, ...options } = {}) => {
|
|
9
|
+
if (!timeout) {
|
|
10
|
+
return (0, node_fetch_1.default)(url, {
|
|
15
11
|
...options,
|
|
16
12
|
agent: (0, openapi_core_1.getProxyAgent)(),
|
|
17
13
|
});
|
|
18
|
-
clearTimeout(timeout);
|
|
19
|
-
return res;
|
|
20
|
-
}
|
|
21
|
-
catch (e) {
|
|
22
|
-
return;
|
|
23
14
|
}
|
|
15
|
+
const controller = new abort_controller_1.default();
|
|
16
|
+
const timeoutId = setTimeout(() => {
|
|
17
|
+
controller.abort();
|
|
18
|
+
}, timeout);
|
|
19
|
+
const res = await (0, node_fetch_1.default)(url, {
|
|
20
|
+
signal: controller.signal,
|
|
21
|
+
...options,
|
|
22
|
+
agent: (0, openapi_core_1.getProxyAgent)(),
|
|
23
|
+
});
|
|
24
|
+
clearTimeout(timeoutId);
|
|
25
|
+
return res;
|
|
24
26
|
};
|
|
@@ -25,7 +25,10 @@ export declare class HandledError extends Error {
|
|
|
25
25
|
}
|
|
26
26
|
export declare function printLintTotals(totals: Totals, definitionsCount: number): void;
|
|
27
27
|
export declare function printConfigLintTotals(totals: Totals, command?: string | number): void;
|
|
28
|
-
export declare function getOutputFileName(entrypoint: string,
|
|
28
|
+
export declare function getOutputFileName(entrypoint: string, output?: string, ext?: BundleOutputFormat): {
|
|
29
|
+
ext: BundleOutputFormat;
|
|
30
|
+
outputFile?: undefined;
|
|
31
|
+
} | {
|
|
29
32
|
outputFile: string;
|
|
30
33
|
ext: BundleOutputFormat;
|
|
31
34
|
};
|