@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.
Files changed (39) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/lib/__tests__/commands/bundle.test.js +3 -32
  3. package/lib/__tests__/commands/join.test.js +0 -11
  4. package/lib/__tests__/utils.test.js +3 -3
  5. package/lib/cms/api/types.d.ts +22 -11
  6. package/lib/cms/commands/__tests__/push-status.test.js +338 -29
  7. package/lib/cms/commands/__tests__/push.test.js +32 -2
  8. package/lib/cms/commands/__tests__/utils.test.d.ts +1 -0
  9. package/lib/cms/commands/__tests__/utils.test.js +60 -0
  10. package/lib/cms/commands/push-status.d.ts +14 -4
  11. package/lib/cms/commands/push-status.js +160 -90
  12. package/lib/cms/commands/push.d.ts +6 -2
  13. package/lib/cms/commands/push.js +8 -2
  14. package/lib/cms/commands/utils.d.ts +22 -0
  15. package/lib/cms/commands/utils.js +53 -0
  16. package/lib/commands/bundle.d.ts +1 -4
  17. package/lib/commands/bundle.js +2 -32
  18. package/lib/commands/join.d.ts +0 -3
  19. package/lib/commands/join.js +13 -36
  20. package/lib/index.js +69 -27
  21. package/lib/utils/miscellaneous.js +5 -4
  22. package/lib/wrapper.d.ts +1 -1
  23. package/package.json +2 -2
  24. package/src/__tests__/commands/bundle.test.ts +4 -37
  25. package/src/__tests__/commands/join.test.ts +0 -17
  26. package/src/__tests__/utils.test.ts +3 -3
  27. package/src/cms/api/types.ts +19 -12
  28. package/src/cms/commands/__tests__/push-status.test.ts +473 -47
  29. package/src/cms/commands/__tests__/push.test.ts +40 -2
  30. package/src/cms/commands/__tests__/utils.test.ts +62 -0
  31. package/src/cms/commands/push-status.ts +242 -120
  32. package/src/cms/commands/push.ts +21 -5
  33. package/src/cms/commands/utils.ts +52 -0
  34. package/src/commands/bundle.ts +3 -53
  35. package/src/commands/join.ts +13 -49
  36. package/src/index.ts +89 -28
  37. package/src/utils/miscellaneous.ts +5 -4
  38. package/src/wrapper.ts +1 -1
  39. package/tsconfig.tsbuildinfo +1 -1
@@ -10,12 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const push_status_1 = require("../push-status");
13
- const miscellaneous_1 = require("../../../utils/miscellaneous");
14
13
  const remotes = {
15
14
  getPush: jest.fn(),
16
15
  getRemotesList: jest.fn(),
17
16
  };
