Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): demand some ruleset to be present #1699

Merged
merged 2 commits into from
Jul 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions packages/cli/src/services/__tests__/linter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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', () => {
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/src/services/linter/utils/getRuleset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export async function getRuleset(rulesetFile: Optional<string>): Promise<Ruleset
}

if (rulesetFile === void 0) {
return new Ruleset({ rules: {} });
throw new Error(
'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)',
);
}

let ruleset;
Expand Down
14 changes: 14 additions & 0 deletions packages/core/src/__tests__/linter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ describe('linter', () => {
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: {
Expand Down Expand Up @@ -511,6 +517,7 @@ responses:: !!foo
description: c
`;

spectral.setRuleset({ rules: {} });
const result = await spectral.run(responses, { ignoreUnknownFormat: true });

expect(result).toEqual(
Expand Down Expand Up @@ -599,6 +606,7 @@ responses:: !!foo
});

test('should report invalid schema $refs', async () => {
spectral.setRuleset({ rules: {} });
const result = await spectral.run(
JSON.stringify(
{
Expand Down Expand Up @@ -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' }],
});
Expand All @@ -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,
});
Expand All @@ -685,6 +696,7 @@ responses:: !!foo
});

test('YAML format', async () => {
spectral.setRuleset({ rules: {} });
const result = await spectral.run(`foo: bar\nfoo: baz`, {
ignoreUnknownFormat: true,
});
Expand All @@ -711,6 +723,7 @@ responses:: !!foo
});

test('should report invalid YAML mapping keys', async () => {
spectral.setRuleset({ rules: {} });
const results = await spectral.run(
`responses:
200:
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/__tests__/spectral.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand All @@ -19,6 +20,7 @@ describe('spectral', () => {

const target = { foo: 'bar' };

s.setRuleset(new Ruleset({ rules: {} }));
await s.run(target);

expect(resolve).toBeCalledWith(target, {
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/spectral.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -55,6 +55,10 @@ export class Spectral {
target: IParsedResult | IDocument | Record<string, unknown> | string,
opts: IRunOpts = {},
): Promise<ISpectralFullResult> {
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);

Expand Down
Original file line number Diff line number Diff line change
@@ -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====
Expand Down
10 changes: 10 additions & 0 deletions test-harness/scenarios/no-ruleset.scenario
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 5 additions & 1 deletion test-harness/scenarios/proxy-agent.scenario
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down