@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
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { handlePushStatus } from '../push-status';
|
|
2
2
|
import { PushResponse } from '../../api/types';
|
|
3
|
-
import { exitWithError } from '../../../utils/miscellaneous';
|
|
4
3
|
|
|
5
4
|
const remotes = {
|
|
6
5
|
getPush: jest.fn(),
|
|
7
6
|
getRemotesList: jest.fn(),
|
|
8
7
|
};
|
|
9
8
|
|
|
10
|
-
jest.mock('../../../utils/miscellaneous');
|
|
11
|
-
|
|
12
9
|
jest.mock('colorette', () => ({
|
|
13
10
|
green: (str: string) => str,
|
|
14
11
|
yellow: (str: string) => str,
|
|
@@ -25,28 +22,57 @@ jest.mock('../../api', () => ({
|
|
|
25
22
|
}),
|
|
26
23
|
}));
|
|
27
24
|
|
|
25
|
+
jest.mock('@redocly/openapi-core', () => ({
|
|
26
|
+
pause: jest.requireActual('@redocly/openapi-core').pause,
|
|
27
|
+
}));
|
|
28
|
+
|
|
28
29
|
describe('handlePushStatus()', () => {
|
|
29
30
|
const mockConfig = { apis: {} } as any;
|
|
30
31
|
|
|
31
|
-
const
|
|
32
|
+
const commitStub: PushResponse['commit'] = {
|
|
33
|
+
message: 'test-commit-message',
|
|
34
|
+
branchName: 'test-branch-name',
|
|
35
|
+
sha: null,
|
|
36
|
+
url: null,
|
|
37
|
+
createdAt: null,
|
|
38
|
+
namespaceId: null,
|
|
39
|
+
repositoryId: null,
|
|
40
|
+
author: {
|
|
41
|
+
name: 'test-author-name',
|
|
42
|
+
email: 'test-author-email',
|
|
43
|
+
image: null,
|
|
44
|
+
},
|
|
45
|
+
statuses: [],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const pushResponseStub: PushResponse = {
|
|
49
|
+
id: 'test-push-id',
|
|
50
|
+
remoteId: 'test-remote-id',
|
|
51
|
+
replace: false,
|
|
52
|
+
scoutJobId: null,
|
|
53
|
+
uploadedFiles: [],
|
|
54
|
+
commit: commitStub,
|
|
55
|
+
remote: { commits: [] },
|
|
56
|
+
isOutdated: false,
|
|
57
|
+
isMainBranch: false,
|
|
32
58
|
hasChanges: true,
|
|
33
59
|
status: {
|
|
34
60
|
preview: {
|
|
35
61
|
scorecard: [],
|
|
36
62
|
deploy: {
|
|
37
|
-
url: 'https://test-url',
|
|
63
|
+
url: 'https://preview-test-url',
|
|
38
64
|
status: 'success',
|
|
39
65
|
},
|
|
40
66
|
},
|
|
41
67
|
production: {
|
|
42
68
|
scorecard: [],
|
|
43
69
|
deploy: {
|
|
44
|
-
url: 'https://test-url',
|
|
70
|
+
url: 'https://production-test-url',
|
|
45
71
|
status: 'success',
|
|
46
72
|
},
|
|
47
73
|
},
|
|
48
74
|
},
|
|
49
|
-
}
|
|
75
|
+
};
|
|
50
76
|
|
|
51
77
|
beforeEach(() => {
|
|
52
78
|
jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
|
@@ -58,23 +84,27 @@ describe('handlePushStatus()', () => {
|
|
|
58
84
|
});
|
|
59
85
|
|
|
60
86
|
it('should throw error if organization not provided', async () => {
|
|
61
|
-
await
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
87
|
+
await expect(
|
|
88
|
+
handlePushStatus(
|
|
89
|
+
{
|
|
90
|
+
domain: 'test-domain',
|
|
91
|
+
organization: '',
|
|
92
|
+
project: 'test-project',
|
|
93
|
+
pushId: 'test-push-id',
|
|
94
|
+
},
|
|
95
|
+
mockConfig
|
|
96
|
+
)
|
|
97
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
98
|
+
`"No organization provided, please use --organization option or specify the 'organization' field in the config file."`
|
|
70
99
|
);
|
|
71
100
|
|
|
72
|
-
expect(
|
|
73
|
-
|
|
101
|
+
expect(process.stderr.write).toHaveBeenCalledWith(
|
|
102
|
+
`No organization provided, please use --organization option or specify the 'organization' field in the config file.` +
|
|
103
|
+
'\n\n'
|
|
74
104
|
);
|
|
75
105
|
});
|
|
76
106
|
|
|
77
|
-
it('should
|
|
107
|
+
it('should print success push status for preview-build', async () => {
|
|
78
108
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
79
109
|
remotes.getPush.mockResolvedValueOnce(pushResponseStub);
|
|
80
110
|
|
|
@@ -84,17 +114,16 @@ describe('handlePushStatus()', () => {
|
|
|
84
114
|
organization: 'test-org',
|
|
85
115
|
project: 'test-project',
|
|
86
116
|
pushId: 'test-push-id',
|
|
87
|
-
'max-execution-time': 1000,
|
|
88
117
|
},
|
|
89
118
|
mockConfig
|
|
90
119
|
);
|
|
91
120
|
expect(process.stdout.write).toHaveBeenCalledTimes(1);
|
|
92
121
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
|
93
|
-
'🚀 Preview deploy success.\nPreview URL: https://test-url\n'
|
|
122
|
+
'🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
|
|
94
123
|
);
|
|
95
124
|
});
|
|
96
125
|
|
|
97
|
-
it('should
|
|
126
|
+
it('should print success push status for preview and production builds', async () => {
|
|
98
127
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
99
128
|
remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: true });
|
|
100
129
|
|
|
@@ -104,46 +133,50 @@ describe('handlePushStatus()', () => {
|
|
|
104
133
|
organization: 'test-org',
|
|
105
134
|
project: 'test-project',
|
|
106
135
|
pushId: 'test-push-id',
|
|
107
|
-
'max-execution-time': 1000,
|
|
108
136
|
},
|
|
109
137
|
mockConfig
|
|
110
138
|
);
|
|
111
139
|
expect(process.stdout.write).toHaveBeenCalledTimes(2);
|
|
112
140
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
|
113
|
-
'🚀 Preview deploy success.\nPreview URL: https://test-url\n'
|
|
141
|
+
'🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
|
|
114
142
|
);
|
|
115
143
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
|
116
|
-
'🚀 Production deploy success.\nProduction URL: https://test-url\n'
|
|
144
|
+
'🚀 Production deploy success.\nProduction URL: https://production-test-url\n'
|
|
117
145
|
);
|
|
118
146
|
});
|
|
119
147
|
|
|
120
|
-
it('should
|
|
148
|
+
it('should print failed push status for preview build', async () => {
|
|
121
149
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
122
150
|
|
|
123
151
|
remotes.getPush.mockResolvedValue({
|
|
124
152
|
isOutdated: false,
|
|
125
153
|
hasChanges: true,
|
|
126
154
|
status: {
|
|
127
|
-
preview: { deploy: { status: 'failed', url: 'https://test-url' }, scorecard: [] },
|
|
155
|
+
preview: { deploy: { status: 'failed', url: 'https://preview-test-url' }, scorecard: [] },
|
|
128
156
|
},
|
|
129
157
|
});
|
|
130
158
|
|
|
131
|
-
await
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
159
|
+
await expect(
|
|
160
|
+
handlePushStatus(
|
|
161
|
+
{
|
|
162
|
+
domain: 'test-domain',
|
|
163
|
+
organization: 'test-org',
|
|
164
|
+
project: 'test-project',
|
|
165
|
+
pushId: 'test-push-id',
|
|
166
|
+
},
|
|
167
|
+
mockConfig
|
|
168
|
+
)
|
|
169
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
|
170
|
+
"❌ Preview deploy fail.
|
|
171
|
+
Preview URL: https://preview-test-url"
|
|
172
|
+
`);
|
|
173
|
+
|
|
174
|
+
expect(process.stderr.write).toHaveBeenCalledWith(
|
|
175
|
+
'❌ Preview deploy fail.\nPreview URL: https://preview-test-url' + '\n\n'
|
|
143
176
|
);
|
|
144
177
|
});
|
|
145
178
|
|
|
146
|
-
it('should
|
|
179
|
+
it('should print success push status for preview build and print scorecards', async () => {
|
|
147
180
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
148
181
|
|
|
149
182
|
remotes.getPush.mockResolvedValue({
|
|
@@ -151,7 +184,7 @@ describe('handlePushStatus()', () => {
|
|
|
151
184
|
hasChanges: true,
|
|
152
185
|
status: {
|
|
153
186
|
preview: {
|
|
154
|
-
deploy: { status: 'success', url: 'https://test-url' },
|
|
187
|
+
deploy: { status: 'success', url: 'https://preview-test-url' },
|
|
155
188
|
scorecard: [
|
|
156
189
|
{
|
|
157
190
|
name: 'test-name',
|
|
@@ -170,13 +203,12 @@ describe('handlePushStatus()', () => {
|
|
|
170
203
|
organization: 'test-org',
|
|
171
204
|
project: 'test-project',
|
|
172
205
|
pushId: 'test-push-id',
|
|
173
|
-
'max-execution-time': 1000,
|
|
174
206
|
},
|
|
175
207
|
mockConfig
|
|
176
208
|
);
|
|
177
209
|
expect(process.stdout.write).toHaveBeenCalledTimes(4);
|
|
178
210
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
|
179
|
-
'🚀 Preview deploy success.\nPreview URL: https://test-url\n'
|
|
211
|
+
'🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n'
|
|
180
212
|
);
|
|
181
213
|
expect(process.stdout.write).toHaveBeenCalledWith('\nScorecard:');
|
|
182
214
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
|
@@ -185,14 +217,18 @@ describe('handlePushStatus()', () => {
|
|
|
185
217
|
expect(process.stdout.write).toHaveBeenCalledWith('\n');
|
|
186
218
|
});
|
|
187
219
|
|
|
188
|
-
it('should
|
|
220
|
+
it('should print message if there is no changes', async () => {
|
|
189
221
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
190
222
|
|
|
191
223
|
remotes.getPush.mockResolvedValueOnce({
|
|
192
224
|
isOutdated: false,
|
|
193
225
|
hasChanges: false,
|
|
194
226
|
status: {
|
|
195
|
-
preview: { deploy: { status: 'skipped', url: 'https://test-url' }, scorecard: [] },
|
|
227
|
+
preview: { deploy: { status: 'skipped', url: 'https://preview-test-url' }, scorecard: [] },
|
|
228
|
+
production: {
|
|
229
|
+
deploy: { status: 'skipped', url: null },
|
|
230
|
+
scorecard: [],
|
|
231
|
+
},
|
|
196
232
|
},
|
|
197
233
|
});
|
|
198
234
|
|
|
@@ -203,10 +239,400 @@ describe('handlePushStatus()', () => {
|
|
|
203
239
|
project: 'test-project',
|
|
204
240
|
pushId: 'test-push-id',
|
|
205
241
|
wait: true,
|
|
206
|
-
'max-execution-time': 1000,
|
|
207
242
|
},
|
|
208
243
|
mockConfig
|
|
209
244
|
);
|
|
210
|
-
|
|
245
|
+
|
|
246
|
+
expect(process.stderr.write).toHaveBeenCalledWith(
|
|
247
|
+
'Files not added to your project. Reason: no changes.\n'
|
|
248
|
+
);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('return value', () => {
|
|
252
|
+
it('should return preview deployment info', async () => {
|
|
253
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
254
|
+
remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: false });
|
|
255
|
+
|
|
256
|
+
const result = await handlePushStatus(
|
|
257
|
+
{
|
|
258
|
+
domain: 'test-domain',
|
|
259
|
+
organization: 'test-org',
|
|
260
|
+
project: 'test-project',
|
|
261
|
+
pushId: 'test-push-id',
|
|
262
|
+
},
|
|
263
|
+
mockConfig
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
expect(result).toEqual({
|
|
267
|
+
preview: {
|
|
268
|
+
deploy: {
|
|
269
|
+
status: 'success',
|
|
270
|
+
url: 'https://preview-test-url',
|
|
271
|
+
},
|
|
272
|
+
scorecard: [],
|
|
273
|
+
},
|
|
274
|
+
production: null,
|
|
275
|
+
commit: commitStub,
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('should return preview and production deployment info', async () => {
|
|
280
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
281
|
+
remotes.getPush.mockResolvedValue({ ...pushResponseStub, isMainBranch: true });
|
|
282
|
+
|
|
283
|
+
const result = await handlePushStatus(
|
|
284
|
+
{
|
|
285
|
+
domain: 'test-domain',
|
|
286
|
+
organization: 'test-org',
|
|
287
|
+
project: 'test-project',
|
|
288
|
+
pushId: 'test-push-id',
|
|
289
|
+
},
|
|
290
|
+
mockConfig
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
expect(result).toEqual({
|
|
294
|
+
preview: {
|
|
295
|
+
deploy: {
|
|
296
|
+
status: 'success',
|
|
297
|
+
url: 'https://preview-test-url',
|
|
298
|
+
},
|
|
299
|
+
scorecard: [],
|
|
300
|
+
},
|
|
301
|
+
production: {
|
|
302
|
+
deploy: {
|
|
303
|
+
status: 'success',
|
|
304
|
+
url: 'https://production-test-url',
|
|
305
|
+
},
|
|
306
|
+
scorecard: [],
|
|
307
|
+
},
|
|
308
|
+
commit: commitStub,
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe('"wait" option', () => {
|
|
314
|
+
it('should wait for preview "success" deployment status', async () => {
|
|
315
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
316
|
+
|
|
317
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
318
|
+
...pushResponseStub,
|
|
319
|
+
status: {
|
|
320
|
+
preview: {
|
|
321
|
+
deploy: { status: 'pending', url: 'https://preview-test-url' },
|
|
322
|
+
scorecard: [],
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
328
|
+
...pushResponseStub,
|
|
329
|
+
status: {
|
|
330
|
+
preview: {
|
|
331
|
+
deploy: { status: 'running', url: 'https://preview-test-url' },
|
|
332
|
+
scorecard: [],
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
338
|
+
...pushResponseStub,
|
|
339
|
+
status: {
|
|
340
|
+
preview: {
|
|
341
|
+
deploy: { status: 'success', url: 'https://preview-test-url' },
|
|
342
|
+
scorecard: [],
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
const result = await handlePushStatus(
|
|
348
|
+
{
|
|
349
|
+
domain: 'test-domain',
|
|
350
|
+
organization: 'test-org',
|
|
351
|
+
project: 'test-project',
|
|
352
|
+
pushId: 'test-push-id',
|
|
353
|
+
'retry-interval': 0.5, // 500 ms
|
|
354
|
+
wait: true,
|
|
355
|
+
},
|
|
356
|
+
mockConfig
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
expect(result).toEqual({
|
|
360
|
+
preview: {
|
|
361
|
+
deploy: {
|
|
362
|
+
status: 'success',
|
|
363
|
+
url: 'https://preview-test-url',
|
|
364
|
+
},
|
|
365
|
+
scorecard: [],
|
|
366
|
+
},
|
|
367
|
+
production: null,
|
|
368
|
+
commit: commitStub,
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('should wait for production "success" status after preview "success" status', async () => {
|
|
373
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
374
|
+
|
|
375
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
376
|
+
...pushResponseStub,
|
|
377
|
+
isMainBranch: true,
|
|
378
|
+
status: {
|
|
379
|
+
preview: {
|
|
380
|
+
deploy: { status: 'success', url: 'https://preview-test-url' },
|
|
381
|
+
scorecard: [],
|
|
382
|
+
},
|
|
383
|
+
production: {
|
|
384
|
+
deploy: { status: 'pending', url: 'https://production-test-url' },
|
|
385
|
+
scorecard: [],
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
391
|
+
...pushResponseStub,
|
|
392
|
+
isMainBranch: true,
|
|
393
|
+
status: {
|
|
394
|
+
preview: {
|
|
395
|
+
deploy: { status: 'success', url: 'https://preview-test-url' },
|
|
396
|
+
scorecard: [],
|
|
397
|
+
},
|
|
398
|
+
production: {
|
|
399
|
+
deploy: { status: 'running', url: 'https://production-test-url' },
|
|
400
|
+
scorecard: [],
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
406
|
+
...pushResponseStub,
|
|
407
|
+
isMainBranch: true,
|
|
408
|
+
status: {
|
|
409
|
+
preview: {
|
|
410
|
+
deploy: { status: 'success', url: 'https://preview-test-url' },
|
|
411
|
+
scorecard: [],
|
|
412
|
+
},
|
|
413
|
+
production: {
|
|
414
|
+
deploy: { status: 'success', url: 'https://production-test-url' },
|
|
415
|
+
scorecard: [],
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
const result = await handlePushStatus(
|
|
421
|
+
{
|
|
422
|
+
domain: 'test-domain',
|
|
423
|
+
organization: 'test-org',
|
|
424
|
+
project: 'test-project',
|
|
425
|
+
pushId: 'test-push-id',
|
|
426
|
+
'retry-interval': 0.5, // 500 ms
|
|
427
|
+
wait: true,
|
|
428
|
+
},
|
|
429
|
+
mockConfig
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
expect(result).toEqual({
|
|
433
|
+
preview: {
|
|
434
|
+
deploy: { status: 'success', url: 'https://preview-test-url' },
|
|
435
|
+
scorecard: [],
|
|
436
|
+
},
|
|
437
|
+
production: {
|
|
438
|
+
deploy: { status: 'success', url: 'https://production-test-url' },
|
|
439
|
+
scorecard: [],
|
|
440
|
+
},
|
|
441
|
+
commit: commitStub,
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
describe('"continue-on-deploy-failures" option', () => {
|
|
447
|
+
it('should throw error if option value is false', async () => {
|
|
448
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
449
|
+
|
|
450
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
451
|
+
...pushResponseStub,
|
|
452
|
+
status: {
|
|
453
|
+
preview: {
|
|
454
|
+
deploy: { status: 'failed', url: 'https://preview-test-url' },
|
|
455
|
+
scorecard: [],
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
await expect(
|
|
461
|
+
handlePushStatus(
|
|
462
|
+
{
|
|
463
|
+
domain: 'test-domain',
|
|
464
|
+
organization: 'test-org',
|
|
465
|
+
project: 'test-project',
|
|
466
|
+
pushId: 'test-push-id',
|
|
467
|
+
'continue-on-deploy-failures': false,
|
|
468
|
+
},
|
|
469
|
+
mockConfig
|
|
470
|
+
)
|
|
471
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
|
472
|
+
"❌ Preview deploy fail.
|
|
473
|
+
Preview URL: https://preview-test-url"
|
|
474
|
+
`);
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
it('should not throw error if option value is true', async () => {
|
|
478
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
479
|
+
|
|
480
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
481
|
+
...pushResponseStub,
|
|
482
|
+
status: {
|
|
483
|
+
preview: {
|
|
484
|
+
deploy: { status: 'failed', url: 'https://preview-test-url' },
|
|
485
|
+
scorecard: [],
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
await expect(
|
|
491
|
+
handlePushStatus(
|
|
492
|
+
{
|
|
493
|
+
domain: 'test-domain',
|
|
494
|
+
organization: 'test-org',
|
|
495
|
+
project: 'test-project',
|
|
496
|
+
pushId: 'test-push-id',
|
|
497
|
+
'continue-on-deploy-failures': true,
|
|
498
|
+
},
|
|
499
|
+
mockConfig
|
|
500
|
+
)
|
|
501
|
+
).resolves.toStrictEqual({
|
|
502
|
+
preview: {
|
|
503
|
+
deploy: { status: 'failed', url: 'https://preview-test-url' },
|
|
504
|
+
scorecard: [],
|
|
505
|
+
},
|
|
506
|
+
production: null,
|
|
507
|
+
commit: commitStub,
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
describe('"onRetry" callback', () => {
|
|
513
|
+
it('should be called when command retries request to API in wait mode for preview deploy', async () => {
|
|
514
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
515
|
+
|
|
516
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
517
|
+
...pushResponseStub,
|
|
518
|
+
status: {
|
|
519
|
+
preview: {
|
|
520
|
+
deploy: { status: 'pending', url: 'https://preview-test-url' },
|
|
521
|
+
scorecard: [],
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
527
|
+
...pushResponseStub,
|
|
528
|
+
status: {
|
|
529
|
+
preview: {
|
|
530
|
+
deploy: { status: 'running', url: 'https://preview-test-url' },
|
|
531
|
+
scorecard: [],
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
remotes.getPush.mockResolvedValueOnce({
|
|
537
|
+
...pushResponseStub,
|
|
538
|
+
status: {
|
|
539
|
+
preview: {
|
|
540
|
+
deploy: { status: 'success', url: 'https://preview-test-url' },
|
|
541
|
+
scorecard: [],
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
const onRetrySpy = jest.fn();
|
|
547
|
+
|
|
548
|
+
const result = await handlePushStatus(
|
|
549
|
+
{
|
|
550
|
+
domain: 'test-domain',
|
|
551
|
+
organization: 'test-org',
|
|
552
|
+
project: 'test-project',
|
|
553
|
+
pushId: 'test-push-id',
|
|
554
|
+
wait: true,
|
|
555
|
+
'retry-interval': 0.5, // 500 ms
|
|
556
|
+
onRetry: onRetrySpy,
|
|
557
|
+
},
|
|
558
|
+
mockConfig
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
expect(onRetrySpy).toBeCalledTimes(2);
|
|
562
|
+
|
|
563
|
+
// first retry
|
|
564
|
+
expect(onRetrySpy).toHaveBeenNthCalledWith(1, {
|
|
565
|
+
preview: {
|
|
566
|
+
deploy: {
|
|
567
|
+
status: 'pending',
|
|
568
|
+
url: 'https://preview-test-url',
|
|
569
|
+
},
|
|
570
|
+
scorecard: [],
|
|
571
|
+
},
|
|
572
|
+
production: null,
|
|
573
|
+
commit: commitStub,
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
// second retry
|
|
577
|
+
expect(onRetrySpy).toHaveBeenNthCalledWith(2, {
|
|
578
|
+
preview: {
|
|
579
|
+
deploy: {
|
|
580
|
+
status: 'running',
|
|
581
|
+
url: 'https://preview-test-url',
|
|
582
|
+
},
|
|
583
|
+
scorecard: [],
|
|
584
|
+
},
|
|
585
|
+
production: null,
|
|
586
|
+
commit: commitStub,
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// final result
|
|
590
|
+
expect(result).toEqual({
|
|
591
|
+
preview: {
|
|
592
|
+
deploy: {
|
|
593
|
+
status: 'success',
|
|
594
|
+
url: 'https://preview-test-url',
|
|
595
|
+
},
|
|
596
|
+
scorecard: [],
|
|
597
|
+
},
|
|
598
|
+
production: null,
|
|
599
|
+
commit: commitStub,
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
describe('"max-execution-time" option', () => {
|
|
605
|
+
it('should throw error in case "max-execution-time" was exceeded', async () => {
|
|
606
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
607
|
+
|
|
608
|
+
// Stuck deployment simulation
|
|
609
|
+
remotes.getPush.mockResolvedValue({
|
|
610
|
+
...pushResponseStub,
|
|
611
|
+
status: {
|
|
612
|
+
preview: {
|
|
613
|
+
deploy: { status: 'pending', url: 'https://preview-test-url' },
|
|
614
|
+
scorecard: [],
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
await expect(
|
|
620
|
+
handlePushStatus(
|
|
621
|
+
{
|
|
622
|
+
domain: 'test-domain',
|
|
623
|
+
organization: 'test-org',
|
|
624
|
+
project: 'test-project',
|
|
625
|
+
pushId: 'test-push-id',
|
|
626
|
+
'retry-interval': 2, // seconds
|
|
627
|
+
'max-execution-time': 1, // seconds
|
|
628
|
+
wait: true,
|
|
629
|
+
},
|
|
630
|
+
mockConfig
|
|
631
|
+
)
|
|
632
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
|
633
|
+
"✗ Failed to get push status. Reason: Timeout exceeded
|
|
634
|
+
"
|
|
635
|
+
`);
|
|
636
|
+
});
|
|
211
637
|
});
|
|
212
638
|
});
|
|
@@ -29,8 +29,8 @@ describe('handlePush()', () => {
|
|
|
29
29
|
|
|
30
30
|
beforeEach(() => {
|
|
31
31
|
remotes.getDefaultBranch.mockResolvedValueOnce('test-default-branch');
|
|
32
|
-
remotes.upsert.mockResolvedValueOnce({ id: 'test-remote-id' });
|
|
33
|
-
remotes.push.mockResolvedValueOnce({ branchName: 'uploaded-to-branch' });
|
|
32
|
+
remotes.upsert.mockResolvedValueOnce({ id: 'test-remote-id', mountPath: 'test-mount-path' });
|
|
33
|
+
remotes.push.mockResolvedValueOnce({ branchName: 'uploaded-to-branch', id: 'test-id' });
|
|
34
34
|
|
|
35
35
|
jest.spyOn(fs, 'createReadStream').mockReturnValue('stream' as any);
|
|
36
36
|
|
|
@@ -118,6 +118,44 @@ describe('handlePush()', () => {
|
|
|
118
118
|
);
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
+
it('should return push id', async () => {
|
|
122
|
+
const mockConfig = { apis: {} } as any;
|
|
123
|
+
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|
|
124
|
+
|
|
125
|
+
fsStatSyncSpy.mockReturnValueOnce({
|
|
126
|
+
isDirectory() {
|
|
127
|
+
return false;
|
|
128
|
+
},
|
|
129
|
+
} as any);
|
|
130
|
+
|
|
131
|
+
pathResolveSpy.mockImplementationOnce((p) => p);
|
|
132
|
+
pathRelativeSpy.mockImplementationOnce((_, p) => p);
|
|
133
|
+
pathDirnameSpy.mockImplementation((_: string) => '.');
|
|
134
|
+
|
|
135
|
+
const result = await handlePush(
|
|
136
|
+
{
|
|
137
|
+
domain: 'test-domain',
|
|
138
|
+
'mount-path': 'test-mount-path',
|
|
139
|
+
organization: 'test-org',
|
|
140
|
+
project: 'test-project',
|
|
141
|
+
branch: 'test-branch',
|
|
142
|
+
namespace: 'test-namespace',
|
|
143
|
+
repository: 'test-repository',
|
|
144
|
+
'commit-sha': 'test-commit-sha',
|
|
145
|
+
'commit-url': 'test-commit-url',
|
|
146
|
+
'default-branch': 'test-branch',
|
|
147
|
+
'created-at': 'test-created-at',
|
|
148
|
+
author: 'TestAuthor <test-author@mail.com>',
|
|
149
|
+
message: 'Test message',
|
|
150
|
+
files: ['test-file'],
|
|
151
|
+
'max-execution-time': 10,
|
|
152
|
+
},
|
|
153
|
+
mockConfig
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
expect(result).toEqual({ pushId: 'test-id' });
|
|
157
|
+
});
|
|
158
|
+
|
|
121
159
|
it('should collect files from directory and preserve file structure', async () => {
|
|
122
160
|
const mockConfig = { apis: {} } as any;
|
|
123
161
|
process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
|