Skip to content

Commit

Permalink
Enable piping output through additional formatter for CI (#332)
Browse files Browse the repository at this point in the history
Co-authored-by: Tom Charles <tocharles@linkedin.com>
Co-authored-by: Steve Calvert <steve.calvert@gmail.com>
  • Loading branch information
3 people committed Aug 1, 2022
1 parent 47582ca commit 0e00ee6
Show file tree
Hide file tree
Showing 8 changed files with 458 additions and 2 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,14 @@ Converting errors to todos with `warn` and `error` dates that transition the `to
```bash
UPDATE_TODO='1' TODO_DAYS_TO_WARN= '' TODO_DAYS_TO_ERROR='20' eslint . --format @lint-todo/eslint-formatter-todo
```

### Additional options for formatting output

This package will only format the data in todos with the pretty format.

If you need to preserve the todo functionality while outputting in a different format for your CI system, you can set an additional environment variable, `FORMAT_TODO_AS`, which references a node module that is installed in your project.

:warning: Note that additional functionality of this formatter is not supported (i.e., `UPDATE_TODO`, etc) when using the `FORMAT_TODO_AS` flag; this flag is strictly for modifying the command line output.

```bash
FORMAT_TODO_AS=@microsoft/eslint-formatter-sarif eslint . --format @lint-todo/eslint-formatter-todo
54 changes: 54 additions & 0 deletions __tests__/acceptance/eslint-with-todo-formatter-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import '@microsoft/jest-sarif';
import stripAnsi from 'strip-ansi';
import { differenceInDays, subDays } from 'date-fns';
import {
Expand Down Expand Up @@ -1238,4 +1239,57 @@ describe('eslint with todo formatter', function () {
}
});
}

it('when given FORMAT_TODO_AS will output with that formatters format', async () => {
await project.write({
src: {
'with-errors-0.js': getStringFixture('with-errors-0.js'),
},
});

const result = await runBin({
env: {
FORMAT_TODO_AS: '@microsoft/eslint-formatter-sarif',
},
});

expect(JSON.parse(result.stdout)).toBeValidSarifLog();
});

it('when given FORMAT_TODO_AS will ensure that results provided to that formatter do not include todos', async () => {
await project.write({
src: {
'with-errors-0.js': getStringFixture('with-errors-0.js'),
},
});

let result = await runBin();

// without converting to todos, we should have errors
expect(result.stdout.match(/\s*\d*:\d*\s*error.*/g) || []).toHaveLength(7);

result = await runBin({
env: {
UPDATE_TODO: '1',
},
});

// after converting to todos, we should have no errors
expect(result.stdout.match(/\s*\d*:\d*\s*error.*/g) || []).toHaveLength(0);

result = await runBin({
env: {
FORMAT_TODO_AS: '@microsoft/eslint-formatter-sarif',
},
});

// extract errors from SARIF results, we should continue to have no errors (todos are respected with external formatter)
const potentialErrors = JSON.parse(result.stdout).runs[0].results.reduce(
(acc: string[], result: any) =>
result.level === 'error' ? [...acc, result.message.text] : acc,
[]
);

expect(potentialErrors).toHaveLength(0);
});
});
144 changes: 144 additions & 0 deletions __tests__/unit/print-results-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ function getOptions(options = {}) {
return Object.assign(
{},
{
formatTodoAs: undefined,
updateTodo: false,
includeTodo: false,
shouldCleanTodos: true,
Expand Down Expand Up @@ -141,4 +142,147 @@ describe('print-results', () => {
"
`);
});

it('should throw an error when formatTodoAs is present but the given module is not found', () => {
const results = fixtures.eslintWithErrors('/stable/path');
expect(() =>
printResults(
results,
getOptions({ formatTodoAs: '@lint-todo/not-found' })
)
).toThrow(
"Unable to find formatter `@lint-todo/not-found`. Must declare explicit dependency on package. Try 'npm install @lint-todo/not-found --save-dev' or 'yarn add @lint-todo/not-found --dev'"
);
});

it('should only include errors and warnings if formatTodoAs is specified', () => {
const formatterSpy = jest.fn().mockReturnValue('mock formatted results');
jest.mock('@lint-todo/alternate-formatter', () => formatterSpy, {
virtual: true,
});

const results = fixtures.eslintWithErrorsWarningsTodos('/stable/path');
expect(
printResults(
results,
getOptions({
formatTodoAs: '@lint-todo/alternate-formatter',
})
)
).toEqual('mock formatted results');
expect(formatterSpy).toHaveBeenCalledWith([
{
filePath: '/stable/path/app/errors-only.js',
messages: [
{
ruleId: 'no-prototype-builtins',
severity: 2,
message:
"Do not access Object.prototype method 'hasOwnProperty' from target object.",
line: 25,
column: 21,
nodeType: 'CallExpression',
messageId: 'prototypeBuildIn',
endLine: 25,
endColumn: 35,
},
{
ruleId: 'no-prototype-builtins',
severity: 2,
message:
"Do not access Object.prototype method 'hasOwnProperty' from target object.",
line: 26,
column: 19,
nodeType: 'CallExpression',
messageId: 'prototypeBuildIn',
endLine: 26,
endColumn: 33,
},
{
ruleId: 'no-prototype-builtins',
severity: 2,
message:
"Do not access Object.prototype method 'hasOwnProperty' from target object.",
line: 32,
column: 34,
nodeType: 'CallExpression',
messageId: 'prototypeBuildIn',
endLine: 32,
endColumn: 48,
},
],
errorCount: 3,
warningCount: 0,
fixableErrorCount: 0,
fixableWarningCount: 0,
source: '',
},
{
filePath: '/stable/path/app/warnings-only.js',
messages: [
{
ruleId: 'no-alert',
severity: 1,
message: 'Unexpected alert.',
line: 3,
column: 3,
nodeType: 'CallExpression',
messageId: 'unexpected',
endLine: 2,
endColumn: 14,
},
],
errorCount: 0,
warningCount: 1,
fixableErrorCount: 0,
fixableWarningCount: 0,
source: '',
},
{
filePath: '/stable/path/app/todos-only.js',
messages: [],
errorCount: 0,
warningCount: 0,
todoCount: 2,
fixableErrorCount: 0,
fixableWarningCount: 0,
source: '',
},
{
filePath: '/stable/path/app/errors-warnings-todo.js',
messages: [
{
ruleId: 'no-redeclare',
severity: 2,
message:
"'window' is already defined as a built-in global variable.",
line: 1,
column: 11,
nodeType: 'Block',
messageId: 'redeclaredAsBuiltin',
endLine: 1,
endColumn: 17,
fix: { range: [0, 1], text: '' },
},
{
ruleId: 'no-alert',
severity: 1,
message: 'Unexpected alert.',
line: 3,
column: 3,
nodeType: 'CallExpression',
messageId: 'unexpected',
endLine: 2,
endColumn: 14,
},
],
errorCount: 1,
warningCount: 1,
todoCount: 1,
fixableErrorCount: 1,
fixableWarningCount: 0,
source: '',
},
]);
});
});
Loading

0 comments on commit 0e00ee6

Please sign in to comment.