18
- jest.mock('../../../utils/miscellaneous');
19
17
  jest.mock('colorette', () => ({
20
18
  green: (str) => str,
21
19
  yellow: (str) => str,
@@ -27,22 +25,49 @@ jest.mock('colorette', () => ({
27
25
  jest.mock('../../api', () => (Object.assign(Object.assign({}, jest.requireActual('../../api')), { ReuniteApiClient: jest.fn().mockImplementation(function (...args) {
28
26
  this.remotes = remotes;
29
27
  }) })));
28
+ jest.mock('@redocly/openapi-core', () => ({
29
+ pause: jest.requireActual('@redocly/openapi-core').pause,
30
+ }));
30
31
  describe('handlePushStatus()', () => {
31
32
  const mockConfig = { apis: {} };
33
+ const commitStub = {
34
+ message: 'test-commit-message',
35
+ branchName: 'test-branch-name',
36
+ sha: null,
37
+ url: null,
38
+ createdAt: null,
39
+ namespaceId: null,
40
+ repositoryId: null,
41
+ author: {
42
+ name: 'test-author-name',
43
+ email: 'test-author-email',
44
+ image: null,
45
+ },
46
+ statuses: [],
47
+ };
32
48
  const pushResponseStub = {
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,
33
58
  hasChanges: true,
34
59
  status: {
35
60
  preview: {
36
61
  scorecard: [],
37
62
  deploy: {
38
- url: 'https://test-url',
63
+ url: 'https://preview-test-url',
39
64
  status: 'success',
40
65
  },
41
66
  },
42
67
  production: {
43
68
  scorecard: [],
44
69
  deploy: {
45
- url: 'https://test-url',
70
+ url: 'https://production-test-url',
46
71
  status: 'success',
47
72
  },
48
73
  },
@@ -56,16 +81,16 @@ describe('handlePushStatus()', () => {
56
81
  jest.clearAllMocks();
57
82
  });
58
83
  it('should throw error if organization not provided', () => __awaiter(void 0, void 0, void 0, function* () {
59
- yield (0, push_status_1.handlePushStatus)({
84
+ yield expect((0, push_status_1.handlePushStatus)({
60
85
  domain: 'test-domain',
61
86
  organization: '',
62
87
  project: 'test-project',
63
88
  pushId: 'test-push-id',
64
- 'max-execution-time': 1000,
65
- }, mockConfig);
66
- expect(miscellaneous_1.exitWithError).toHaveBeenCalledWith("No organization provided, please use --organization option or specify the 'organization' field in the config file.");
89
+ }, mockConfig)).rejects.toThrowErrorMatchingInlineSnapshot(`"No organization provided, please use --organization option or specify the 'organization' field in the config file."`);
90
+ expect(process.stderr.write).toHaveBeenCalledWith(`No organization provided, please use --organization option or specify the 'organization' field in the config file.` +
91
+ '\n\n');
67
92
  }));
68
- it('should return success push status for preview-build', () => __awaiter(void 0, void 0, void 0, function* () {
93
+ it('should print success push status for preview-build', () => __awaiter(void 0, void 0, void 0, function* () {
69
94
  process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
70
95
  remotes.getPush.mockResolvedValueOnce(pushResponseStub);
71
96
  yield (0, push_status_1.handlePushStatus)({
@@ -73,12 +98,11 @@ describe('handlePushStatus()', () => {
73
98
  organization: 'test-org',
74
99
  project: 'test-project',
75
100
  pushId: 'test-push-id',
76
- 'max-execution-time': 1000,
77
101
  }, mockConfig);
78
102
  expect(process.stdout.write).toHaveBeenCalledTimes(1);
79
- expect(process.stdout.write).toHaveBeenCalledWith('🚀 Preview deploy success.\nPreview URL: https://test-url\n');
103
+ expect(process.stdout.write).toHaveBeenCalledWith('🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n');
80
104
  }));
81
- it('should return success push status for preview and production builds', () => __awaiter(void 0, void 0, void 0, function* () {
105
+ it('should print success push status for preview and production builds', () => __awaiter(void 0, void 0, void 0, function* () {
82
106
  process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
83
107
  remotes.getPush.mockResolvedValue(Object.assign(Object.assign({}, pushResponseStub), { isMainBranch: true }));
84
108
  yield (0, push_status_1.handlePushStatus)({
@@ -86,38 +110,39 @@ describe('handlePushStatus()', () => {
86
110
  organization: 'test-org',
87
111
  project: 'test-project',
88
112
  pushId: 'test-push-id',
89
- 'max-execution-time': 1000,
90
113
  }, mockConfig);
91
114
  expect(process.stdout.write).toHaveBeenCalledTimes(2);
92
- expect(process.stdout.write).toHaveBeenCalledWith('🚀 Preview deploy success.\nPreview URL: https://test-url\n');
93
- expect(process.stdout.write).toHaveBeenCalledWith('🚀 Production deploy success.\nProduction URL: https://test-url\n');
115
+ expect(process.stdout.write).toHaveBeenCalledWith('🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n');
116
+ expect(process.stdout.write).toHaveBeenCalledWith('🚀 Production deploy success.\nProduction URL: https://production-test-url\n');
94
117
  }));
95
- it('should return failed push status for preview build', () => __awaiter(void 0, void 0, void 0, function* () {
118
+ it('should print failed push status for preview build', () => __awaiter(void 0, void 0, void 0, function* () {
96
119
  process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
97
120
  remotes.getPush.mockResolvedValue({
98
121
  isOutdated: false,
99
122
  hasChanges: true,
100
123
  status: {
101
- preview: { deploy: { status: 'failed', url: 'https://test-url' }, scorecard: [] },
124
+ preview: { deploy: { status: 'failed', url: 'https://preview-test-url' }, scorecard: [] },
102
125
  },
103
126
  });
104
- yield (0, push_status_1.handlePushStatus)({
127
+ yield expect((0, push_status_1.handlePushStatus)({
105
128
  domain: 'test-domain',
106
129
  organization: 'test-org',
107
130
  project: 'test-project',
108
131
  pushId: 'test-push-id',
109
- 'max-execution-time': 1000,
110
- }, mockConfig);
111
- expect(miscellaneous_1.exitWithError).toHaveBeenCalledWith('❌ Preview deploy fail.\nPreview URL: https://test-url');
132
+ }, mockConfig)).rejects.toThrowErrorMatchingInlineSnapshot(`
133
+ "❌ Preview deploy fail.
134
+ Preview URL: https://preview-test-url"
135
+ `);
136
+ expect(process.stderr.write).toHaveBeenCalledWith('❌ Preview deploy fail.\nPreview URL: https://preview-test-url' + '\n\n');
112
137
  }));
113
- it('should return success push status for preview build and print scorecards', () => __awaiter(void 0, void 0, void 0, function* () {
138
+ it('should print success push status for preview build and print scorecards', () => __awaiter(void 0, void 0, void 0, function* () {
114
139
  process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
115
140
  remotes.getPush.mockResolvedValue({
116
141
  isOutdated: false,
117
142
  hasChanges: true,
118
143
  status: {
119
144
  preview: {
120
- deploy: { status: 'success', url: 'https://test-url' },
145
+ deploy: { status: 'success', url: 'https://preview-test-url' },
121
146
  scorecard: [
122
147
  {
123
148
  name: 'test-name',
@@ -134,21 +159,24 @@ describe('handlePushStatus()', () => {
134
159
  organization: 'test-org',
135
160
  project: 'test-project',
136
161
  pushId: 'test-push-id',
137
- 'max-execution-time': 1000,
138
162
  }, mockConfig);
139
163
  expect(process.stdout.write).toHaveBeenCalledTimes(4);
140
- expect(process.stdout.write).toHaveBeenCalledWith('🚀 Preview deploy success.\nPreview URL: https://test-url\n');
164
+ expect(process.stdout.write).toHaveBeenCalledWith('🚀 Preview deploy success.\nPreview URL: https://preview-test-url\n');
141
165
  expect(process.stdout.write).toHaveBeenCalledWith('\nScorecard:');
142
166
  expect(process.stdout.write).toHaveBeenCalledWith('\n Name: test-name\n Status: success\n URL: test-url\n Description: test-description\n');
143
167
  expect(process.stdout.write).toHaveBeenCalledWith('\n');
144
168
  }));
145
- it('should display message if there is no changes', () => __awaiter(void 0, void 0, void 0, function* () {
169
+ it('should print message if there is no changes', () => __awaiter(void 0, void 0, void 0, function* () {
146
170
  process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
147
171
  remotes.getPush.mockResolvedValueOnce({
148
172
  isOutdated: false,
149
173
  hasChanges: false,
150
174
  status: {
151
- preview: { deploy: { status: 'skipped', url: 'https://test-url' }, scorecard: [] },
175
+ preview: { deploy: { status: 'skipped', url: 'https://preview-test-url' }, scorecard: [] },
176
+ production: {
177
+ deploy: { status: 'skipped', url: null },
178
+ scorecard: [],
179
+ },
152
180
  },
153
181
  });
154
182
  yield (0, push_status_1.handlePushStatus)({
@@ -157,8 +185,289 @@ describe('handlePushStatus()', () => {
157
185
  project: 'test-project',
158
186
  pushId: 'test-push-id',
159
187
  wait: true,
160
- 'max-execution-time': 1000,
161
188
  }, mockConfig);
162
- expect(process.stderr.write).toHaveBeenCalledWith('Files not uploaded. Reason: no changes.\n');
189
+ expect(process.stderr.write).toHaveBeenCalledWith('Files not added to your project. Reason: no changes.\n');
163
190
  }));
191
+ describe('return value', () => {
192
+ it('should return preview deployment info', () => __awaiter(void 0, void 0, void 0, function* () {
193
+ process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
194
+ remotes.getPush.mockResolvedValue(Object.assign(Object.assign({}, pushResponseStub), { isMainBranch: false }));
195
+ const result = yield (0, push_status_1.handlePushStatus)({
196
+ domain: 'test-domain',
197
+ organization: 'test-org',
198
+ project: 'test-project',
199
+ pushId: 'test-push-id',
200
+ }, mockConfig);
201
+ expect(result).toEqual({
202
+ preview: {
203
+ deploy: {
204
+ status: 'success',
205
+ url: 'https://preview-test-url',
206
+ },
207
+ scorecard: [],
208
+ },
209
+ production: null,
210
+ commit: commitStub,
211
+ });
212
+ }));
213
+ it('should return preview and production deployment info', () => __awaiter(void 0, void 0, void 0, function* () {
214
+ process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
215
+ remotes.getPush.mockResolvedValue(Object.assign(Object.assign({}, pushResponseStub), { isMainBranch: true }));
216
+ const result = yield (0, push_status_1.handlePushStatus)({
217
+ domain: 'test-domain',
218
+ organization: 'test-org',
219
+ project: 'test-project',
220
+ pushId: 'test-push-id',
221
+ }, mockConfig);
222
+ expect(result).toEqual({
223
+ preview: {
224
+ deploy: {
225
+ status: 'success',
226
+ url: 'https://preview-test-url',
227
+ },
228
+ scorecard: [],
229
+ },
230
+ production: {
231
+ deploy: {
232
+ status: 'success',
233
+ url: 'https://production-test-url',
234
+ },
235
+ scorecard: [],
236
+ },
237
+ commit: commitStub,
238
+ });
239
+ }));
240
+ });
241
+ describe('"wait" option', () => {
242
+ it('should wait for preview "success" deployment status', () => __awaiter(void 0, void 0, void 0, function* () {
243
+ process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
244
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { status: {
245
+ preview: {
246
+ deploy: { status: 'pending', url: 'https://preview-test-url' },
247
+ scorecard: [],
248
+ },
249
+ } }));
250
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { status: {
251
+ preview: {
252
+ deploy: { status: 'running', url: 'https://preview-test-url' },
253
+ scorecard: [],
254
+ },
255
+ } }));
256
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { status: {
257
+ preview: {
258
+ deploy: { status: 'success', url: 'https://preview-test-url' },
259
+ scorecard: [],
260
+ },
261
+ } }));
262
+ const result = yield (0, push_status_1.handlePushStatus)({
263
+ domain: 'test-domain',
264
+ organization: 'test-org',
265
+ project: 'test-project',
266
+ pushId: 'test-push-id',
267
+ 'retry-interval': 0.5,
268
+ wait: true,
269
+ }, mockConfig);
270
+ expect(result).toEqual({
271
+ preview: {
272
+ deploy: {
273
+ status: 'success',
274
+ url: 'https://preview-test-url',
275
+ },
276
+ scorecard: [],
277
+ },
278
+ production: null,
279
+ commit: commitStub,
280
+ });
281
+ }));
282
+ it('should wait for production "success" status after preview "success" status', () => __awaiter(void 0, void 0, void 0, function* () {
283
+ process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
284
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { isMainBranch: true, status: {
285
+ preview: {
286
+ deploy: { status: 'success', url: 'https://preview-test-url' },
287
+ scorecard: [],
288
+ },
289
+ production: {
290
+ deploy: { status: 'pending', url: 'https://production-test-url' },
291
+ scorecard: [],
292
+ },
293
+ } }));
294
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { isMainBranch: true, status: {
295
+ preview: {
296
+ deploy: { status: 'success', url: 'https://preview-test-url' },
297
+ scorecard: [],
298
+ },
299
+ production: {
300
+ deploy: { status: 'running', url: 'https://production-test-url' },
301
+ scorecard: [],
302
+ },
303
+ } }));
304
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { isMainBranch: true, status: {
305
+ preview: {
306
+ deploy: { status: 'success', url: 'https://preview-test-url' },
307
+ scorecard: [],
308
+ },
309
+ production: {
310
+ deploy: { status: 'success', url: 'https://production-test-url' },
311
+ scorecard: [],
312
+ },
313
+ } }));
314
+ const result = yield (0, push_status_1.handlePushStatus)({
315
+ domain: 'test-domain',
316
+ organization: 'test-org',
317
+ project: 'test-project',
318
+ pushId: 'test-push-id',
319
+ 'retry-interval': 0.5,
320
+ wait: true,
321
+ }, mockConfig);
322
+ expect(result).toEqual({
323
+ preview: {
324
+ deploy: { status: 'success', url: 'https://preview-test-url' },
325
+ scorecard: [],
326
+ },
327
+ production: {
328
+ deploy: { status: 'success', url: 'https://production-test-url' },
329
+ scorecard: [],
330
+ },
331
+ commit: commitStub,
332
+ });
333
+ }));
334
+ });
335
+ describe('"continue-on-deploy-failures" option', () => {
336
+ it('should throw error if option value is false', () => __awaiter(void 0, void 0, void 0, function* () {
337
+ process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
338
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { status: {
339
+ preview: {
340
+ deploy: { status: 'failed', url: 'https://preview-test-url' },
341
+ scorecard: [],
342
+ },
343
+ } }));
344
+ yield expect((0, push_status_1.handlePushStatus)({
345
+ domain: 'test-domain',
346
+ organization: 'test-org',
347
+ project: 'test-project',
348
+ pushId: 'test-push-id',
349
+ 'continue-on-deploy-failures': false,
350
+ }, mockConfig)).rejects.toThrowErrorMatchingInlineSnapshot(`
351
+ "❌ Preview deploy fail.
352
+ Preview URL: https://preview-test-url"
353
+ `);
354
+ }));
355
+ it('should not throw error if option value is true', () => __awaiter(void 0, void 0, void 0, function* () {
356
+ process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
357
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { status: {
358
+ preview: {
359
+ deploy: { status: 'failed', url: 'https://preview-test-url' },
360
+ scorecard: [],
361
+ },
362
+ } }));
363
+ yield expect((0, push_status_1.handlePushStatus)({
364
+ domain: 'test-domain',
365
+ organization: 'test-org',
366
+ project: 'test-project',
367
+ pushId: 'test-push-id',
368
+ 'continue-on-deploy-failures': true,
369
+ }, mockConfig)).resolves.toStrictEqual({
370
+ preview: {
371
+ deploy: { status: 'failed', url: 'https://preview-test-url' },
372
+ scorecard: [],
373
+ },
374
+ production: null,
375
+ commit: commitStub,
376
+ });
377
+ }));
378
+ });
379
+ describe('"onRetry" callback', () => {
380
+ it('should be called when command retries request to API in wait mode for preview deploy', () => __awaiter(void 0, void 0, void 0, function* () {
381
+ process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
382
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { status: {
383
+ preview: {
384
+ deploy: { status: 'pending', url: 'https://preview-test-url' },
385
+ scorecard: [],
386
+ },
387
+ } }));
388
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { status: {
389
+ preview: {
390
+ deploy: { status: 'running', url: 'https://preview-test-url' },
391
+ scorecard: [],
392
+ },
393
+ } }));
394
+ remotes.getPush.mockResolvedValueOnce(Object.assign(Object.assign({}, pushResponseStub), { status: {
395
+ preview: {
396
+ deploy: { status: 'success', url: 'https://preview-test-url' },
397
+ scorecard: [],
398
+ },
399
+ } }));
400
+ const onRetrySpy = jest.fn();
401
+ const result = yield (0, push_status_1.handlePushStatus)({
402
+ domain: 'test-domain',
403
+ organization: 'test-org',
404
+ project: 'test-project',
405
+ pushId: 'test-push-id',
406
+ wait: true,
407
+ 'retry-interval': 0.5,
408
+ onRetry: onRetrySpy,
409
+ }, mockConfig);
410
+ expect(onRetrySpy).toBeCalledTimes(2);
411
+ // first retry
412
+ expect(onRetrySpy).toHaveBeenNthCalledWith(1, {
413
+ preview: {
414
+ deploy: {
415
+ status: 'pending',
416
+ url: 'https://preview-test-url',
417
+ },
418
+ scorecard: [],
419
+ },
420
+ production: null,
421
+ commit: commitStub,
422
+ });
423
+ // second retry
424
+ expect(onRetrySpy).toHaveBeenNthCalledWith(2, {
425
+ preview: {
426
+ deploy: {
427
+ status: 'running',
428
+ url: 'https://preview-test-url',
429
+ },
430
+ scorecard: [],
431
+ },
432
+ production: null,
433
+ commit: commitStub,
434
+ });
435
+ // final result
436
+ expect(result).toEqual({
437
+ preview: {
438
+ deploy: {
439
+ status: 'success',
440
+ url: 'https://preview-test-url',
441
+ },
442
+ scorecard: [],
443
+ },
444
+ production: null,
445
+ commit: commitStub,
446
+ });
447
+ }));
448
+ });
449
+ describe('"max-execution-time" option', () => {
450
+ it('should throw error in case "max-execution-time" was exceeded', () => __awaiter(void 0, void 0, void 0, function* () {
451
+ process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
452
+ // Stuck deployment simulation
453
+ remotes.getPush.mockResolvedValue(Object.assign(Object.assign({}, pushResponseStub), { status: {
454
+ preview: {
455
+ deploy: { status: 'pending', url: 'https://preview-test-url' },
456
+ scorecard: [],
457
+ },
458
+ } }));
459
+ yield expect((0, push_status_1.handlePushStatus)({
460
+ domain: 'test-domain',
461
+ organization: 'test-org',
462
+ project: 'test-project',
463
+ pushId: 'test-push-id',
464
+ 'retry-interval': 2,
465
+ 'max-execution-time': 1,
466
+ wait: true,
467
+ }, mockConfig)).rejects.toThrowErrorMatchingInlineSnapshot(`
468
+ "✗ Failed to get push status. Reason: Timeout exceeded
469
+ "
470
+ `);
471
+ }));
472
+ });
164
473
  });
@@ -32,8 +32,8 @@ describe('handlePush()', () => {
32
32
  let fsReaddirSyncSpy;
33
33
  beforeEach(() => {
34
34
  remotes.getDefaultBranch.mockResolvedValueOnce('test-default-branch');
35
- remotes.upsert.mockResolvedValueOnce({ id: 'test-remote-id' });
36
- remotes.push.mockResolvedValueOnce({ branchName: 'uploaded-to-branch' });
35
+ remotes.upsert.mockResolvedValueOnce({ id: 'test-remote-id', mountPath: 'test-mount-path' });
36
+ remotes.push.mockResolvedValueOnce({ branchName: 'uploaded-to-branch', id: 'test-id' });
37
37
  jest.spyOn(fs, 'createReadStream').mockReturnValue('stream');
38
38
  pathResolveSpy = jest.spyOn(path, 'resolve');
39
39
  pathRelativeSpy = jest.spyOn(path, 'relative');
@@ -104,6 +104,36 @@ describe('handlePush()', () => {
104
104
  },
105
105
  ]);
106
106
  }));
107
+ it('should return push id', () => __awaiter(void 0, void 0, void 0, function* () {
108
+ const mockConfig = { apis: {} };
109
+ process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
110
+ fsStatSyncSpy.mockReturnValueOnce({
111
+ isDirectory() {
112
+ return false;
113
+ },
114
+ });
115
+ pathResolveSpy.mockImplementationOnce((p) => p);
116
+ pathRelativeSpy.mockImplementationOnce((_, p) => p);
117
+ pathDirnameSpy.mockImplementation((_) => '.');
118
+ const result = yield (0, push_1.handlePush)({
119
+ domain: 'test-domain',
120
+ 'mount-path': 'test-mount-path',
121
+ organization: 'test-org',
122
+ project: 'test-project',
123
+ branch: 'test-branch',
124
+ namespace: 'test-namespace',
125
+ repository: 'test-repository',
126
+ 'commit-sha': 'test-commit-sha',
127
+ 'commit-url': 'test-commit-url',
128
+ 'default-branch': 'test-branch',
129
+ 'created-at': 'test-created-at',
130
+ author: 'TestAuthor <test-author@mail.com>',
131
+ message: 'Test message',
132
+ files: ['test-file'],
133
+ 'max-execution-time': 10,
134
+ }, mockConfig);
135
+ expect(result).toEqual({ pushId: 'test-id' });
136
+ }));
107
137
  it('should collect files from directory and preserve file structure', () => __awaiter(void 0, void 0, void 0, function* () {
108
138
  const mockConfig = { apis: {} };
109
139
  process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,60 @@
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
+ const utils_1 = require("../utils");
13
+ jest.mock('@redocly/openapi-core', () => ({
14
+ pause: jest.requireActual('@redocly/openapi-core').pause,
15
+ }));
16
+ describe('retryUntilConditionMet()', () => {
17
+ it('should retry until condition meet and return result', () => __awaiter(void 0, void 0, void 0, function* () {
18
+ const operation = jest
19
+ .fn()
20
+ .mockResolvedValueOnce({ status: 'pending' })
21
+ .mockResolvedValueOnce({ status: 'pending' })
22
+ .mockResolvedValueOnce({ status: 'done' });
23
+ const data = yield (0, utils_1.retryUntilConditionMet)({
24
+ operation,
25
+ condition: (result) => (result === null || result === void 0 ? void 0 : result.status) === 'done',
26
+ retryIntervalMs: 100,
27
+ retryTimeoutMs: 1000,
28
+ });
29
+ expect(data).toEqual({ status: 'done' });
30
+ }));
31
+ it('should throw error if condition not meet for desired timeout', () => __awaiter(void 0, void 0, void 0, function* () {
32
+ const operation = jest.fn().mockResolvedValue({ status: 'pending' });
33
+ yield expect((0, utils_1.retryUntilConditionMet)({
34
+ operation,
35
+ condition: (result) => (result === null || result === void 0 ? void 0 : result.status) === 'done',
36
+ retryIntervalMs: 100,
37
+ retryTimeoutMs: 1000,
38
+ })).rejects.toThrow('Timeout exceeded');
39
+ }));
40
+ it('should call "onConditionNotMet" and "onRetry" callbacks', () => __awaiter(void 0, void 0, void 0, function* () {
41
+ const operation = jest
42
+ .fn()
43
+ .mockResolvedValueOnce({ status: 'pending' })
44
+ .mockResolvedValueOnce({ status: 'pending' })
45
+ .mockResolvedValueOnce({ status: 'done' });
46
+ const onConditionNotMet = jest.fn();
47
+ const onRetry = jest.fn();
48
+ const data = yield (0, utils_1.retryUntilConditionMet)({
49
+ operation,
50
+ condition: (result) => (result === null || result === void 0 ? void 0 : result.status) === 'done',
51
+ retryIntervalMs: 100,
52
+ retryTimeoutMs: 1000,
53
+ onConditionNotMet,
54
+ onRetry,
55
+ });
56
+ expect(data).toEqual({ status: 'done' });
57
+ expect(onConditionNotMet).toHaveBeenCalledTimes(2);
58
+ expect(onRetry).toHaveBeenCalledTimes(2);
59
+ }));
60
+ });
@@ -1,12 +1,22 @@
1
- import { Config } from '@redocly/openapi-core';
1
+ import type { Config, OutputFormat } from '@redocly/openapi-core';
2
+ import type { DeploymentStatusResponse, PushResponse } from '../api/types';
2
3
  export type PushStatusOptions = {
3
4
  organization: string;
4
5
  project: string;
5
6
  pushId: string;
6
7
  domain?: string;
7
8
  config?: string;
8
- format?: 'stylish' | 'json';
9
+ format?: Extract<OutputFormat, 'stylish'>;
9
10
  wait?: boolean;
10
- 'max-execution-time': number;
11
+ 'max-execution-time'?: number;
12
+ 'retry-interval'?: number;
13
+ 'start-time'?: number;
14
+ 'continue-on-deploy-failures'?: boolean;
15
+ onRetry?: (lasSummary: PushStatusSummary) => void;
11
16
  };
12
- export declare function handlePushStatus(argv: PushStatusOptions, config: Config): Promise<void>;
17
+ export interface PushStatusSummary {
18
+ preview: DeploymentStatusResponse;
19
+ production: DeploymentStatusResponse | null;
20
+ commit: PushResponse['commit'];
21
+ }
22
+ export declare function handlePushStatus(argv: PushStatusOptions, config: Config): Promise<PushStatusSummary | undefined>;