mirror of
https://github.com/LukeHagar/redocly-cli.git
synced 2025-12-09 20:57:44 +00:00
feat: add markdown output format for lint command (#1559)
* feat: Add markdown output format for lint command * feat: Tweak output and add a test * fix: send markdown output to stdout to match existing json/checkstyle behaviour * fix: Update snapshots * fix: Check error count to determine success * docs: Add markdown format docs to lint command page * chore: Add changeset * Apply suggestions from code review Co-authored-by: Heather Cloward <heathercloward@gmail.com> * docs: Update from review feedback * fix: Add missing image, run prettier * fix: Update test to match corrected code behaviour --------- Co-authored-by: Heather Cloward <heathercloward@gmail.com>
This commit is contained in:
committed by
GitHub
parent
dbbbad889c
commit
546d482b03
6
.changeset/bright-garlics-flash.md
Normal file
6
.changeset/bright-garlics-flash.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@redocly/openapi-core": minor
|
||||||
|
"@redocly/cli": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Added support for the linting command to output markdown format.
|
||||||
@@ -14,7 +14,7 @@ Options:
|
|||||||
--help Show help. [boolean]
|
--help Show help. [boolean]
|
||||||
--format Use a specific output format.
|
--format Use a specific output format.
|
||||||
[choices: "stylish", "codeframe", "json", "checkstyle", "codeclimate",
|
[choices: "stylish", "codeframe", "json", "checkstyle", "codeclimate",
|
||||||
"summary", "github-actions"] [default: "codeframe"]
|
"summary", "markdown", "github-actions"] [default: "codeframe"]
|
||||||
--max-problems Reduce output to a maximum of N problems.
|
--max-problems Reduce output to a maximum of N problems.
|
||||||
[number] [default: 100]
|
[number] [default: 100]
|
||||||
--generate-ignore-file Generate an ignore file. [boolean]
|
--generate-ignore-file Generate an ignore file. [boolean]
|
||||||
|
|||||||
BIN
docs/commands/images/lint-markdown.png
Normal file
BIN
docs/commands/images/lint-markdown.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
@@ -22,19 +22,19 @@ redocly lint --version
|
|||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
| Option | Type | Description |
|
| Option | Type | Description |
|
||||||
| ---------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| ---------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| apis | [string] | Array of API description filenames that need to be linted. See [the Apis section](#apis) for more options. |
|
| apis | [string] | Array of API description filenames that need to be linted. See [the Apis section](#apis) for more options. |
|
||||||
| --config | string | Specify path to the [configuration file](#custom-configuration-file). |
|
| --config | string | Specify path to the [configuration file](#custom-configuration-file). |
|
||||||
| --extends | [string] | [Extend a specific configuration](#extend-configuration) (defaults or config file settings). |
|
| --extends | [string] | [Extend a specific configuration](#extend-configuration) (defaults or config file settings). |
|
||||||
| --format | string | Format for the output.<br />**Possible values:** `codeframe`, `stylish`, `json`, `checkstyle`, `codeclimate`, `github-actions`, `summary`. Default value is `codeframe`. |
|
| --format | string | Format for the output.<br />**Possible values:** `codeframe`, `stylish`, `json`, `checkstyle`, `codeclimate`, `github-actions`, `markdown`, `summary`. Default value is `codeframe`. |
|
||||||
| --generate-ignore-file | boolean | [Generate ignore file](#generate-ignore-file). |
|
| --generate-ignore-file | boolean | [Generate ignore file](#generate-ignore-file). |
|
||||||
| --help | boolean | Show help. |
|
| --help | boolean | Show help. |
|
||||||
| --lint-config | string | Specify the severity level for the configuration file. <br/> **Possible values:** `warn`, `error`, `off`. Default value is `warn`. |
|
| --lint-config | string | Specify the severity level for the configuration file. <br/> **Possible values:** `warn`, `error`, `off`. Default value is `warn`. |
|
||||||
| --max-problems | integer | Truncate output to display the specified [maximum number of problems](#max-problems). Default value is 100. |
|
| --max-problems | integer | Truncate output to display the specified [maximum number of problems](#max-problems). Default value is 100. |
|
||||||
| --skip-preprocessor | [string] | Ignore certain preprocessors. See the [Skip preprocessor or rule section](#skip-preprocessor-or-rule) below. |
|
| --skip-preprocessor | [string] | Ignore certain preprocessors. See the [Skip preprocessor or rule section](#skip-preprocessor-or-rule) below. |
|
||||||
| --skip-rule | [string] | Ignore certain rules. See the [Skip preprocessor or rule section](#skip-preprocessor-or-rule) below. |
|
| --skip-rule | [string] | Ignore certain rules. See the [Skip preprocessor or rule section](#skip-preprocessor-or-rule) below. |
|
||||||
| --version | boolean | Show version number. |
|
| --version | boolean | Show version number. |
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@@ -239,6 +239,30 @@ Use `redocly lint --format=github-actions` to have any encountered problem annot
|
|||||||
::warning title=operation-operationId,file=museum-with-errors.yaml,line=16,endLine=16,col=5,endColumn=5::Operation object should contain `operationId` field.
|
::warning title=operation-operationId,file=museum-with-errors.yaml,line=16,endLine=16,col=5,endColumn=5::Operation object should contain `operationId` field.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Markdown
|
||||||
|
|
||||||
|
Use `markdown` format output with the `lint` command to get a Markdown-ready output format.
|
||||||
|
This output format is useful if you want to report the outcomes to a document, or use the information in a GitHub Job Summary.
|
||||||
|
|
||||||
|
Running the `lint` command with `--format=markdown` produces output like the following example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
## Lint: ./museum-with-errors.yaml
|
||||||
|
|
||||||
|
| Severity | Location | Problem | Message |
|
||||||
|
|---|---|---|---|
|
||||||
|
| error | line 42:11 | [spec](https://redocly.com/docs/cli/rules/spec/) | Must contain at least one of the following fields: schema, content. |
|
||||||
|
| error | line 44:11 | [spec](https://redocly.com/docs/cli/rules/spec/) | Property `type` is not expected here. |
|
||||||
|
|
||||||
|
Validation failed
|
||||||
|
Errors: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
The output includes a formatted table, and links to any built-in rules that identified problems.
|
||||||
|
An example is shown in the following screenshot.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### <a id="max-problems"></a>Limit the problem count
|
### <a id="max-problems"></a>Limit the problem count
|
||||||
|
|
||||||
With the `--max-problems` option, you can limit the number of problems displayed in the command output. If the number of detected problems exceeds the specified threshold, the remaining problems are hidden under the "spoiler message" that lets you know how many problems were hidden.
|
With the `--max-problems` option, you can limit the number of problems displayed in the command output. If the number of detected problems exceeds the specified threshold, the remaining problems are hidden under the "spoiler message" that lets you know how many problems were hidden.
|
||||||
|
|||||||
@@ -408,6 +408,7 @@ yargs
|
|||||||
'checkstyle',
|
'checkstyle',
|
||||||
'codeclimate',
|
'codeclimate',
|
||||||
'summary',
|
'summary',
|
||||||
|
'markdown',
|
||||||
'github-actions',
|
'github-actions',
|
||||||
] as ReadonlyArray<OutputFormat>,
|
] as ReadonlyArray<OutputFormat>,
|
||||||
default: 'codeframe' as OutputFormat,
|
default: 'codeframe' as OutputFormat,
|
||||||
|
|||||||
@@ -107,4 +107,41 @@ describe('format', () => {
|
|||||||
'::error title=spec,file=openapi.yaml,line=1,col=2,endLine=3,endColumn=4::message\n'
|
'::error title=spec,file=openapi.yaml,line=1,col=2,endLine=3,endColumn=4::message\n'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should format problems using markdown', () => {
|
||||||
|
const problems = [
|
||||||
|
{
|
||||||
|
ruleId: 'spec',
|
||||||
|
message: 'message',
|
||||||
|
severity: 'error' as const,
|
||||||
|
location: [
|
||||||
|
{
|
||||||
|
source: { absoluteRef: 'openapi.yaml' } as Source,
|
||||||
|
start: { line: 1, col: 2 },
|
||||||
|
end: { line: 3, col: 4 },
|
||||||
|
} as LocationObject,
|
||||||
|
],
|
||||||
|
suggest: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
formatProblems(problems, {
|
||||||
|
format: 'markdown',
|
||||||
|
version: '1.0.0',
|
||||||
|
totals: getTotals(problems),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(output).toMatchInlineSnapshot(`
|
||||||
|
"## Lint: openapi.yaml
|
||||||
|
|
||||||
|
| Severity | Location | Problem | Message |
|
||||||
|
|---|---|---|---|
|
||||||
|
| error | line 1:2 | [spec](https://redocly.com/docs/cli/rules/spec/) | message |
|
||||||
|
|
||||||
|
Validation failed
|
||||||
|
Errors: 1
|
||||||
|
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -134,6 +134,33 @@ export function formatProblems(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'markdown': {
|
||||||
|
const groupedByFile = groupByFiles(problems);
|
||||||
|
for (const [file, { fileProblems }] of Object.entries(groupedByFile)) {
|
||||||
|
output.write(`## Lint: ${isAbsoluteUrl(file) ? file : path.relative(cwd, file)}\n\n`);
|
||||||
|
|
||||||
|
output.write(`| Severity | Location | Problem | Message |\n`);
|
||||||
|
output.write(`|---|---|---|---|\n`);
|
||||||
|
for (let i = 0; i < fileProblems.length; i++) {
|
||||||
|
const problem = fileProblems[i];
|
||||||
|
output.write(`${formatMarkdown(problem)}\n`);
|
||||||
|
}
|
||||||
|
output.write('\n');
|
||||||
|
|
||||||
|
if (totals.errors > 0) {
|
||||||
|
output.write(`Validation failed\nErrors: ${totals.errors}\n`);
|
||||||
|
} else {
|
||||||
|
output.write('Validation successful\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totals.warnings > 0) {
|
||||||
|
output.write(`Warnings: ${totals.warnings}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.write('\n');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'checkstyle': {
|
case 'checkstyle': {
|
||||||
const groupedByFile = groupByFiles(problems);
|
const groupedByFile = groupByFiles(problems);
|
||||||
|
|
||||||
@@ -270,6 +297,17 @@ export function formatProblems(
|
|||||||
)} ${severityName} ${problem.ruleId.padEnd(ruleIdPad)} ${problem.message}`;
|
)} ${severityName} ${problem.ruleId.padEnd(ruleIdPad)} ${problem.message}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatMarkdown(problem: OnlyLineColProblem) {
|
||||||
|
if (!SEVERITY_NAMES[problem.severity]) {
|
||||||
|
return 'Error not found severity. Please check your config file. Allowed values: `warn,error,off`';
|
||||||
|
}
|
||||||
|
const severityName = SEVERITY_NAMES[problem.severity].toLowerCase();
|
||||||
|
const { start } = problem.location[0];
|
||||||
|
return `| ${severityName} | line ${`${start.line}:${start.col}`} | [${
|
||||||
|
problem.ruleId
|
||||||
|
}](https://redocly.com/docs/cli/rules/${problem.ruleId}/) | ${problem.message} |`;
|
||||||
|
}
|
||||||
|
|
||||||
function formatCheckstyle(problem: OnlyLineColProblem) {
|
function formatCheckstyle(problem: OnlyLineColProblem) {
|
||||||
const { line, col } = problem.location[0].start;
|
const { line, col } = problem.location[0].start;
|
||||||
const severity = problem.severity == 'warn' ? 'warning' : 'error';
|
const severity = problem.severity == 'warn' ? 'warning' : 'error';
|
||||||
|
|||||||
Reference in New Issue
Block a user