fix: show error if apis or rules not provided (#1055)

This commit is contained in:
Ihor Karpiuk
2023-05-08 16:07:18 +03:00
committed by GitHub
parent e9dde4b6f3
commit f5bf5f834a
27 changed files with 136 additions and 54 deletions

View File

@@ -28,8 +28,6 @@ paths:
foo: TEST
components: {}
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./test.yaml...
📦 Created a bundle for ./test.yaml at stdout <test>ms.

View File

@@ -36,13 +36,6 @@ components:
$ref: '#/components/schemas/Name'
description: Other name (specific).
test.yaml:
1:1 error spec The field \`info\` must be present on this level.
< ... 2 more problems hidden > increase with \`--max-problems N\`
❌ Validation failed with 2 errors and 1 warning.
run \`openapi lint --generate-ignore-file\` to add all problems to the ignore file.
bundling ./test.yaml...
📦 Created a bundle for ./test.yaml at stdout <test>ms.

View File

@@ -18,12 +18,6 @@ info:
security: []
components: {}
test.yaml:
1:1 error no-empty-servers Servers must be present.
❌ Validation failed with 1 error.
run \`openapi lint --generate-ignore-file\` to add all problems to the ignore file.
bundling ./test.yaml...
📦 Created a bundle for ./test.yaml at stdout <test>ms.

View File

@@ -2,8 +2,6 @@
exports[`E2E bundle info-description-override-error 1`] = `
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./main.yaml...
main.yaml:
8:16 error info-description-override Failed to read markdown override file for "info.description".

View File

@@ -31,8 +31,6 @@ paths:
description: example description
components: {}
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./main.yaml...
📦 Created a bundle for ./main.yaml at stdout <test>ms.

View File

@@ -27,8 +27,6 @@ paths:
description: example description
components: {}
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./main.yaml...
📦 Created a bundle for ./main.yaml at stdout <test>ms.

View File

@@ -2,8 +2,6 @@
exports[`E2E bundle operation-description-override-error 1`] = `
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./openapi.yaml...
openapi.yaml:
23:7 error operation-description-override Failed to read markdown override file for operation "updatePet".

View File

@@ -47,8 +47,6 @@ paths:
description: ok
components: {}
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./openapi.yaml...
📦 Created a bundle for ./openapi.yaml at stdout <test>ms.

View File

@@ -40,8 +40,6 @@ paths:
key2: 2
components: {}
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./openapi.yaml...
📦 Created a bundle for ./openapi.yaml at stdout <test>ms.

View File

@@ -1,6 +1,7 @@
apis:
main:
root: ./openapi.yaml
decorators:
plugin/resolve-x: on
plugins:

View File

@@ -2,6 +2,9 @@ openapi: 3.0.3
info:
title: foo
version: 1.0
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
x-attributes:
- $ref: external.yaml#/Test1
test-attributes:

View File

@@ -5,6 +5,9 @@ openapi: 3.0.3
info:
title: foo
version: 1
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
x-attributes:
- $ref: external.yaml#/Test1
resolved:
@@ -15,8 +18,6 @@ info:
name: test 2
components: {}
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./openapi.yaml...
📦 Created a bundle for ./openapi.yaml at stdout <test>ms.

View File

@@ -2,8 +2,6 @@
exports[`E2E bundle tag-description-override-error 1`] = `
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./main.yaml...
main.yaml:
17:5 error tag-description-override Failed to read markdown override file for tag "pet".

View File

@@ -43,8 +43,6 @@ paths:
description: example description
components: {}
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./main.yaml...
📦 Created a bundle for ./main.yaml at stdout <test>ms.

View File

@@ -205,6 +205,7 @@ describe('E2E', () => {
'bundle-remove-unused-components',
'bundle-remove-unused-components-from-config',
'bundle-lint-format',
'max-problems-argument',
];
const folderPath = join(__dirname, 'bundle');
const contents = readdirSync(folderPath).filter((folder) => !excludeFolders.includes(folder));
@@ -218,8 +219,6 @@ describe('E2E', () => {
const entryPoints = getEntrypoints(testPath);
const args = getParams('../../../packages/cli/src/index.ts', 'bundle', [
'--lint',
'--max-problems=1',
'--format=stylish',
...entryPoints,
]);
@@ -229,6 +228,19 @@ describe('E2E', () => {
(<any>expect(result)).toMatchSpecificSnapshot(join(testPath, 'snapshot.js'));
});
}
it('max-problems-argument', () => {
const folderPath = join(__dirname, 'bundle/max-problems-argument');
const entryPoints = getEntrypoints(folderPath);
const args = getParams('../../../packages/cli/src/index.ts', 'bundle', [
'--lint',
'--max-problems=1',
'--format=stylish',
...entryPoints,
]);
const result = getCommandOutput(args, folderPath);
(<any>expect(result)).toMatchSpecificSnapshot(join(folderPath, 'snapshot.js'));
});
});
describe('bundle lint format', () => {

View File

@@ -1 +1,4 @@
badKey: 1
badKey: 1
extends:
- recommended

View File

@@ -0,0 +1,5 @@
apis:
main:
root: openapi.yaml
extends: []

View File

@@ -0,0 +1,18 @@
openapi: 3.1.0
info:
title: Example OpenAPI 3 definition.
version: 1.0.0
paths:
'/ping/{id}/{test}':
get:
parameters:
- in: path
name: test_id
description: User id
required: true
schema:
type: string
responses:
'200':
description: example description

View File

@@ -0,0 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`E2E lint extends-empty-array 1`] = `
⚠️ No rules were configured. Learn how to configure rules: https://redocly.com/docs/cli/rules/
`;

View File

@@ -2,10 +2,7 @@
exports[`E2E lint turn-off-rules 1`] = `
validating /openapi.yaml...
/openapi.yaml: validated in <test>ms
Woohoo! Your OpenAPI definition is valid. 🎉
⚠️ No rules were configured. Learn how to configure rules: https://redocly.com/docs/cli/rules/
`;

View File

@@ -2,10 +2,7 @@
exports[`E2E zero-config no-default-recommended-fallback 1`] = `
validating /openapi.yaml...
/openapi.yaml: validated in <test>ms
Woohoo! Your OpenAPI definition is valid. 🎉
⚠️ No rules were configured. Learn how to configure rules: https://redocly.com/docs/cli/rules/
`;

View File

@@ -15,4 +15,5 @@ export const handleError = jest.fn();
export const exitWithError = jest.fn();
export const writeYaml = jest.fn();
export const loadConfigAndHandleErrors = jest.fn(() => ConfigFixture);
export const checkIfRulesetExist = jest.fn();
export const sortTopLevelKeysForOas = jest.fn((document) => document);

View File

@@ -13,6 +13,7 @@ import {
handleError,
exitWithError,
loadConfigAndHandleErrors,
checkIfRulesetExist,
} from '../../utils';
import { ConfigFixture } from '../fixtures/config';
import { performance } from 'perf_hooks';
@@ -87,6 +88,17 @@ describe('handleLint', () => {
await handleLint({ ...argvMock, 'generate-ignore-file': true }, versionMock);
expect(getMergedConfigMock).toHaveBeenCalled();
});
it('should check if ruleset exist', async () => {
await handleLint(argvMock, versionMock);
expect(checkIfRulesetExist).toHaveBeenCalledTimes(1);
});
it('should fail if apis not provided', async () => {
await handleLint({ ...argvMock, apis: [] }, versionMock);
expect(getFallbackApisOrExit).toHaveBeenCalledTimes(1);
expect(exitWithError).toHaveBeenCalledWith('No APIs were provided');
});
});
describe('loop through entrypints and lint stage', () => {

View File

@@ -4,6 +4,7 @@ import {
pathToFilename,
printConfigLintTotals,
langToExt,
checkIfRulesetExist,
handleError,
CircularJSONNotSupportedError,
sortTopLevelKeysForOas,
@@ -408,3 +409,33 @@ describe('handleErrors', () => {
);
});
});
describe('checkIfRulesetExist', () => {
beforeEach(() => {
jest.spyOn(process, 'exit').mockImplementation((code?: number) => code as never);
});
afterEach(() => {
jest.clearAllMocks();
});
it('should exit if rules not provided', () => {
const rules = {
oas2: {},
oas3_0: {},
oas3_1: {},
};
checkIfRulesetExist(rules);
expect(process.exit).toHaveBeenCalledWith(1);
});
it('should not exit if rules provided', () => {
const rules = {
oas2: { 'operation-4xx-response': 'error' },
oas3_0: {},
oas3_1: {},
} as any;
checkIfRulesetExist(rules);
expect(process.exit).not.toHaveBeenCalled();
});
});

