diff --git a/.changeset/witty-taxis-occur.md b/.changeset/witty-taxis-occur.md new file mode 100644 index 000000000..c6b693a60 --- /dev/null +++ b/.changeset/witty-taxis-occur.md @@ -0,0 +1,7 @@ +--- +'@redocly/cli': minor +'@redocly/openapi-core': minor +--- + +Added the possibility to configure the linting severity level of the configuration file for all CLI commands. +Redocly CLI will exit with an error if there are any issues with the configuration file, and the severity is set to `error`. diff --git a/__tests__/commands.test.ts b/__tests__/commands.test.ts index 9a8159a99..e88f475c5 100644 --- a/__tests__/commands.test.ts +++ b/__tests__/commands.test.ts @@ -60,8 +60,8 @@ describe('E2E', () => { { dirName: 'invalid-config--lint-config-error', option: 'error' }, { dirName: 'invalid-lint-config-severity', option: 'something' }, { dirName: 'invalid-config--no-option', option: null }, - { dirName: 'invalid-config-assertation-name', option: 'error' }, - { dirName: 'invalid-config-assertation-config-type', option: 'error' }, + { dirName: 'invalid-config-assertation-name', option: 'warn' }, + { dirName: 'invalid-config-assertation-config-type', option: 'warn' }, { dirName: 'invalid-config-format-json', option: 'warn', format: 'json' }, ]; @@ -85,15 +85,29 @@ describe('E2E', () => { (expect(result) as any).toMatchSpecificSnapshot(join(folderPath, 'snapshot.js')); }); - test('invalid-definition-and-config', () => { - const folderPath = join(__dirname, 'lint-config/invalid-definition-and-config'); + const configSeverityOptions: { dirName: string; option: string | null; snapshot: string }[] = [ + { + dirName: 'invalid-definition-and-config', + option: 'error', + snapshot: 'config-with-error.snapshot.js', + }, + { + dirName: 'invalid-definition-and-config', + option: 'warn', + snapshot: 'config-with-warn.snapshot.js', + }, + ]; + + test.each(configSeverityOptions)('invalid-definition-and-config: %s', (severityOption) => { + const { dirName, option, snapshot } = severityOption; + const folderPath = join(__dirname, `lint-config/${dirName}`); const relativeInvalidOpenapiFile = relative(folderPath, invalidOpenapiFile); - const args = [relativeInvalidOpenapiFile, `--lint-config=error`]; + const args = [relativeInvalidOpenapiFile, `--lint-config=${option}`]; const passedArgs = getParams('../../../packages/cli/src/index.ts', 'lint', args); const result = getCommandOutput(passedArgs, folderPath); - (expect(result) as any).toMatchSpecificSnapshot(join(folderPath, 'snapshot.js')); + (expect(result) as any).toMatchSpecificSnapshot(join(folderPath, snapshot)); }); }); diff --git a/__tests__/lint-config/invalid-config--lint-config-error/snapshot.js b/__tests__/lint-config/invalid-config--lint-config-error/snapshot.js index f4fad3d0d..da6fe49b0 100644 --- a/__tests__/lint-config/invalid-config--lint-config-error/snapshot.js +++ b/__tests__/lint-config/invalid-config--lint-config-error/snapshot.js @@ -16,12 +16,6 @@ Error was generated by the configuration spec rule. ❌ Your config has 1 error. -validating ../__fixtures__/valid-openapi.yaml... -../__fixtures__/valid-openapi.yaml: validated in ms -Woohoo! Your API description is valid. 🎉 - -[WARNING] Unused rules found in .redocly.yaml: context. -Check the spelling and verify the added plugin prefix. `; diff --git a/__tests__/lint-config/invalid-config--lint-config-warn/snapshot.js b/__tests__/lint-config/invalid-config--lint-config-warn/snapshot.js index 5e0007ec9..6fe44b25b 100644 --- a/__tests__/lint-config/invalid-config--lint-config-warn/snapshot.js +++ b/__tests__/lint-config/invalid-config--lint-config-warn/snapshot.js @@ -15,7 +15,7 @@ Property \`context\` is not expected here. Warning was generated by the configuration spec rule. -You have 1 warning. +⚠️ Your config has 1 warning. validating ../__fixtures__/valid-openapi.yaml... ../__fixtures__/valid-openapi.yaml: validated in ms diff --git a/__tests__/lint-config/invalid-config--no-option/snapshot.js b/__tests__/lint-config/invalid-config--no-option/snapshot.js index 7456ea063..25fe6ccf3 100644 --- a/__tests__/lint-config/invalid-config--no-option/snapshot.js +++ b/__tests__/lint-config/invalid-config--no-option/snapshot.js @@ -15,7 +15,7 @@ Property \`context\` is not expected here. Warning was generated by the configuration spec rule. -You have 1 warning. +⚠️ Your config has 1 warning. validating ../__fixtures__/valid-openapi.yaml... ../__fixtures__/valid-openapi.yaml: validated in ms diff --git a/__tests__/lint-config/invalid-config-assertation-config-type/snapshot.js b/__tests__/lint-config/invalid-config-assertation-config-type/snapshot.js index 4d8dcff3f..bb7df83c0 100644 --- a/__tests__/lint-config/invalid-config-assertation-config-type/snapshot.js +++ b/__tests__/lint-config/invalid-config-assertation-config-type/snapshot.js @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`E2E lint-config test with option: { dirName: 'invalid-config-assertation-config-type', option: 'error' } 1`] = ` +exports[`E2E lint-config test with option: { dirName: 'invalid-config-assertation-config-type', option: 'warn' } 1`] = ` [1] .redocly.yaml:8:17 at #/rules/assert~1path-item-mutually-required/where/0/subject/type @@ -13,10 +13,10 @@ exports[`E2E lint-config test with option: { dirName: 'invalid-config-assertatio 9 | property: property 10 | assertions: -Error was generated by the configuration spec rule. +Warning was generated by the configuration spec rule. -❌ Your config has 1 error. +⚠️ Your config has 1 warning. The 'assert/' syntax in assert/path-item-mutually-required is deprecated. Update your configuration to use 'rule/' instead. Examples and more information: https://redocly.com/docs/cli/rules/configurable-rules/ validating ../__fixtures__/valid-openapi.yaml... diff --git a/__tests__/lint-config/invalid-config-assertation-name/snapshot.js b/__tests__/lint-config/invalid-config-assertation-name/snapshot.js index b11b18bb5..1cdd50189 100644 --- a/__tests__/lint-config/invalid-config-assertation-name/snapshot.js +++ b/__tests__/lint-config/invalid-config-assertation-name/snapshot.js @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`E2E lint-config test with option: { dirName: 'invalid-config-assertation-name', option: 'error' } 1`] = ` +exports[`E2E lint-config test with option: { dirName: 'invalid-config-assertation-name', option: 'warn' } 1`] = ` [1] .redocly.yaml:5:3 at #/rules/asset~1path-item-mutually-required @@ -13,10 +13,10 @@ The field \`severity\` must be present on this level. 6 | context: 7 | - type: PathItem -Error was generated by the configuration spec rule. +Warning was generated by the configuration spec rule. -❌ Your config has 1 error. +⚠️ Your config has 1 warning. validating ../__fixtures__/valid-openapi.yaml... ../__fixtures__/valid-openapi.yaml: validated in ms diff --git a/__tests__/lint-config/invalid-definition-and-config/config-with-error.snapshot.js b/__tests__/lint-config/invalid-definition-and-config/config-with-error.snapshot.js new file mode 100644 index 000000000..c2a894965 --- /dev/null +++ b/__tests__/lint-config/invalid-definition-and-config/config-with-error.snapshot.js @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`E2E lint-config invalid-definition-and-config: { + dirName: 'invalid-definition-and-config', + option: 'error', + snapshot: 'config-with-error.snapshot.js' +} 1`] = ` + +[1] .redocly.yaml:5:3 at #/rules/context + +Property \`context\` is not expected here. + +3 | root: ./openapi.yaml +4 | rules: +5 | context: null + | ^^^^^^^ +6 | extends: +7 | - recommended + +Error was generated by the configuration spec rule. + + +❌ Your config has 1 error. + + +`; diff --git a/__tests__/lint-config/invalid-definition-and-config/snapshot.js b/__tests__/lint-config/invalid-definition-and-config/config-with-warn.snapshot.js similarity index 88% rename from __tests__/lint-config/invalid-definition-and-config/snapshot.js rename to __tests__/lint-config/invalid-definition-and-config/config-with-warn.snapshot.js index 1839add1e..bc984de8d 100644 --- a/__tests__/lint-config/invalid-definition-and-config/snapshot.js +++ b/__tests__/lint-config/invalid-definition-and-config/config-with-warn.snapshot.js @@ -1,6 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`E2E lint-config invalid-definition-and-config 1`] = ` +exports[`E2E lint-config invalid-definition-and-config: { + dirName: 'invalid-definition-and-config', + option: 'warn', + snapshot: 'config-with-warn.snapshot.js' +} 1`] = ` [1] .redocly.yaml:5:3 at #/rules/context @@ -13,10 +17,10 @@ Property \`context\` is not expected here. 6 | extends: 7 | - recommended -Error was generated by the configuration spec rule. +Warning was generated by the configuration spec rule. -❌ Your config has 1 error. +⚠️ Your config has 1 warning. validating ../__fixtures__/invalid-openapi.yaml... [1] ../__fixtures__/invalid-openapi.yaml:4:1 at #/info diff --git a/__tests__/lint/deprecated-apiDefinitions/snapshot.js b/__tests__/lint/deprecated-apiDefinitions/snapshot.js index 173577062..5e007ced4 100644 --- a/__tests__/lint/deprecated-apiDefinitions/snapshot.js +++ b/__tests__/lint/deprecated-apiDefinitions/snapshot.js @@ -30,7 +30,7 @@ Did you mean: env ? Warning was generated by the configuration spec rule. -You have 2 warnings. +⚠️ Your config has 2 warnings. The 'apiDefinitions' field is deprecated. Use apis instead. Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties The 'lint' field is deprecated. Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties validating /openapi.yaml... diff --git a/__tests__/lint/deprecated-lint/snapshot.js b/__tests__/lint/deprecated-lint/snapshot.js index d9924ab4c..3ac900434 100644 --- a/__tests__/lint/deprecated-lint/snapshot.js +++ b/__tests__/lint/deprecated-lint/snapshot.js @@ -18,7 +18,7 @@ Did you mean: env ? Warning was generated by the configuration spec rule. -You have 1 warning. +⚠️ Your config has 1 warning. The 'lint' field is deprecated. Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties validating /openapi.yaml... [1] openapi.yaml:11:7 at #/paths/~1pet~1findByStatus/get/responses diff --git a/__tests__/lint/deprecated-styleguide/snapshot.js b/__tests__/lint/deprecated-styleguide/snapshot.js index d699b800a..ea88d190e 100644 --- a/__tests__/lint/deprecated-styleguide/snapshot.js +++ b/__tests__/lint/deprecated-styleguide/snapshot.js @@ -16,7 +16,7 @@ Property \`styleguide\` is not expected here. Warning was generated by the configuration spec rule. -You have 1 warning. +⚠️ Your config has 1 warning. The 'styleguide' field is deprecated. Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties validating /openapi.yaml... [1] openapi.yaml:11:7 at #/paths/~1pet~1findByStatus/get/responses diff --git a/__tests__/split/missing-outDir/snapshot.js b/__tests__/split/missing-outDir/snapshot.js index 0b28ec7eb..2d0c7f328 100644 --- a/__tests__/split/missing-outDir/snapshot.js +++ b/__tests__/split/missing-outDir/snapshot.js @@ -10,11 +10,14 @@ Positionals: api API description file that you want to split [string] [required] Options: - --version Show version number. [boolean] - --help Show help. [boolean] - --outDir Output directory where files will be saved. [string] [required] - --separator File path separator used while splitting. [string] [default: "_"] - --config Path to the config file. [string] + --version Show version number. [boolean] + --help Show help. [boolean] + --outDir Output directory where files will be saved. [string] [required] + --separator File path separator used while splitting. + [string] [default: "_"] + --config Path to the config file. [string] + --lint-config Severity level for config file linting. + [choices: "warn", "error", "off"] [default: "warn"] Missing required argument: outDir diff --git a/docs/commands/build-docs.md b/docs/commands/build-docs.md index 5426d707e..4565b2a71 100644 --- a/docs/commands/build-docs.md +++ b/docs/commands/build-docs.md @@ -16,18 +16,19 @@ redocly build-docs -t custom.hbs --templateOptions.metaDescription "Page m ## Options -| Option | Type | Description | -| ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| api | string | Path to the API description filename or alias that you want to generate the build for. Refer to the [API examples](#api-examples) for more information. | -| --output, -o | string | Sets the path and name of the output file. The default value is `redoc-static.html`. | -| --title | string | Sets the page title. | -| --disableGoogleFont | boolean | Disables Google fonts. The default value is `false`. | -| --template, -t | string | Uses custom [Handlebars](https://handlebarsjs.com/) templates to render your OpenAPI description. | -| --templateOptions | string | Adds template options you want to pass to your custom Handlebars template. To add options, use dot notation. | -| --theme.openapi | string | Customizes your output with [Redoc functionality options](https://redocly.com/docs/api-reference-docs/configuration/functionality/) or [Redoc theming options](https://redocly.com/docs/api-reference-docs/configuration/theming/). | -| --config | string | Specifies path to the [configuration file](#custom-configuration-file). | -| --help | boolean | Shows help. | -| --version | boolean | Shows version number. | +| Option | Type | Description | +| ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| api | string | Path to the API description filename or alias that you want to generate the build for. Refer to the [API examples](#api-examples) for more information.
| +| --config | string | Specifies path to the [configuration file](#custom-configuration-file). | +| --disableGoogleFont | boolean | Disables Google fonts. The default value is false. | +| --help | boolean | Shows help. | +| --lint-config | string | Specify the severity level for the configuration file. Possible values: warn, error, off. Default value is warn | +| --output, -o | string | Sets the path and name of the output file. The default value is redoc-static.html. | +| --template, -t | string | Uses custom [Handlebars](https://handlebarsjs.com/) templates to render your OpenAPI description. | +| --templateOptions | string | Adds template options you want to pass to your custom Handlebars template. To add options, use dot notation. | +| --theme.openapi | string | Customizes your output with [Redoc functionality options](https://redocly.com/docs/api-reference-docs/configuration/functionality/) or [Redoc theming options](https://redocly.com/docs/api-reference-docs/configuration/theming/). | +| --title | string | Sets the page title. | +| --version | boolean | Shows version number. | ## Examples diff --git a/docs/commands/bundle.md b/docs/commands/bundle.md index 622b1244f..ae5b81bd3 100644 --- a/docs/commands/bundle.md +++ b/docs/commands/bundle.md @@ -22,7 +22,7 @@ redocly bundle --version | Option | Type | Description | | -------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| apis | [string] | List of API description root filenames or names assigned in the `apis` section of your Redocly configuration file. Default values are all names defined in the `apis` section within your configuration file. | +| apis | [string] | List of API description root filenames or names assigned in the `apis` section of your Redocly configuration file. Default values are all names defined in the `apis` section within your configuration file. | | --config | string | Specify path to the [config file](#custom-configuration-file). | | --dereferenced, -d | boolean | Generate fully dereferenced bundle. | | --ext | string | Specify bundled file extension. Possible values are `json`, `yaml`, or `yml`. Default value is `yaml`. | @@ -31,7 +31,8 @@ redocly bundle --version | --format | string | Format for the output. Possible values are `codeframe`, `stylish`, `json`, or `checkstyle`. Default value is `codeframe`. | | --help | boolean | Show help. | | --keep-url-references, -k | boolean | Keep absolute url references. | -| --lint | boolean | Lint API description files. Default value is `false`. | +| --lint | boolean | Lint API description files. Default value is `false`. | +| --lint-config | string | Specify the severity level for the configuration file.
**Possible values:** `warn`, `error`, `off`. Default value is `warn`. | | --max-problems | integer | Truncate output to display the specified maximum number of problems. Default value is `100`. | | --metafile | string | Path for the bundle metadata file. | | --output, -o | string | Name or folder for the bundle file. If you don't specify the file extension, `.yaml` is used by default. If the specified folder doesn't exist, it's created automatically. **If the file specified as the bundler's output already exists, it's overwritten.** | @@ -111,11 +112,14 @@ The compressed output omits other contexts and suggestions. {% tabs %} {% tab label="Command" %} + ```bash redocly bundle pet.yaml store.yaml -o ./bundled --format=json ``` + {% /tab %} {% tab label="Output" %} + ```bash bundling pet.yaml... { @@ -138,19 +142,24 @@ bundling store.yaml... "problems": [] }📦 Created a bundle for store.yaml at bundled/store.yaml 15ms. ``` + {% /tab %} {% /tabs %} In this format, `bundle` shows the result of bundling (including the number of errors and warnings and their descriptions) in JSON-like output. #### Checkstyle + {% tabs %} {% tab label="Command" %} + ```bash redocly bundle pet.yaml -o ./bundled --lint --format=checkstyle ``` + {% /tab %} {% tab label="Output" %} + ```bash bundling pet.yaml... @@ -160,6 +169,7 @@ bundling pet.yaml... 📦 Created a bundle for pet.yaml at bundled/pet.yaml 35ms. ``` + {% /tab %} {% /tabs %} In this format, `bundle` uses the [Checkstyle](https://checkstyle.org/) XML report format. @@ -172,19 +182,25 @@ All other information is omitted. You may want to skip specific preprocessors, rules, or decorators upon running the command. {% tabs %} {% tab label="Skip preprocessors" %} + ```bash redocly bundle --skip-preprocessor=discriminator-mapping-to-one-of --skip-preprocessor=another-example ``` + {% /tab %} {% tab label="Skip rules" %} + ```bash redocly bundle --skip-rule=no-sibling-refs --skip-rule=no-parent-tags ``` + {% /tab %} {% tab label="Skip decorators" %} + ```bash redocly bundle --skip-decorator=generate-code-samples --skip-decorator=remove-internal-operations ``` + {% /tab %} {% /tabs %} {% admonition type="success" name="Tip" %} diff --git a/docs/commands/join.md b/docs/commands/join.md index 63b08d112..8e5c24d31 100644 --- a/docs/commands/join.md +++ b/docs/commands/join.md @@ -38,33 +38,39 @@ redocly join --version | Option | Type | Description | | ---------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | apis | [string] | **REQUIRED.** 1. Array of paths to API description files that you want to join. At least two input files are required.
2. A wildcard pattern to match API description files within a specific folder. | +| --config | string | Specify path to the [config file](../configuration/index.md). | +| --decorate | boolean | Run decorators. | | --help | boolean | Show help. | | --lint | boolean | Lint API description files. | -| --decorate | boolean | Run decorators. | -| --preprocess | boolean | Run preprocessors. | -| --prefix-tags-with-filename | string | Prefix tags with property value from file name. See the [prefix-tags-with-filename section](#prefix-tags-with-filename) below. | +| --lint-config | string | Specify the severity level for the configuration file.
**Possible values:** `warn`, `error`, `off`. Default value is `warn`. | +| --output, -o | string | Name for the joined output file. Defaults to `openapi.yaml`. **If the file already exists, it's overwritten.** | | --prefix-components-with-info-prop | string | Prefix components with property value from info object. See the [prefix-components-with-info-prop section](#prefix-components-with-info-prop) below. | +| --prefix-tags-with-filename | string | Prefix tags with property value from file name. See the [prefix-tags-with-filename section](#prefix-tags-with-filename) below. | | --prefix-tags-with-info-prop | boolean | Prefix tags with property value from info object. See the [prefix-tags-with-info-prop](#prefix-tags-with-info-prop) section. | -| --without-x-tag-groups | boolean | Skip automated `x-tagGroups` creation. See the [without-x-tag-groups](#without-x-tag-groups) section. | +| --preprocess | boolean | Run preprocessors. | | --version | boolean | Show version number. | -| --output, -o | string | Name for the joined output file. Defaults to `openapi.yaml`. **If the file already exists, it's overwritten.** | -| --config | string | Specify path to the [config file](../configuration/index.md). | +| --without-x-tag-groups | boolean | Skip automated `x-tagGroups` creation. See the [without-x-tag-groups](#without-x-tag-groups) section. | ## Examples ### Array of paths + {% tabs %} {% tab label="Command" %} + ```bash redocly join first-api.yaml second-api.json ``` + {% /tab %} {% tab label="Output" %} + ```bash redocly join first-api.yaml second-api.json openapi.yaml: join processed in 56ms ``` + {% /tab %} {% /tabs %} The command creates the output `openapi.yaml` file in the working directory. @@ -140,13 +146,17 @@ If any of the input files contain the `tags` object, tags in the output file are The output file preserves the original tag names as the value of the `x-displayName` property for each tag. #### Usage + {% tabs %} {% tab label="Command" %} + ```bash redocly join first-api.yaml second-api.json --prefix-tags-with-info-prop title ``` + {% /tab %} {% tab label="Output file example" %} + ```yaml - name: First Document title_endpoints description: endpoints tag description @@ -156,8 +166,10 @@ redocly join first-api.yaml second-api.json --prefix-tags-with-info-prop title description: pets tag description x-displayName: pets ``` + {% /tab %} {% /tabs %} + ### prefix-tags-with-filename If any of the input files contain the `tags` object, tags in the output file are prefixed by the filename of the corresponding input file. @@ -165,13 +177,17 @@ If any of the input files contain the `tags` object, tags in the output file are The output file preserves the original tag names as the value of the `x-displayName` property for each tag. #### Usage + {% tabs %} {% tab label="Command" %} + ```bash redocly join first-api.yaml second-api.json --prefix-tags-with-filename true ``` + {% /tab %} {% tab label="Output file example" %} + ```yaml - name: first-api_endpoints description: endpoints tag description @@ -181,8 +197,10 @@ redocly join first-api.yaml second-api.json --prefix-tags-with-filename true description: pets tag description x-displayName: pets ``` + {% /tab %} {% /tabs %} + ### without-x-tag-groups If you have the same tags in multiple API descriptions, you can allow tag duplication by using the `without-x-tag-groups` option. In this case, the `x-tagGroups` property is not created in the joined file. @@ -206,13 +224,17 @@ openapi.yaml: join processed in 69ms If any of the input files have conflicting component names, this option can be used to resolve that issue and generate the output file. All component names in the output file are prefixed by the selected property from the `info` object of the corresponding input file(s). #### Usage + {% tabs %} {% tab label="Command" %} + ```bash redocly join first-api.yaml second-api.json --prefix-components-with-info-prop version ``` + {% /tab %} {% tab label="Output file example" %} + ```yaml components: schemas: @@ -246,8 +268,10 @@ components: type: integer format: int64 ``` + {% /tab %} {% /tabs %} + ### Custom output file By default, the CLI tool writes the joined file as `openapi.yaml` in the current working directory. Use the optional `--output` argument to provide an alternative output file path. diff --git a/docs/commands/login.md b/docs/commands/login.md index 04b52b08d..d71f08372 100644 --- a/docs/commands/login.md +++ b/docs/commands/login.md @@ -24,17 +24,19 @@ redocly login --verbose ## Options -| Option | Type | Description | -| ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| --help | boolean | Show help. | -| --region, -r | string | Specify which region to use when logging in. Supported values: `us`, `eu`. Read more about [configuring the region](../configuration/index.md). | -| --verbose | boolean | Include additional output. | -| --version | boolean | Show version number. | +| Option | Type | Description | +| ------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | --config | string | Specify path to the [config file](../configuration/index.md). | +| --help | boolean | Show help. | +| --region, -r | string | Specify which region to use when logging in. Supported values: `us`, `eu`. Read more about [configuring the region](../configuration/index.md). | +| --verbose | boolean | Include additional output. | +| --version | boolean | Show version number. | ## Examples + {% tabs %} {% tab label="Successful login" %} + ```bash redocly login 🔑 Copy your API key from https://app.redocly.com/profile and paste it below: @@ -42,8 +44,10 @@ redocly login Logging in... Authorization confirmed. ✅ ``` + {% /tab %} {% tab label="Failed login" %} + ```bash redocly login 🔑 Copy your API key from https://app.redocly.com/profile and paste it below: @@ -51,5 +55,6 @@ redocly login Logging in... Authorization failed. Please check if you entered a valid API key. ``` + {% /tab %} {% /tabs %} diff --git a/docs/commands/preview-docs.md b/docs/commands/preview-docs.md index df8fe6b9b..5feab571e 100644 --- a/docs/commands/preview-docs.md +++ b/docs/commands/preview-docs.md @@ -23,11 +23,12 @@ redocly preview-docs --version | Option | Type | Description | | ----------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| api | string | Path to the API description filename or alias that you want to generate the preview for. Refer to [the api section](#api) for more options. | +| api | string | Path to the API description filename or alias that you want to generate the preview for. Refer to [the api section](#api) for more options. | | --config | string | Specify path to the [configuration file](#custom-configuration-file). | | --force, -f | boolean | Generate preview output even when errors occur. | | --help | boolean | Show help. | | --host, -h | string | The host where the documentation preview can be accessed. The default value is `127.0.0.1`. | +| --lint-config | string | Specify the severity level for the configuration file.
**Possible values:** `warn`, `error`, `off`. Default value is `warn`. | | --port, -p | integer | The port where the documentation preview can be accessed. You can set any port number over 1024 as long as it is not already being used. The default value is port `8080`. | | --skip-decorator | [string] | Ignore [certain decorators](#skip-preprocessor-or-decorator). | | --skip-preprocessor | [string] | Ignore [certain preprocessors](#skip-preprocessor-or-decorator). | @@ -53,16 +54,20 @@ In this case, `preview-docs` previews the API description that was passed to the Instead of a full path, you can use an API name from the `apis` section of your Redocly configuration file. {% tabs %} {% tab label="Command" %} + ```bash redocly preview-docs core@v1 ``` + {% /tab %} {% tab label="Configuration file" %} + ```yaml apis: core@v1: root: ./openapi/api-description.json ``` + {% /tab %} {% /tabs %} @@ -83,14 +88,18 @@ By default, without using the `port` option, the preview starts on port `8080`, To specify a custom port for the preview, pass the desired value using either short or long option format: {% tabs %} {% tab label="Short format" %} + ```bash redocly preview-docs -p 8888 openapi/openapi.yaml ``` + {% /tab %} {% tab label="Long format" %} + ```bash redocly preview-docs -port 8888 openapi/openapi.yaml ``` + {% /tab %} {% /tabs %} @@ -103,14 +112,18 @@ By default, without using the `host` option, the preview starts on host `127.0.0 To specify a custom host for the preview, pass the desired value using either short or long option format: {% tabs %} {% tab label="Short format" %} + ```bash redocly preview-docs -h 0.0.0.0 openapi/openapi.yaml ``` + {% /tab %} {% tab label="Long format" %} + ```bash redocly preview-docs --host 0.0.0.0 openapi/openapi.yaml ``` + {% /tab %} {% /tabs %} @@ -121,13 +134,17 @@ Both commands start the preview on host `0.0.0.0`, so you can access the docs at You may want to skip specific preprocessors, rules, or decorators upon running the command. {% tabs %} {% tab label="Skip preprocessors" %} + ```bash redocly preview-docs --skip-preprocessor=discriminator-mapping-to-one-of --skip-preprocessor=another-example ``` + {% /tab %} {% tab label="Skip decorators" %} + ```bash redocly preview-docs --skip-decorator=generate-code-samples --skip-decorator=remove-internal-operations ``` + {% /tab %} {% /tabs %} diff --git a/docs/commands/push.md b/docs/commands/push.md index 94b84e509..247e1e9f4 100644 --- a/docs/commands/push.md +++ b/docs/commands/push.md @@ -72,21 +72,22 @@ redocly push [-u] [--job-id id] [--batch-size number] **Possible values:** `warn`, `error`, `off`. Default value is `warn`. | +| --organization | string | ID of organization that the API description is being pushed to. Overrides the one defined in the config file. | +| --public | boolean | Make API descriptions publicly accessible from the API Registry. Read more about [using the public option](#public). | | --region,-r | string | Which region to use when logging in. Supported values: `us`, `eu`. The `eu` region is limited to enterprise customers. Default value is `us`. Alternatively, set an environment variable `REDOCLY_DOMAIN` with the value of the appropriate Redocly API. | -| --skip-decorator | [string] | Ignore one or more decorators. See the [Skip decorator section](#skip-decorator) for usage examples. | -| --upsert, -u | boolean | Create a new version of an API when pushing to the API registry if the version doesn't exist. See [the Upsert an API with push section](#upsert-an-api-with-push) for more information. | -| --version | boolean | Show version number. | -| --files | [string] | List of other folders and files to upload. See [the Files section](#files) for more information. | +| --skip-decorator | [string] | Ignore one or more decorators. See the [Skip decorator section](#skip-decorator) for usage examples. | +| --upsert, -u | boolean | Create a new version of an API when pushing to the API registry if the version doesn't exist. See [the Upsert an API with push section](#upsert-an-api-with-push) for more information. | +| --version | boolean | Show version number. | ## Examples @@ -202,34 +203,45 @@ In this case, you don't have to specify the organization ID in the configuration To upsert an API in the registry with the `push` command, use the `--upsert` or `-u` option. The upsert creates the destination if it doesn't exist, or updates it if it does. {% tabs %} {% tab label="Set options explicitly" %} + ```bash redocly push -u test-api-v1.yaml --destination=test-api@v1 --organization=redocly ``` + {% /tab %} {% tab label="Use config file" %} + ```bash redocly push -u --destination=test-api@v1 ``` + {% /tab %} {% tab label="Upsert all APIs from config file" %} + ```bash redocly push -u ``` + {% /tab %} {% /tabs %} To upsert the API description to a particular branch, specify the branch name with `--branch` or `-b`. {% tabs %} {% tab label="Set options explicitly" %} + ```bash redocly push openapi/petstore.yaml --destination=petstore-api@v1 --organization=openapi-org -b develop ``` + {% /tab %} {% tab label="Use config file" %} + ```bash Use config file redocly push -u test-api@v1 -b develop ``` + {% /tab %} {% /tabs %} + ### Job ID The `--job-id` option can be used by Redocly Workflows to associate multiple pushes with a single CI job. @@ -252,16 +264,21 @@ Must be used only in combination with the `--job-id` option. Must be an integer You may want to skip specific decorators upon running the command. {% tabs %} {% tab label="Skip a decorator" %} + ```bash redocly push openapi/petstore.yaml --destination=petstore-api@v1 --organization=openapi-org --skip-decorator=test/remove-internal-operations ``` + {% /tab %} {% tab label="Skip multiple decorators" %} + ```bash redocly push openapi/petstore.yaml --destination=petstore-api@v1 --organization=openapi-org --skip-decorator=test/remove-internal-operations --skip-decorator=test/remove-internal-schemas ``` + {% /tab %} {% /tabs %} + ### Public The `--public` option allows you to upload your API description and make it publicly accessible from the API Registry. By default, API descriptions uploaded with the `push` command are not available to the public. diff --git a/docs/commands/split.md b/docs/commands/split.md index 8c44518bb..b6f1b3f50 100644 --- a/docs/commands/split.md +++ b/docs/commands/split.md @@ -20,30 +20,35 @@ redocly split --version ## Options -| Option | Type | Description | -| ----------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| api | string | **REQUIRED.** Path to the API description file that you want to split into a multi-file structure. | -| --outDir | string | **REQUIRED.** Path to the directory where you want to save split files. If the specified directory doesn't exist, it is created automatically. | -| --help | boolean | Show help. | -| --separator | string | File path separator used while splitting. The default value is `_`. This controls the file names generated in the `paths` folder (e.g. `/users/create` path becomes `user_create.yaml`). | -| --config | string | Specify path to the [config file](../configuration/index.md). | -| --version | boolean | Show version number. | +| Option | Type | Description | +| ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| api | string | **REQUIRED.** Path to the API description file that you want to split into a multi-file structure. | +| --config | string | Specify path to the [config file](../configuration/index.md). | +| --help | boolean | Show help. | +| --lint-config | string | Specify the severity level for the configuration file.
**Possible values:** `warn`, `error`, `off`. Default value is `warn`. | +| --outDir | string | **REQUIRED.** Path to the directory where you want to save split files. If the specified directory doesn't exist, it is created automatically. | +| --separator | string | File path separator used while splitting. The default value is `_`. This controls the file names generated in the `paths` folder (e.g. `/users/create` path becomes `user_create.yaml`). | +| --version | boolean | Show version number. | ## Example {% tabs %} {% tab label="Command" %} + ```bash redocly split pet.yaml --outDir=openapi ``` + {% /tab %} {% tab label="Output" %} + ```bash Document: pet.yaml is successfully split and all related files are saved to the directory: openapi pet.yaml: split processed in 33ms ``` + {% /tab %} {% /tabs %} diff --git a/docs/commands/stats.md b/docs/commands/stats.md index 3ca92e69a..1dc3737a1 100644 --- a/docs/commands/stats.md +++ b/docs/commands/stats.md @@ -23,13 +23,14 @@ redocly stats --version ## Options -| Option | Type | Description | -| --------- | ------- | ------------------------------------------------------------------------------------------------- | -| api | string | **REQUIRED.** Path to the API description file that you want to split into a multi-file structure. | -| --config | string | Specify path to the [configuration file](#custom-configuration-file). | -| --format | string | Format for the output.
**Possible values:** `stylish`, `json`. | -| --help | boolean | Show help. | -| --version | boolean | Show version number. | +| Option | Type | Description | +| ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| api | string | **REQUIRED.** Path to the API description file that you want to split into a multi-file structure. | +| --config | string | Specify path to the [configuration file](#custom-configuration-file). | +| --format | string | Format for the output.
**Possible values:** `stylish`, `json`. | +| --help | boolean | Show help. | +| --lint-config | string | Specify the severity level for the configuration file.
**Possible values:** `warn`, `error`, `off`. Default value is `warn`. | +| --version | boolean | Show version number. | ## Examples @@ -51,16 +52,20 @@ Instead of full paths, you can use API names from the `apis` section of your Red {% tabs %} {% tab label="Command" %} + ```bash redocly stats core@v1 ``` + {% /tab %} {% tab label="Configuration file" %} + ```yaml apis: core@v1: root: ./openapi/api-description.json ``` + {% /tab %} {% /tabs %} @@ -77,13 +82,17 @@ redocly stats --config=./another/directory/config.yaml ### Format #### Stylish (default) + {% tabs %} {% tab label="Request" %} + ```bash redocly stats pet.yaml ``` + {% /tab %} {% tab label="Output" %} + ```bash Document: pet.yaml stats: @@ -98,18 +107,23 @@ Document: pet.yaml stats: pet.yaml: stats processed in 6ms ``` + {% /tab %} {% /tabs %} In this format, `stats` shows the statistics for the metrics mentioned in the [Introduction section](#introduction) in condensed output with colored text and an icon at the beginning of each line. #### JSON + {% tabs %} {% tab label="Command" %} + ```bash redocly stats pet.yaml --format=json ``` + {% /tab %} {% tab label="Output" %} + ```bash Output Document: pet.yaml stats: @@ -149,6 +163,7 @@ Document: pet.yaml stats: } pet.yaml: stats processed in 6ms ``` + {% /tab %} {% /tabs %} In this format, `stats` shows the statistics for the metrics mentioned in the [Introduction section](#introduction) in JSON-like output. diff --git a/packages/cli/src/__tests__/utils.test.ts b/packages/cli/src/__tests__/utils.test.ts index 3b8180eea..48cfde5eb 100644 --- a/packages/cli/src/__tests__/utils.test.ts +++ b/packages/cli/src/__tests__/utils.test.ts @@ -108,22 +108,14 @@ describe('printConfigLintTotals', () => { it('should print errors if such exist', () => { printConfigLintTotals(totalProblemsMock); - expect(process.stderr.write).toHaveBeenCalledWith('❌ Your config has 1 error.\n'); - expect(redColoretteMocks).toHaveBeenCalledWith('❌ Your config has 1 error.\n'); - }); - - it('should print warnign and error', () => { - printConfigLintTotals({ ...totalProblemsMock, warnings: 2 }); - expect(process.stderr.write).toHaveBeenCalledWith( - '❌ Your config has 1 error and 2 warnings.\n' - ); - expect(redColoretteMocks).toHaveBeenCalledWith('❌ Your config has 1 error and 2 warnings.\n'); + expect(process.stderr.write).toHaveBeenCalledWith('❌ Your config has 1 error.'); + expect(redColoretteMocks).toHaveBeenCalledWith('❌ Your config has 1 error.'); }); it('should print warnign if no error', () => { printConfigLintTotals({ ...totalProblemsMock, errors: 0, warnings: 2 }); - expect(process.stderr.write).toHaveBeenCalledWith('You have 2 warnings.\n'); - expect(yellowColoretteMocks).toHaveBeenCalledWith('You have 2 warnings.\n'); + expect(process.stderr.write).toHaveBeenCalledWith('⚠️ Your config has 2 warnings.\n'); + expect(yellowColoretteMocks).toHaveBeenCalledWith('⚠️ Your config has 2 warnings.\n'); }); it('should print nothing if no error and no warnings', () => { diff --git a/packages/cli/src/commands/join.ts b/packages/cli/src/commands/join.ts index 38550ac33..087e4befa 100644 --- a/packages/cli/src/commands/join.ts +++ b/packages/cli/src/commands/join.ts @@ -17,6 +17,7 @@ import { bundleDocument, Referenced, isRef, + RuleSeverity, } from '@redocly/openapi-core'; import { @@ -64,7 +65,7 @@ export type JoinOptions = { output?: string; config?: string; extends?: undefined; - 'lint-config'?: undefined; + 'lint-config'?: RuleSeverity; }; export async function handleJoin(argv: JoinOptions, config: Config, packageVersion: string) { diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts index cef4a0776..0761bc274 100644 --- a/packages/cli/src/commands/lint.ts +++ b/packages/cli/src/commands/lint.ts @@ -9,6 +9,7 @@ import { makeDocumentFromString, stringifyYaml, } from '@redocly/openapi-core'; +import { ConfigValidationError } from '@redocly/openapi-core/lib/config'; import { checkIfRulesetExist, exitWithError, @@ -134,7 +135,7 @@ export function lintConfigCallback( const configContent = makeDocumentFromString(stringYaml, configPath); const problems = await lintConfig({ document: configContent, - severity: argv['lint-config'] as ProblemSeverity, + severity: (argv['lint-config'] || 'warn') as ProblemSeverity, }); const fileTotals = getTotals(problems); @@ -147,5 +148,9 @@ export function lintConfigCallback( }); printConfigLintTotals(fileTotals); + + if (fileTotals.errors > 0) { + throw new ConfigValidationError(); + } }; } diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index fad24cdb2..0243c756d 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -36,6 +36,11 @@ yargs (yargs) => yargs.positional('api', { type: 'string' }).option({ config: { description: 'Path to the config file.', type: 'string' }, + 'lint-config': { + description: 'Severity level for config file linting.', + choices: ['warn', 'error', 'off'] as ReadonlyArray, + default: 'warn' as RuleSeverity, + }, format: { description: 'Use a specific output format.', choices: ['stylish', 'json'] as ReadonlyArray, @@ -73,6 +78,11 @@ yargs requiresArg: true, type: 'string', }, + 'lint-config': { + description: 'Severity level for config file linting.', + choices: ['warn', 'error', 'off'] as ReadonlyArray, + default: 'warn' as RuleSeverity, + }, }) .demandOption('api'), (argv) => { @@ -124,6 +134,11 @@ yargs requiresArg: true, type: 'string', }, + 'lint-config': { + description: 'Severity level for config file linting.', + choices: ['warn', 'error', 'off'] as ReadonlyArray, + default: 'warn' as RuleSeverity, + }, }), (argv) => { process.env.REDOCLY_CLI_COMMAND = 'join'; @@ -196,6 +211,11 @@ yargs array: true, type: 'string', }, + 'lint-config': { + description: 'Severity level for config file linting.', + choices: ['warn', 'error', 'off'] as ReadonlyArray, + default: 'warn' as RuleSeverity, + }, }) .deprecateOption('batch-id', 'use --job-id') .deprecateOption('maybeDestination') @@ -342,6 +362,11 @@ yargs type: 'boolean', alias: 'k', }, + 'lint-config': { + description: 'Severity level for config file linting.', + choices: ['warn', 'error', 'off'] as ReadonlyArray, + default: 'warn' as RuleSeverity, + }, }), (argv) => { process.env.REDOCLY_CLI_COMMAND = 'bundle'; @@ -426,6 +451,11 @@ yargs description: 'Path to the config file.', type: 'string', }, + 'lint-config': { + description: 'Severity level for config file linting.', + choices: ['warn', 'error', 'off'] as ReadonlyArray, + default: 'warn' as RuleSeverity, + }, }), (argv) => { process.env.REDOCLY_CLI_COMMAND = 'preview-docs'; @@ -471,6 +501,11 @@ yargs describe: 'Path to the config file.', type: 'string', }, + 'lint-config': { + description: 'Severity level for config file linting.', + choices: ['warn', 'error', 'off'] as ReadonlyArray, + default: 'warn' as RuleSeverity, + }, }) .check((argv: any) => { if (argv.theme && !argv.theme?.openapi) diff --git a/packages/cli/src/utils.ts b/packages/cli/src/utils.ts index 2ccafb851..0e3fe865f 100644 --- a/packages/cli/src/utils.ts +++ b/packages/cli/src/utils.ts @@ -24,6 +24,7 @@ import { Oas2Definition, RedoclyClient, } from '@redocly/openapi-core'; +import { ConfigValidationError } from '@redocly/openapi-core/lib/config'; import { Totals, outputExtensions, Entrypoint, ConfigApis, CommandOptions } from './types'; import { isEmptyObject } from '@redocly/openapi-core/lib/utils'; import { Arguments } from 'yargs'; @@ -244,6 +245,8 @@ export function handleError(e: Error, ref: string) { } case SyntaxError: return exitWithError(`Syntax error: ${e.message} ${e.stack?.split('\n\n')?.[0]}`); + case ConfigValidationError: + return exitWithError(e.message); default: { exitWithError(`Something went wrong when processing ${ref}:\n\n - ${e.message}.`); } @@ -294,17 +297,11 @@ export function printLintTotals(totals: Totals, definitionsCount: number) { export function printConfigLintTotals(totals: Totals): void { if (totals.errors > 0) { process.stderr.write( - red( - `❌ Your config has ${totals.errors} ${pluralize('error', totals.errors)}${ - totals.warnings > 0 - ? ` and ${totals.warnings} ${pluralize('warning', totals.warnings)}` - : '' - }.\n` - ) + red(`❌ Your config has ${totals.errors} ${pluralize('error', totals.errors)}.`) ); } else if (totals.warnings > 0) { process.stderr.write( - yellow(`You have ${totals.warnings} ${pluralize('warning', totals.warnings)}.\n`) + yellow(`⚠️ Your config has ${totals.warnings} ${pluralize('warning', totals.warnings)}.\n`) ); } } diff --git a/packages/core/src/config/load.ts b/packages/core/src/config/load.ts index 1cc64cf71..9c0b9ba96 100644 --- a/packages/core/src/config/load.ts +++ b/packages/core/src/config/load.ts @@ -4,7 +4,7 @@ import { RedoclyClient } from '../redocly'; import { isEmptyObject, loadYaml, doesYamlFileExist } from '../utils'; import { parseYaml } from '../js-yaml'; import { Config, DOMAINS } from './config'; -import { transformConfig } from './utils'; +import { ConfigValidationError, transformConfig } from './utils'; import { resolveConfig } from './config-resolvers'; import type { @@ -128,6 +128,9 @@ export async function getConfig( } return transformConfig(rawConfig); } catch (e) { + if (e instanceof ConfigValidationError) { + throw e; + } throw new Error(`Error parsing config file at '${configPath}': ${e.message}`); } } diff --git a/packages/core/src/config/utils.ts b/packages/core/src/config/utils.ts index 53f5582ed..44c73872c 100644 --- a/packages/core/src/config/utils.ts +++ b/packages/core/src/config/utils.ts @@ -347,3 +347,5 @@ export function getUniquePlugins(plugins: Plugin[]): Plugin[] { } return results; } + +export class ConfigValidationError extends Error {}