Skip to content

Commit

Permalink
Draft: feat(codeclimate): outputFormat for CodeClimate (IBM#512)
Browse files Browse the repository at this point in the history
Signed-off-by: Matthias Blümel <[email protected]>
  • Loading branch information
Blaimi committed May 25, 2023
1 parent 52f1c2a commit e38dad8
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 8 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ The IBM OpenAPI Validator lets you validate OpenAPI 3.x documents according to t
- [Validator Output](#validator-output)
* [Text](#text)
* [JSON](#json)
* [CodeClimate](#codeclimate)
- [Logging](#logging)
- [Contributing](#contributing)
- [License](#license)
Expand Down Expand Up @@ -115,6 +116,7 @@ Options:
-e, --errors-only include only errors in the output and skip warnings (default is false)
-i, --ignore <file> avoid validating <file> (e.g. -i /dir1/ignore-file1.json --ignore /dir2/ignore-file2.yaml ...) (default is []) (default: [])
-j, --json produce JSON output (default is text)
--codeclimate produce JSON output according to CodeClimate spec
-l, --log-level <loglevel> set the log level for one or more loggers (e.g. -l root=info -l ibm-schema-description-exists=debug ...) (default: [])
-n, --no-colors disable colorizing of the output (default is false)
-r, --ruleset <file> use Spectral ruleset contained in `<file>` ("default" forces use of default IBM Cloud Validation Ruleset)
Expand Down Expand Up @@ -482,9 +484,9 @@ module.exports = {
<td width=25%><b>Default</b></td>
</tr>
<tr>
<td>You can set the <code>outputFormat</code> configuration property to either <code>text</code> or <code>json</code>
<td>You can set the <code>outputFormat</code> configuration property to either <code>text</code>, <code>json</code> or <code>codeclimate</code>
to indicate the type of output you want the validator to produce.
This property corresponds to the <code>-j</code>/<code>--json</code> command-line option.</td>
This property corresponds to the <code>-j</code>/<code>--json</code>/<code>--codeclimate</code> command-line option.</td>
<td><code>text</code></td>
</tr>
</table>
Expand Down Expand Up @@ -621,7 +623,7 @@ module.exports = {

## Validator Output
The validator can produce output in either text or JSON format. The default is `text` output, and this can be
controlled with the `-j`/`--json` command-line option or `outputFormat` configuration property.
controlled with the `-j`/`--json`/`--codeclimate` command-line option or `outputFormat` configuration property.

### Text
Here is an example of text output:
Expand Down Expand Up @@ -753,6 +755,10 @@ Here is an example of JSON output:
The JSON output is also affected by the `-s`/`--summary-only` and `-e`/`--errors-only` options as well as the `summaryOnly` and `errorsOnly`
configuration properties.

### CodeClimate
When displaying CodeClimate JSON output, the validator will produce a null-byte separated stream of JSON objects
which complies with [the CodeClimate Output format](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#output).

## Logging
The validator uses a *logger* for displaying messages on the console.
The core validator uses a single logger named `root`, while each of the rules contained in the
Expand Down
13 changes: 8 additions & 5 deletions packages/validator/src/cli-validator/run-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const ext = require('./utils/file-extension-validator');
const preprocessFile = require('./utils/preprocess-file');
const print = require('./utils/print-results');
const { printJson } = require('./utils/json-results');
const { printCCJson } = require('./utils/codeclimate-results');
const { runSpectral } = require('../spectral/spectral-validator');
const getCopyrightString = require('./utils/get-copyright-string');

Expand Down Expand Up @@ -72,7 +73,7 @@ async function runValidator(cliArgs, parseOptions = {}) {

context.chalk = chalk;

if (context.config.outputFormat !== 'json') {
if (context.config.outputFormat === 'text') {
console.log(getCopyrightString());
}

Expand Down Expand Up @@ -157,7 +158,7 @@ async function runValidator(cliArgs, parseOptions = {}) {
let originalFile;
let input;

if (context.config.outputFormat != 'json') {
if (context.config.outputFormat === 'text') {
console.log('');
console.log(chalk.underline(`Validation Results for ${validFile}:\n`));
}
Expand Down Expand Up @@ -202,15 +203,15 @@ async function runValidator(cliArgs, parseOptions = {}) {

// Check to see if we should be passing back a non-zero exit code.
if (results.error.summary.total) {
// If we have any errors, then exit code 1 is returned.
exitCode = 1;
// If we have any errors, then exit code 1 is returned, except when running for codeclimate.
exitCode = context.config.outputFormat === 'codeclimate' ? 0 : 1;
}

// If the # of warnings exceeded the warnings limit, then this is an error.
const numWarnings = results.warning.summary.total;
const warningsLimit = context.config.limits.warnings;
if (warningsLimit >= 0 && numWarnings > warningsLimit) {
exitCode = 1;
exitCode = context.config.outputFormat === 'codeclimate' ? 0 : 1;
logger.error(
`Number of warnings (${numWarnings}) exceeds warnings limit (${warningsLimit}).`
);
Expand All @@ -219,6 +220,8 @@ async function runValidator(cliArgs, parseOptions = {}) {
// Now print the results, either JSON or text.
if (context.config.outputFormat === 'json') {
printJson(context, results);
} else if (context.config.outputFormat === 'codeclimate') {
printCCJson(validFile, results);
} else {
if (results.hasResults) {
print(context, results);
Expand Down
1 change: 1 addition & 0 deletions packages/validator/src/cli-validator/utils/cli-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ function createCLIOptions() {
[]
)
.option('-j, --json', 'produce JSON output (default is text)')
.option('--codeclimate', 'produce JSON output according to CodeClimate spec')
.option(
'-l, --log-level <loglevel>',
'set the log level for one or more loggers (e.g. -l root=info -l ibm-schema-description-exists=debug ...) ',
Expand Down
47 changes: 47 additions & 0 deletions packages/validator/src/cli-validator/utils/codeclimate-results.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright 2023 IBM Corporation, Matthias Blümel.
* SPDX-License-Identifier: Apache2.0
*/

const each = require('lodash/each');

function printCCJson(validFile, results) {
const types = ['error', 'warning', 'info', 'hint'];
const ccTypeMap = {
error: 'critical',
warning: 'major',
info: 'minor',
hint: 'info',
};

types.forEach(type => {
each(results[type].results, result => {
let content;
if (result.path.length !== 0) {
let markdown = '';
each(result.path, pathItem => {
markdown += '* ' + pathItem + '\n';
});
content = { body: markdown };
}
const ccResult = {
type: 'issue',
check_name: result.rule,
description: result.message,
content: content,
categories: ['Style'], // required by codeclimate, ignored by gitlab; has to be defined by the rule.
location: {
path: validFile,
lines: {
begin: result.line,
end: result.line,
},
},
severity: ccTypeMap[type],
};
console.log(JSON.stringify(ccResult) + '\0\n');
});
});
}

module.exports.printCCJson = printCCJson;
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ async function processArgs(args, cliParseOptions) {
configObj.outputFormat = 'json';
}

if ('codeclimate' in opts) {
configObj.outputFormat = 'codeclimate';
}

if ('ruleset' in opts) {
configObj.ruleset = opts.ruleset;
}
Expand Down
1 change: 1 addition & 0 deletions packages/validator/src/schemas/config-file.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ properties:
type: string
enum:
- json
- codeclimate
- text
default: text
ruleset:
Expand Down

0 comments on commit e38dad8

Please sign in to comment.