From 3baba292bd4f318b88299d6de9b75d021b508ace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Tue, 6 Jul 2021 20:52:39 +0200 Subject: [PATCH] feat(cli): demand some ruleset to be present (#1699) --- .../cli/src/services/__tests__/linter.test.ts | 17 ++++++++++++++--- .../cli/src/services/linter/utils/getRuleset.ts | 4 +++- packages/core/src/__tests__/linter.test.ts | 14 ++++++++++++++ packages/core/src/__tests__/spectral.test.ts | 2 ++ packages/core/src/spectral.ts | 6 +++++- .../fail-on-unmatched-glob-patterns.scenario | 6 +++++- test-harness/scenarios/no-ruleset.scenario | 10 ++++++++++ test-harness/scenarios/proxy-agent.scenario | 6 +++++- 8 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 test-harness/scenarios/no-ruleset.scenario diff --git a/packages/cli/src/services/__tests__/linter.test.ts b/packages/cli/src/services/__tests__/linter.test.ts index 17c7d8159..e3e63230b 100644 --- a/packages/cli/src/services/__tests__/linter.test.ts +++ b/packages/cli/src/services/__tests__/linter.test.ts @@ -30,18 +30,22 @@ async function run(command: string) { describe('Linter service', () => { let consoleLogSpy: jest.SpyInstance; + let consoleErrorSpy: jest.SpyInstance; let processCwdSpy: jest.SpyInstance; beforeEach(() => { - consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { - // no-op - }); + const noop = () => { + /* no-op */ + }; + consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(noop); + consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(noop); processCwdSpy = jest.spyOn(process, 'cwd').mockReturnValue(join(__dirname, '__fixtures__')); }); afterEach(() => { consoleLogSpy.mockRestore(); + consoleErrorSpy.mockRestore(); processCwdSpy.mockRestore(); nock.cleanAll(); @@ -88,6 +92,13 @@ describe('Linter service', () => { ]); }); + it('demands some ruleset to be present', () => { + processCwdSpy.mockReturnValue(join(__dirname, '__fixtures__/resolver')); + return expect(run(`lint stoplight-info-document.json`)).rejects.toThrow( + 'No ruleset has been found. Please provide a ruleset using the --ruleset CLI argument, or make sure your ruleset file matches .?spectral.(js|ya?ml|json)', + ); + }); + describe('when document is local file', () => { describe('and the file is expected to have no warnings', () => { it('outputs no issues', () => { diff --git a/packages/cli/src/services/linter/utils/getRuleset.ts b/packages/cli/src/services/linter/utils/getRuleset.ts index 3a7dbcf7a..b2e4e6b3e 100644 --- a/packages/cli/src/services/linter/utils/getRuleset.ts +++ b/packages/cli/src/services/linter/utils/getRuleset.ts @@ -28,7 +28,9 @@ export async function getRuleset(rulesetFile: Optional): Promise { spectral = new Spectral(); }); + test('should demand some result', () => { + return expect(spectral.run(new Document('123', Parsers.Json))).rejects.toThrow( + 'No ruleset has been defined. Have you called setRuleset()?', + ); + }); + test('should not throw if passed in value is not an object', () => { spectral.setRuleset({ rules: { @@ -511,6 +517,7 @@ responses:: !!foo description: c `; + spectral.setRuleset({ rules: {} }); const result = await spectral.run(responses, { ignoreUnknownFormat: true }); expect(result).toEqual( @@ -599,6 +606,7 @@ responses:: !!foo }); test('should report invalid schema $refs', async () => { + spectral.setRuleset({ rules: {} }); const result = await spectral.run( JSON.stringify( { @@ -636,6 +644,8 @@ responses:: !!foo test('should report when a resolver is no t defined for a given $ref type', async () => { const s = new Spectral({ resolver: new Resolver() }); + s.setRuleset(new Ruleset({ rules: {} })); + const document = JSON.stringify({ 'file-refs': [{ $ref: './models/pet.yaml' }, { $ref: '../common/models/error.yaml' }], }); @@ -660,6 +670,7 @@ responses:: !!foo describe('reports duplicated properties for', () => { test('JSON format', async () => { + spectral.setRuleset({ rules: {} }); const result = await spectral.run('{"foo":true,"foo":false}', { ignoreUnknownFormat: true, }); @@ -685,6 +696,7 @@ responses:: !!foo }); test('YAML format', async () => { + spectral.setRuleset({ rules: {} }); const result = await spectral.run(`foo: bar\nfoo: baz`, { ignoreUnknownFormat: true, }); @@ -711,6 +723,7 @@ responses:: !!foo }); test('should report invalid YAML mapping keys', async () => { + spectral.setRuleset({ rules: {} }); const results = await spectral.run( `responses: 200: @@ -1221,6 +1234,7 @@ responses:: !!foo test.each(['1', 'null', '', 'false'])('given %s input, should report nothing', async input => { const s = new Spectral(); + s.setRuleset(new Ruleset({ rules: {} })); const source = '/tmp/file.yaml'; const doc = new Document(input, Parsers.Yaml, source); diff --git a/packages/core/src/__tests__/spectral.test.ts b/packages/core/src/__tests__/spectral.test.ts index 377082e20..ddd35891c 100644 --- a/packages/core/src/__tests__/spectral.test.ts +++ b/packages/core/src/__tests__/spectral.test.ts @@ -4,6 +4,7 @@ import * as Parsers from '@stoplight/spectral-parsers'; import { Resolver } from '@stoplight/spectral-ref-resolver'; import { Document } from '../document'; import { Spectral } from '../spectral'; +import { Ruleset } from '../ruleset'; describe('spectral', () => { describe('when a $ref appears', () => { @@ -19,6 +20,7 @@ describe('spectral', () => { const target = { foo: 'bar' }; + s.setRuleset(new Ruleset({ rules: {} })); await s.run(target); expect(resolve).toBeCalledWith(target, { diff --git a/packages/core/src/spectral.ts b/packages/core/src/spectral.ts index 28631c42a..90c3bf72f 100644 --- a/packages/core/src/spectral.ts +++ b/packages/core/src/spectral.ts @@ -22,7 +22,7 @@ export * from './types'; export class Spectral { private readonly _resolver: Resolver; - public ruleset: Ruleset = new Ruleset({ rules: {} }); + public ruleset?: Ruleset; protected readonly runtime: RunnerRuntime; @@ -55,6 +55,10 @@ export class Spectral { target: IParsedResult | IDocument | Record | string, opts: IRunOpts = {}, ): Promise { + if (this.ruleset === void 0) { + throw new Error('No ruleset has been defined. Have you called setRuleset()?'); + } + const document = this.parseDocument(target); const ruleset = this.ruleset.fromSource(document.source); diff --git a/test-harness/scenarios/fail-on-unmatched-glob-patterns.scenario b/test-harness/scenarios/fail-on-unmatched-glob-patterns.scenario index 37c84ce89..779872185 100644 --- a/test-harness/scenarios/fail-on-unmatched-glob-patterns.scenario +++ b/test-harness/scenarios/fail-on-unmatched-glob-patterns.scenario @@ -1,7 +1,11 @@ ====test==== Reports unmatched glob patterns +====asset:ruleset==== +module.exports = { + rules: {} +} ====command==== -{bin} lint ./*oops.{yml,yaml,json} --fail-on-unmatched-globs +{bin} lint ./*oops.{yml,yaml,json} --fail-on-unmatched-globs --ruleset {asset:ruleset} ====status==== 2 ====stderr==== diff --git a/test-harness/scenarios/no-ruleset.scenario b/test-harness/scenarios/no-ruleset.scenario new file mode 100644 index 000000000..b96fcb642 --- /dev/null +++ b/test-harness/scenarios/no-ruleset.scenario @@ -0,0 +1,10 @@ +====test==== +Ruleset is required for Spectral run linting +====document==== +type: string +====command==== +{bin} lint {document} --ignore-unknown-format +====status==== +2 +====stderr==== +No ruleset has been found. Please provide a ruleset using the --ruleset CLI argument, or make sure your ruleset file matches .?spectral.(js|ya?ml|json) diff --git a/test-harness/scenarios/proxy-agent.scenario b/test-harness/scenarios/proxy-agent.scenario index 0d93ce748..e3ce10036 100644 --- a/test-harness/scenarios/proxy-agent.scenario +++ b/test-harness/scenarios/proxy-agent.scenario @@ -5,8 +5,12 @@ foo: $ref: http://localhost:3002/foo.json#/ref ====env==== PROXY=http://localhost:3001 +====asset:ruleset==== +module.exports = { + rules: {} +} ====command==== -{bin} lint {document} --ignore-unknown-format +{bin} lint {document} --ignore-unknown-format --ruleset {asset:ruleset} ====stdout==== {document} 2:9 error invalid-ref FetchError: request to http://localhost:3002/foo.json failed, reason: connect ECONNREFUSED 127.0.0.1:3001 foo.$ref