Skip to content
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
name: Continuous Integration

on:
Expand Down Expand Up @@ -51,6 +51,7 @@
schema: https://gist.githubusercontent.com/dsanders11/b17fd12c00fc44b487df66d61039398e/raw/f05a9c19d6662282b1576b268e5c3228befc4700/schema.json
files: .github/workflows/ci.yml
fail-on-invalid: false
all-errors: true
- name: Test Local Action (Multiple File Valid)
id: multiple-file-valid
uses: ./
Expand All @@ -65,6 +66,7 @@
schema: https://gist.githubusercontent.com/dsanders11/b17fd12c00fc44b487df66d61039398e/raw/f05a9c19d6662282b1576b268e5c3228befc4700/schema.json
files: .github/workflows/**.yml
fail-on-invalid: false
all-errors: true
- name: Confirm Output
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
fi
- name: Validate workflows
if: steps.check-for-changed-workflows.outputs.any_changed == 'true'
uses: dsanders11/json-schema-validate-action@1.2.1
uses: dsanders11/json-schema-validate-action@v1.3.0
with:
schema: https://json.schemastore.org/github-workflow.json
files: .github/workflows/**.yml
Expand All @@ -54,6 +54,8 @@ simply set a URL fragment (e.g. `#bust-cache`) on the schema URL.
(default: `true`)
- `cache-remote-schema` - Whether or not to cache the schema if remote (default:
`true`)
- `all-errors` - Whether to report all errors or stop after the first (default:
`false`)

### Outputs

Expand Down
21 changes: 21 additions & 0 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ describe('action', () => {
expect(runSpy).toHaveReturned();
expect(process.exitCode).not.toBeDefined();

expect(core.error).toHaveBeenCalledTimes(2);
expect(core.setOutput).toHaveBeenCalledTimes(1);
expect(core.setOutput).toHaveBeenLastCalledWith('valid', false);
});
Expand Down Expand Up @@ -453,6 +454,26 @@ describe('action', () => {
expect(core.setOutput).toHaveBeenLastCalledWith('valid', true);
});

it('reports all errors if all-errors input is true', async () => {
mockGetBooleanInput({ 'all-errors': true, 'fail-on-invalid': false });
mockGetInput({ schema });
mockGetMultilineInput({ files });

vi.mocked(fs.readFile)
.mockResolvedValueOnce(schemaContents)
.mockResolvedValueOnce('invalid content')
.mockResolvedValueOnce(instanceContents);
mockGlobGenerator(['/foo/bar/baz/config.yml', '/foo/bar/baz/e/config.yml']);

await main.run();
expect(runSpy).toHaveReturned();
expect(process.exitCode).not.toBeDefined();

expect(core.error).toHaveBeenCalledTimes(4);
expect(core.setOutput).toHaveBeenCalledTimes(1);
expect(core.setOutput).toHaveBeenLastCalledWith('valid', false);
});

describe('can validate schemas', () => {
beforeEach(() => {
mockGetBooleanInput({});
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ inputs:
description: Whether or not to cache the schema if remote
required: false
default: true
all-errors:
description: Report all errors instead of stopping at the first
required: false
default: false

outputs:
valid:
Expand Down
13 changes: 7 additions & 6 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 8 additions & 7 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@ import * as core from '@actions/core';
import * as glob from '@actions/glob';
import * as http from '@actions/http-client';

import type { default as Ajv, ErrorObject } from 'ajv';
import type { default as Ajv, ErrorObject, Options } from 'ajv';
import { default as Ajv2019 } from 'ajv/dist/2019';
import { default as Ajv2020 } from 'ajv/dist/2020';
import AjvDraft04 from 'ajv-draft-04';
import AjvFormats from 'ajv-formats';
import * as yaml from 'yaml';

function newAjv(schema: Record<string, unknown>): Ajv {
function newAjv(schema: Record<string, unknown>, options: Options): Ajv {
const draft04Schema =
schema.$schema === 'http://json-schema.org/draft-04/schema#';
const draft2020Schema =
schema.$schema === 'https://json-schema.org/draft/2020-12/schema';

const ajv = AjvFormats(
draft04Schema
? new AjvDraft04()
? new AjvDraft04(options)
: draft2020Schema
? new Ajv2020()
: new Ajv2019()
? new Ajv2020(options)
: new Ajv2019(options)
);

if (!draft04Schema && !draft2020Schema) {
Expand All @@ -46,6 +46,7 @@ export async function run(): Promise<void> {
try {
let schemaPath = core.getInput('schema', { required: true });
const files = core.getMultilineInput('files', { required: true });
const allErrors = core.getBooleanInput('all-errors');
const cacheRemoteSchema = core.getBooleanInput('cache-remote-schema');
const failOnInvalid = core.getBooleanInput('fail-on-invalid');

Expand Down Expand Up @@ -108,7 +109,7 @@ export async function run(): Promise<void> {
validate = async (data: Record<string, unknown>) => {
// Create a new Ajv instance per-schema since
// they may require different draft versions
const ajv = newAjv(data);
const ajv = newAjv(data, { allErrors });

await ajv.validateSchema(data);
return ajv.errors || [];
Expand All @@ -129,7 +130,7 @@ export async function run(): Promise<void> {
return;
}

const ajv = newAjv(schema);
const ajv = newAjv(schema, { allErrors });

validate = async (data: object) => {
ajv.validate(schema, data);
Expand Down
Loading