Skip to content

Commit

Permalink
feat(formatters): add GitHub Actions formatter (#2508)
Browse files Browse the repository at this point in the history
  • Loading branch information
siketyan authored and P0lip committed Jul 26, 2023
1 parent bddf82e commit 6904927
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 1 deletion.
3 changes: 2 additions & 1 deletion docs/guides/2-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ Other options include:
[string] [choices: "utf8", "ascii", "utf-8", "utf16le", "ucs2", "ucs-2", "base64", "latin1"] [default: "utf8"]
-f, --format formatters to use for outputting results, more than one can be given joining them with
a comma
[string] [choices: "json", "stylish", "junit", "html", "text", "teamcity", "pretty"] [default: "stylish"]
[string] [choices: "json", "stylish", "junit", "html", "text", "teamcity", "pretty", "github-actions"] [default:
"stylish"]
-o, --output where to output results, can be a single file name, multiple "output.<format>" or
missing to print to stdout [string]
--stdin-filepath path to a file to pretend that stdin comes from [string]
Expand Down
1 change: 1 addition & 0 deletions packages/formatters/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ console.error(output);
### Node.js only

- pretty
- github-actions
50 changes: 50 additions & 0 deletions packages/formatters/src/__tests__/github-actions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { DiagnosticSeverity } from '@stoplight/types';
import type { IRuleResult } from '@stoplight/spectral-core';
import { githubActions } from '../github-actions';

const cwd = process.cwd();
const results: IRuleResult[] = [
{
code: 'operation-description',
message: 'paths./pets.get.description is not truthy\nMessage can have\nmultiple lines',
path: ['paths', '/pets', 'get', 'description'],
severity: 1,
source: `${cwd}/__tests__/fixtures/petstore.oas2.yaml`,
range: {
start: {
line: 60,
character: 8,
},
end: {
line: 71,
character: 60,
},
},
},
{
code: 'operation-tags',
message: 'paths./pets.get.tags is not truthy',
path: ['paths', '/pets', 'get', 'tags'],
severity: 1,
source: `${cwd}/__tests__/fixtures/petstore.oas2.yaml`,
range: {
start: {
line: 60,
character: 8,
},
end: {
line: 71,
character: 60,
},
},
},
];

describe('GitHub Actions formatter', () => {
test('should be formatted correctly', () => {
expect(githubActions(results, { failSeverity: DiagnosticSeverity.Error }).split('\n')).toEqual([
'::warning title=operation-description,file=__tests__/fixtures/petstore.oas2.yaml,col=9,endColumn=61,line=61,endLine=72::paths./pets.get.description is not truthy%0AMessage can have%0Amultiple lines',
'::warning title=operation-tags,file=__tests__/fixtures/petstore.oas2.yaml,col=9,endColumn=61,line=61,endLine=72::paths./pets.get.tags is not truthy',
]);
});
});
47 changes: 47 additions & 0 deletions packages/formatters/src/github-actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { relative } from '@stoplight/path';
import { DiagnosticSeverity, Dictionary } from '@stoplight/types';
import { Formatter } from './types';

const OUTPUT_TYPES: Dictionary<string, DiagnosticSeverity> = {
[DiagnosticSeverity.Error]: 'error',
[DiagnosticSeverity.Warning]: 'warning',
[DiagnosticSeverity.Information]: 'notice',
[DiagnosticSeverity.Hint]: 'notice',
};

type OutputParams = {
title?: string;
file: string;
col?: number;
endColumn?: number;
line?: number;
endLine?: number;
};

export const githubActions: Formatter = results => {
return results
.map(result => {
// GitHub Actions requires relative path for annotations, determining from working directory here
const file = relative(process.cwd(), result.source ?? '');
const params: OutputParams = {
title: result.code.toString(),
file,
col: result.range.start.character + 1,
endColumn: result.range.end.character + 1,
line: result.range.start.line + 1,
endLine: result.range.end.line + 1,
};

const paramsString = Object.entries(params)
.map(p => p.join('='))
.join(',');

// As annotated messages must be one-line due to GitHub's limitation, replacing all LF to %0A here.
// see: https://github.com/actions/toolkit/issues/193
// FIXME: Use replaceAll instead after removing Node.js 14 support.
const message = result.message.replace(/\n/g, '%0A');

return `::${OUTPUT_TYPES[result.severity]} ${paramsString}::${message}`;
})
.join('\n');
};
1 change: 1 addition & 0 deletions packages/formatters/src/index.node.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { html, json, junit, text, stylish, teamcity } from './index';
export type { Formatter, FormatterOptions } from './index';
export { pretty } from './pretty';
export { githubActions } from './github-actions';
4 changes: 4 additions & 0 deletions packages/formatters/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ export type { Formatter, FormatterOptions } from './types';
export const pretty: Formatter = () => {
throw Error('pretty formatter is available only in Node.js');
};

export const githubActions: Formatter = () => {
throw Error('github-actions formatter is available only in Node.js');
};

0 comments on commit 6904927

Please sign in to comment.