View File

@@ -9,6 +9,7 @@ import {
saveBundle,
printLintTotals,
loadConfigAndHandleErrors,
checkIfRulesetExist,
sortTopLevelKeysForOas,
} from '../utils';
import type { CommonOptions, OutputExtensions, Skips, Totals } from '../types';
@@ -51,6 +52,7 @@ export async function handleBundle(argv: BundleOptions, version: string) {
styleguide.skipDecorators(argv['skip-decorator']);
if (argv.lint) {
checkIfRulesetExist(styleguide.rules);
if (config.styleguide.recommendedFallback) {
process.stderr.write(
`No configurations were provided -- using built in ${blue(

View File

@@ -1,28 +1,29 @@
import {
Config,
doesYamlFileExist,
findConfig,
formatProblems,
getMergedConfig,
getTotals,
lint,
lintConfig,
findConfig,
getMergedConfig,
makeDocumentFromString,
stringifyYaml,
ProblemSeverity,
RawConfig,
RuleSeverity,
ProblemSeverity,
doesYamlFileExist,
stringifyYaml,
} from '@redocly/openapi-core';
import {
checkIfRulesetExist,
exitWithError,
getExecutionTime,
getFallbackApisOrExit,
handleError,
pluralize,
printLintTotals,
printConfigLintTotals,
printUnusedWarnings,
exitWithError,
loadConfigAndHandleErrors,
pluralize,
printConfigLintTotals,
printLintTotals,
printUnusedWarnings,
} from '../utils';
import type { CommonOptions, Skips, Totals } from '../types';
import { blue, gray } from 'colorette';
@@ -47,6 +48,10 @@ export async function handleLint(argv: LintOptions, version: string) {
const apis = await getFallbackApisOrExit(argv.apis, config);
if (!apis.length) {
return exitWithError('No APIs were provided');
}
if (argv['generate-ignore-file']) {
config.styleguide.ignore = {}; // clear ignore
}
@@ -60,6 +65,8 @@ export async function handleLint(argv: LintOptions, version: string) {
const resolvedConfig = getMergedConfig(config, alias);
const { styleguide } = resolvedConfig;
checkIfRulesetExist(styleguide.rules);
styleguide.skipRules(argv['skip-rule']);
styleguide.skipPreprocessors(argv['skip-preprocessor']);

View File

@@ -22,6 +22,7 @@ import {
Oas2Definition,
} from '@redocly/openapi-core';
import { Totals, outputExtensions, Entrypoint, ConfigApis } from './types';
import { isEmptyObject } from '@redocly/openapi-core/lib/utils';
export async function getFallbackApisOrExit(
argsApis: string[] | undefined,
@@ -455,3 +456,17 @@ function sortOas3Keys(document: Oas3Definition): Oas3Definition {
// merge any other top-level keys (e.g. vendor extensions)
return Object.assign(result, document);
}
export function checkIfRulesetExist(rules: typeof StyleguideConfig.prototype.rules) {
const ruleset = {
...rules.oas2,
...rules.oas3_0,
...rules.oas3_0,
};
if (isEmptyObject(ruleset)) {
exitWithError(
'⚠️ No rules were configured. Learn how to configure rules: https://redocly.com/docs/cli/rules/'
);
}
}