mirror of
https://github.com/LukeHagar/redocly-cli.git
synced 2025-12-06 04:21:09 +00:00
fix: show error if apis or rules not provided (#1055)
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
apis:
|
||||
main:
|
||||
root: ./openapi.yaml
|
||||
|
||||
decorators:
|
||||
plugin/resolve-x: on
|
||||
plugins:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
badKey: 1
|
||||
badKey: 1
|
||||
|
||||
extends:
|
||||
- recommended
|
||||
|
||||
5
__tests__/lint/extends-empty-array/.redocly.yaml
Normal file
5
__tests__/lint/extends-empty-array/.redocly.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
apis:
|
||||
main:
|
||||
root: openapi.yaml
|
||||
|
||||
extends: []
|
||||
18
__tests__/lint/extends-empty-array/openapi.yaml
Normal file
18
__tests__/lint/extends-empty-array/openapi.yaml
Normal 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
|
||||
8
__tests__/lint/extends-empty-array/snapshot.js
Normal file
8
__tests__/lint/extends-empty-array/snapshot.js
Normal 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/
|
||||
|
||||
|
||||
`;
|
||||
@@ -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/
|
||||
|
||||
|
||||
`;
|
||||
|
||||
@@ -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/
|
||||
|
||||
|
||||
`;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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']);
|
||||
|
||||
|
||||
@@ -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/'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user