diff --git a/.changeset/big-peas-trade.md b/.changeset/big-peas-trade.md new file mode 100644 index 000000000..dbf77cc6d --- /dev/null +++ b/.changeset/big-peas-trade.md @@ -0,0 +1,6 @@ +--- +"@redocly/openapi-core": patch +"@redocly/cli": patch +--- + +Added the possibility to skip configurable rules using the `--skip-rule` option. diff --git a/.gitignore b/.gitignore index 1a8b6f978..bdee3c94d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,3 @@ output/ *.tgz redoc-static.html packages/cli/README.md -/redocly.yaml -/.redocly.yaml -/redocly.yml -/.redocly.yml diff --git a/__tests__/commands.test.ts b/__tests__/commands.test.ts index b6a8f2eea..af20c6541 100644 --- a/__tests__/commands.test.ts +++ b/__tests__/commands.test.ts @@ -81,6 +81,22 @@ describe('E2E', () => { join(folderPath, 'snapshot.js') ); }); + + test('skip-rules', () => { + const dirName = 'skip-rules'; + const folderPath = join(__dirname, `lint/${dirName}`); + + const args = getParams('../../../packages/cli/src/index.ts', 'lint', [ + '--skip-rule=operation-4xx-response', + '--skip-rule', + 'rule/operationId-casing', + ]); + + const result = getCommandOutput(args, folderPath); + (expect(cleanupOutput(result)) as any).toMatchSpecificSnapshot( + join(folderPath, 'snapshot.js') + ); + }); }); describe('zero-config', () => { diff --git a/__tests__/lint/skip-rules/openapi.yaml b/__tests__/lint/skip-rules/openapi.yaml new file mode 100644 index 000000000..bd079a6d3 --- /dev/null +++ b/__tests__/lint/skip-rules/openapi.yaml @@ -0,0 +1,17 @@ +openapi: 3.0.0 +info: + title: Sample API + version: 1.0.0 + description: It should skip built-in and configurable rules. +paths: + /users: + get: + summary: Retrieve a list of users + operationId: camelCase + responses: + '200': + description: A list of users + content: + application/json: + schema: + type: object diff --git a/__tests__/lint/skip-rules/redocly.yaml b/__tests__/lint/skip-rules/redocly.yaml new file mode 100644 index 000000000..1059d5dec --- /dev/null +++ b/__tests__/lint/skip-rules/redocly.yaml @@ -0,0 +1,11 @@ +apis: + main: + root: ./openapi.yaml + rules: + rule/operationId-casing: + subject: + type: Operation + property: operationId + assertions: + casing: PascalCase + operation-4xx-response: error diff --git a/__tests__/lint/skip-rules/snapshot.js b/__tests__/lint/skip-rules/snapshot.js new file mode 100644 index 000000000..a9da17985 --- /dev/null +++ b/__tests__/lint/skip-rules/snapshot.js @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`E2E lint skip-rules 1`] = ` + +validating /openapi.yaml... +[1] openapi.yaml:10:20 at #/paths/~1users/get/operationId + +rule/operationId-casing failed because the Operation operationId didn't meet the assertions: "camelCase" should use PascalCase + + 8 | get: + 9 | summary: Retrieve a list of users +10 | operationId: camelCase + | ^^^^^^^^^ +11 | responses: +12 | '200': + +Error was generated by the rule/operationId-casing rule. + + +[2] openapi.yaml:11:7 at #/paths/~1users/get/responses + +Operation must have at least one \`4XX\` response. + + 9 | summary: Retrieve a list of users +10 | operationId: camelCase +11 | responses: + | ^^^^^^^^^ +12 | '200': +13 | description: A list of users + +Error was generated by the operation-4xx-response rule. + + +/openapi.yaml: validated in ms + +❌ Validation failed with 2 errors. +run \`redocly lint --generate-ignore-file\` to add all problems to the ignore file. + + +`; + +exports[`E2E lint skip-rules 2`] = ` + +validating /openapi.yaml... +/openapi.yaml: validated in ms + +Woohoo! Your API description is valid. 🎉 + + +`; diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index 7df93d044..365d57a4b 100755 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -323,6 +323,13 @@ export class StyleguideConfig { for (const version of Object.values(SpecVersion)) { if (this.rules[version][ruleId]) { this.rules[version][ruleId] = 'off'; + } else if (Array.isArray(this.rules[version].assertions)) { + // skip assertions + for (const configurableRule of this.rules[version].assertions) { + if (configurableRule.assertionId === ruleId) { + configurableRule.severity = 'off'; + } + } } } }