@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
@@ -1,12 +1,4 @@
1
- import {
2
- formatProblems,
3
- getTotals,
4
- getMergedConfig,
5
- lint,
6
- bundle,
7
- Config,
8
- OutputFormat,
9
- } from '@redocly/openapi-core';
1
+ import { formatProblems, getTotals, getMergedConfig, bundle, Config } from '@redocly/openapi-core';
10
2
  import {
11
3
  dumpBundle,
12
4
  getExecutionTime,
@@ -15,8 +7,6 @@ import {
15
7
  handleError,
16
8
  printUnusedWarnings,
17
9
  saveBundle,
18
- printLintTotals,
19
- checkIfRulesetExist,
20
10
  sortTopLevelKeysForOas,
21
11
  } from '../utils/miscellaneous';
22
12
  import type { OutputExtensions, Skips, Totals } from '../types';
@@ -27,15 +17,12 @@ import { checkForDeprecatedOptions } from '../utils/miscellaneous';
27
17
 
28
18
  export type BundleOptions = {
29
19
  apis?: string[];
30
- 'max-problems'?: number;
31
20
  extends?: string[];
32
21
  config?: string;
33
- format?: OutputFormat;
34
22
  output?: string;
35
23
  ext: OutputExtensions;
36
24
  dereferenced?: boolean;
37
25
  force?: boolean;
38
- lint?: boolean;
39
26
  metafile?: string;
40
27
  'remove-unused-components'?: boolean;
41
28
  'keep-url-references'?: boolean;
@@ -47,14 +34,7 @@ export async function handleBundle(argv: BundleOptions, config: Config, version:
47
34
  config.rawConfig?.styleguide?.decorators?.hasOwnProperty('remove-unused-components');
48
35
  const apis = await getFallbackApisOrExit(argv.apis, config);
49
36
  const totals: Totals = { errors: 0, warnings: 0, ignored: 0 };
50
- const maxProblems = argv['max-problems'];
51
- const deprecatedOptions: Array<keyof BundleOptions> = [
52
- 'lint',
53
- 'format',
54
- 'skip-rule',
55
- 'extends',
56
- 'max-problems',
57
- ];
37
+ const deprecatedOptions: Array<keyof BundleOptions> = [];
58
38
 
59
39
  checkForDeprecatedOptions(argv, deprecatedOptions);
60
40
 
@@ -64,38 +44,9 @@ export async function handleBundle(argv: BundleOptions, config: Config, version:
64
44
  const resolvedConfig = getMergedConfig(config, alias);
65
45
  const { styleguide } = resolvedConfig;
66
46
 
67
- styleguide.skipRules(argv['skip-rule']);
68
47
  styleguide.skipPreprocessors(argv['skip-preprocessor']);
69
48
  styleguide.skipDecorators(argv['skip-decorator']);
70
49
 
71
- if (argv.lint) {
72
- checkIfRulesetExist(styleguide.rules);
73
- if (config.styleguide.recommendedFallback) {
74
- process.stderr.write(
75
- `No configurations were provided -- using built in ${blue(
76
- 'recommended'
77
- )} configuration by default.\n\n`
78
- );
79
- }
80
- const results = await lint({
81
- ref: path,
82
- config: resolvedConfig,
83
- });
84
- const fileLintTotals = getTotals(results);
85
-
86
- totals.errors += fileLintTotals.errors;
87
- totals.warnings += fileLintTotals.warnings;
88
- totals.ignored += fileLintTotals.ignored;
89
-
90
- formatProblems(results, {
91
- format: argv.format || 'codeframe',
92
- totals: fileLintTotals,
93
- version,
94
- maxProblems: maxProblems,
95
- });
96
- printLintTotals(fileLintTotals, 2);
97
- }
98
-
99
50
  process.stderr.write(gray(`bundling ${path}...\n`));
100
51
 
101
52
  const {
@@ -132,8 +83,7 @@ export async function handleBundle(argv: BundleOptions, config: Config, version:
132
83
  totals.ignored += fileTotals.ignored;
133
84
 
134
85
  formatProblems(problems, {
135
- format: argv.format || 'codeframe',
136
- maxProblems: maxProblems,
86
+ format: 'codeframe',
137
87
  totals: fileTotals,
138
88
  version,
139
89
  });
@@ -6,10 +6,8 @@ import {
6
6
  Config,
7
7
  SpecVersion,
8
8
  BaseResolver,
9
- StyleguideConfig,
10
9
  formatProblems,
11
10
  getTotals,
12
- lintDocument,
13
11
  detectSpec,
14
12
  bundleDocument,
15
13
  isRef,
@@ -17,13 +15,10 @@ import {
17
15
  import {
18
16
  getFallbackApisOrExit,
19
17
  printExecutionTime,
20
- handleError,
21
- printLintTotals,
22
18
  exitWithError,
23
19
  sortTopLevelKeysForOas,
24
20
  getAndValidateFileExtension,
25
21
  writeToFileByExtension,
26
- checkForDeprecatedOptions,
27
22
  } from '../utils/miscellaneous';
28
23
  import { isObject, isString, keysOf } from '../utils/js-utils';
29
24
  import { COMPONENTS, OPENAPI3_METHOD } from './split/types';
@@ -60,9 +55,6 @@ type JoinDocumentContext = {
60
55
 
61
56
  export type JoinOptions = {
62
57
  apis: string[];
63
- lint?: boolean;
64
- decorate?: boolean;
65
- preprocess?: boolean;
66
58
  'prefix-tags-with-info-prop'?: string;
67
59
  'prefix-tags-with-filename'?: boolean;
68
60
  'prefix-components-with-info-prop'?: string;
@@ -79,8 +71,6 @@ export async function handleJoin(argv: JoinOptions, config: Config, packageVersi
79
71
  return exitWithError(`At least 2 apis should be provided. \n\n`);
80
72
  }
81
73
 
82
- checkForDeprecatedOptions(argv, ['lint'] as Array<keyof JoinOptions>);
83
-
84
74
  const fileExtension = getAndValidateFileExtension(argv.output || argv.apis[0]);
85
75
 
86
76
  const {
@@ -111,23 +101,19 @@ export async function handleJoin(argv: JoinOptions, config: Config, packageVersi
111
101
  )
112
102
  );
113
103
 
114
- if (!argv.decorate) {
115
- const decorators = new Set([
116
- ...Object.keys(config.styleguide.decorators.oas3_0),
117
- ...Object.keys(config.styleguide.decorators.oas3_1),
118
- ...Object.keys(config.styleguide.decorators.oas2),
119
- ]);
120
- config.styleguide.skipDecorators(Array.from(decorators));
121
- }
104
+ const decorators = new Set([
105
+ ...Object.keys(config.styleguide.decorators.oas3_0),
106
+ ...Object.keys(config.styleguide.decorators.oas3_1),
107
+ ...Object.keys(config.styleguide.decorators.oas2),
108
+ ]);
109
+ config.styleguide.skipDecorators(Array.from(decorators));
122
110
 
123
- if (!argv.preprocess) {
124
- const preprocessors = new Set([
125
- ...Object.keys(config.styleguide.preprocessors.oas3_0),
126
- ...Object.keys(config.styleguide.preprocessors.oas3_1),
127
- ...Object.keys(config.styleguide.preprocessors.oas2),
128
- ]);
129
- config.styleguide.skipPreprocessors(Array.from(preprocessors));
130
- }
111
+ const preprocessors = new Set([
112
+ ...Object.keys(config.styleguide.preprocessors.oas3_0),
113
+ ...Object.keys(config.styleguide.preprocessors.oas3_1),
114
+ ...Object.keys(config.styleguide.preprocessors.oas2),
115
+ ]);
116
+ config.styleguide.skipPreprocessors(Array.from(preprocessors));
131
117
 
132
118
  const bundleResults = await Promise.all(
133
119
  documents.map((document) =>
@@ -146,7 +132,7 @@ export async function handleJoin(argv: JoinOptions, config: Config, packageVersi
146
132
  if (fileTotals.errors) {
147
133
  formatProblems(problems, {
148
134
  totals: fileTotals,
149
- version: document.parsed.version,
135
+ version: packageVersion,
150
136
  });
151
137
  exitWithError(
152
138
  `❌ Errors encountered while bundling ${blue(
@@ -179,12 +165,6 @@ export async function handleJoin(argv: JoinOptions, config: Config, packageVersi
179
165
  }
180
166
  }
181
167
 
182
- if (argv.lint) {
183
- for (const document of documents) {
184
- await validateApi(document, config.styleguide, externalRefResolver, packageVersion);
185
- }
186
- }
187
-
188
168
  const joinedDef: any = {};
189
169
  const potentialConflicts = {
190
170
  tags: {},
@@ -787,22 +767,6 @@ function getInfoPrefix(info: any, prefixArg: string | undefined, type: string) {
787
767
  return info[prefixArg].replaceAll(/\s/g, '_');
788
768
  }
789
769
 
790
- async function validateApi(
791
- document: Document,
792
- config: StyleguideConfig,
793
- externalRefResolver: BaseResolver,
794
- packageVersion: string
795
- ) {
796
- try {
797
- const results = await lintDocument({ document, config, externalRefResolver });
798
- const fileTotals = getTotals(results);
799
- formatProblems(results, { format: 'stylish', totals: fileTotals, version: packageVersion });
800
- printLintTotals(fileTotals, 2);
801
- } catch (err) {
802
- handleError(err, document.parsed);
803
- }
804
- }
805
-
806
770
  function replace$Refs(obj: unknown, componentsPrefix: string) {
807
771
  crawl(obj, (node: Record<string, unknown>) => {
808
772
  if (node.$ref && typeof node.$ref === 'string' && startsWithComponents(node.$ref)) {
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import './utils/assert-node-version';
4
4
  import * as yargs from 'yargs';
5
+ import * as colors from 'colorette';
5
6
  import { outputExtensions, PushArguments, regionChoices } from './types';
6
7
  import { RedoclyClient } from '@redocly/openapi-core';
7
8
  import { previewDocs } from './commands/preview-docs';
@@ -104,9 +105,6 @@ yargs
104
105
  demandOption: true,
105
106
  })
106
107
  .option({
107
- lint: { description: 'Lint descriptions', type: 'boolean', default: false, hidden: true },
108
- decorate: { description: 'Run decorators', type: 'boolean', default: false },
109
- preprocess: { description: 'Run preprocessors', type: 'boolean', default: false },
110
108
  'prefix-tags-with-info-prop': {
111
109
  description: 'Prefix tags with property value from info object.',
112
110
  requiresArg: true,
@@ -141,8 +139,47 @@ yargs
141
139
  choices: ['warn', 'error', 'off'] as ReadonlyArray<RuleSeverity>,
142
140
  default: 'warn' as RuleSeverity,
143
141
  },
142
+ lint: {
143
+ hidden: true,
144
+ deprecated: true,
145
+ },
146
+ decorate: {
147
+ hidden: true,
148
+ deprecated: true,
149
+ },
150
+ preprocess: {
151
+ hidden: true,
152
+ deprecated: true,
153
+ },
144
154
  }),
145
155
  (argv) => {
156
+ const DEPRECATED_OPTIONS = ['lint', 'preprocess', 'decorate'];
157
+ const DECORATORS_DOCUMENTATION_LINK = 'https://redocly.com/docs/cli/decorators/#decorators';
158
+ const JOIN_COMMAND_DOCUMENTATION_LINK = 'https://redocly.com/docs/cli/commands/join/#join';
159
+
160
+ DEPRECATED_OPTIONS.forEach((option) => {
161
+ if (argv[option]) {
162
+ process.stdout.write(
163
+ `${colors.red(
164
+ `Option --${option} is no longer supported. Please review join command documentation ${JOIN_COMMAND_DOCUMENTATION_LINK}.`
165
+ )}`
166
+ );
167
+ process.stdout.write('\n\n');
168
+
169
+ if (['preprocess', 'decorate'].includes(option)) {
170
+ process.stdout.write(
171
+ `${colors.red(
172
+ `If you are looking for decorators, please review the decorators documentation ${DECORATORS_DOCUMENTATION_LINK}.`
173
+ )}`
174
+ );
175
+ process.stdout.write('\n\n');
176
+ }
177
+
178
+ yargs.showHelp();
179
+ process.exit(1);
180
+ }
181
+ });
182
+
146
183
  process.env.REDOCLY_CLI_COMMAND = 'join';
147
184
  commandWrapper(handleJoin)(argv);
148
185
  }
@@ -167,9 +204,10 @@ yargs
167
204
  project: {
168
205
  description: 'Name of the project to push to.',
169
206
  type: 'string',
207
+ required: true,
170
208
  alias: 'p',
171
209
  },
172
- domain: { description: 'Specify a domain.', alias: 'd', type: 'string' },
210
+ domain: { description: 'Specify a domain.', alias: 'd', type: 'string', required: false },
173
211
  wait: {
174
212
  description: 'Wait for build to finish.',
175
213
  type: 'boolean',
@@ -179,6 +217,11 @@ yargs
179
217
  description: 'Maximum execution time in seconds.',
180
218
  type: 'number',
181
219
  },
220
+ 'continue-on-deploy-failures': {
221
+ description: 'Command does not fail even if the deployment fails.',
222
+ type: 'boolean',
223
+ default: false,
224
+ },
182
225
  }),
183
226
  (argv) => {
184
227
  process.env.REDOCLY_CLI_COMMAND = 'push-status';
@@ -340,10 +383,15 @@ yargs
340
383
  type: 'boolean',
341
384
  default: false,
342
385
  },
386
+ 'continue-on-deploy-failures': {
387
+ description: 'Command does not fail even if the deployment fails.',
388
+ type: 'boolean',
389
+ default: false,
390
+ },
343
391
  }),
344
392
  (argv) => {
345
393
  process.env.REDOCLY_CLI_COMMAND = 'push';
346
- commandWrapper(commonPushHandler(argv))(argv as PushArguments);
394
+ commandWrapper(commonPushHandler(argv))(argv as Arguments<PushArguments>);
347
395
  }
348
396
  )
349
397
  .command(
@@ -360,6 +408,7 @@ yargs
360
408
  'checkstyle',
361
409
  'codeclimate',
362
410
  'summary',
411
+ 'github-actions',
363
412
  ] as ReadonlyArray<OutputFormat>,
364
413
  default: 'codeframe' as OutputFormat,
365
414
  },
@@ -415,28 +464,11 @@ yargs
415
464
  description: 'Output file.',
416
465
  alias: 'o',
417
466
  },
418
- format: {
419
- description: 'Use a specific output format.',
420
- choices: ['stylish', 'codeframe', 'json', 'checkstyle'] as ReadonlyArray<OutputFormat>,
421
- hidden: true,
422
- },
423
- 'max-problems': {
424
- requiresArg: true,
425
- description: 'Reduce output to a maximum of N problems.',
426
- type: 'number',
427
- hidden: true,
428
- },
429
467
  ext: {
430
468
  description: 'Bundle file extension.',
431
469
  requiresArg: true,
432
470
  choices: outputExtensions,
433
471
  },
434
- 'skip-rule': {
435
- description: 'Ignore certain rules.',
436
- array: true,
437
- type: 'string',
438
- hidden: true,
439
- },
440
472
  'skip-preprocessor': {
441
473
  description: 'Ignore certain preprocessors.',
442
474
  array: true,
@@ -461,12 +493,6 @@ yargs
461
493
  description: 'Path to the config file.',
462
494
  type: 'string',
463
495
  },
464
- lint: {
465
- description: 'Lint API descriptions',
466
- type: 'boolean',
467
- default: false,
468
- hidden: true,
469
- },
470
496
  metafile: {
471
497
  description: 'Produce metadata about the bundle',
472
498
  type: 'string',
@@ -493,8 +519,43 @@ yargs
493
519
  choices: ['warn', 'error', 'off'] as ReadonlyArray<RuleSeverity>,
494
520
  default: 'warn' as RuleSeverity,
495
521
  },
522
+ format: {
523
+ hidden: true,
524
+ deprecated: true,
525
+ },
526
+ lint: {
527
+ hidden: true,
528
+ deprecated: true,
529
+ },
530
+ 'skip-rule': {
531
+ hidden: true,
532
+ deprecated: true,
533
+ array: true,
534
+ type: 'string',
535
+ },
536
+ 'max-problems': {
537
+ hidden: true,
538
+ deprecated: true,
539
+ },
496
540
  }),
497
541
  (argv) => {
542
+ const DEPRECATED_OPTIONS = ['lint', 'format', 'skip-rule', 'max-problems'];
543
+ const LINT_AND_BUNDLE_DOCUMENTATION_LINK =
544
+ 'https://redocly.com/docs/cli/guides/lint-and-bundle/#lint-and-bundle-api-descriptions-with-redocly-cli';
545
+
546
+ DEPRECATED_OPTIONS.forEach((option) => {
547
+ if (argv[option]) {
548
+ process.stdout.write(
549
+ `${colors.red(
550
+ `Option --${option} is no longer supported. Please use separate commands, as described in the ${LINT_AND_BUNDLE_DOCUMENTATION_LINK}.`
551
+ )}`
552
+ );
553
+ process.stdout.write('\n\n');
554
+ yargs.showHelp();
555
+ process.exit(1);
556
+ }
557
+ });
558
+
498
559
  process.env.REDOCLY_CLI_COMMAND = 'bundle';
499
560
  commandWrapper(handleBundle)(argv);
500
561
  }
@@ -7,6 +7,7 @@ import * as fs from 'fs';
7
7
  import * as readline from 'readline';
8
8
  import { Writable } from 'stream';
9
9
  import { execSync } from 'child_process';
10
+ import { promisify } from 'util';
10
11
  import {
11
12
  BundleOutputFormat,
12
13
  StyleguideConfig,
@@ -106,7 +107,7 @@ async function expandGlobsInEntrypoints(args: string[], config: ConfigApis) {
106
107
  await Promise.all(
107
108
  (args as string[]).map(async (aliasOrPath) => {
108
109
  return glob.hasMagic(aliasOrPath) && !isAbsoluteUrl(aliasOrPath)
109
- ? (await glob.__promisify__(aliasOrPath)).map((g: string) => getAliasOrPath(config, g))
110
+ ? (await promisify(glob)(aliasOrPath)).map((g: string) => getAliasOrPath(config, g))
110
111
  : getAliasOrPath(config, aliasOrPath);
111
112
  })
112
113
  )
@@ -292,9 +293,9 @@ export function handleError(e: Error, ref: string) {
292
293
  throw e;
293
294
  }
294
295
  case ResolveError:
295
- return exitWithError(`Failed to resolve API description at ${ref}:\n\n - ${e.message}.`);
296
+ return exitWithError(`Failed to resolve API description at ${ref}:\n\n - ${e.message}`);
296
297
  case YamlParseError:
297
- return exitWithError(`Failed to parse API description at ${ref}:\n\n - ${e.message}.`);
298
+ return exitWithError(`Failed to parse API description at ${ref}:\n\n - ${e.message}`);
298
299
  case CircularJSONNotSupportedError: {
299
300
  return exitWithError(
300
301
  `Detected circular reference which can't be converted to JSON.\n` +
@@ -306,7 +307,7 @@ export function handleError(e: Error, ref: string) {
306
307
  case ConfigValidationError:
307
308
  return exitWithError(e.message);
308
309
  default: {
309
- exitWithError(`Something went wrong when processing ${ref}:\n\n - ${e.message}.`);
310
+ exitWithError(`Something went wrong when processing ${ref}:\n\n - ${e.message}`);
310
311
  }
311
312
  }
312
313
  }
package/src/wrapper.ts CHANGED
@@ -11,7 +11,7 @@ import { lintConfigCallback } from './commands/lint';
11
11
  import type { CommandOptions } from './types';
12
12
 
13
13
  export function commandWrapper<T extends CommandOptions>(
14
- commandHandler?: (argv: T, config: Config, version: string) => Promise<void>
14
+ commandHandler?: (argv: T, config: Config, version: string) => Promise<unknown>
15
15
  ) {
16
16
  return async (argv: Arguments<T>) => {
17
17
  let code: ExitCode = 2;