From 37863a801fb004b56112cee02b9456aa4dd31d03 Mon Sep 17 00:00:00 2001 From: SimeonC <1085899+SimeonC@users.noreply.github.com> Date: Fri, 28 Jul 2023 14:33:57 +0900 Subject: [PATCH] feat(commitlint-config): add junit formatter Old package was deprecated so we are adding a new one forked into the repo --- packages/commitlint-config/README.stories.mdx | 8 + .../commitlint-config/formatters/junit.js | 159 ++++++++++++++++++ packages/commitlint-config/package.json | 8 + 3 files changed, 175 insertions(+) create mode 100644 packages/commitlint-config/formatters/junit.js diff --git a/packages/commitlint-config/README.stories.mdx b/packages/commitlint-config/README.stories.mdx index b34e0853..17521600 100644 --- a/packages/commitlint-config/README.stories.mdx +++ b/packages/commitlint-config/README.stories.mdx @@ -5,3 +5,11 @@ import { Meta } from '@storybook/addon-docs/blocks'; ## Introduction This package is a rules preset package for [https://commitlint.js.org/](https://commitlint.js.org/). + +## Formatters + +We provide some custom formatters under the `formatters` folder. Run these by providing the `--formatter` argument to commitlint like as follows; + +```sh +npx commitlint --format @tablecheck/commitlint-config/formatters/junit +``` diff --git a/packages/commitlint-config/formatters/junit.js b/packages/commitlint-config/formatters/junit.js new file mode 100644 index 00000000..abf882dd --- /dev/null +++ b/packages/commitlint-config/formatters/junit.js @@ -0,0 +1,159 @@ +// @ts-check +/** + * Forked from archived repo - https://github.com/byCedric/Commitlint-Formats/blob/develop/packages/junit/src/junit.js + */ + +/** + * Indent the message with an indentation level. + * This will add tabs based on this level. + * + * @param {number} level + * @param {string} line + * @return {string} + */ +function indent(level, line) { + return `${' '.repeat(level)}${line}`; +} + +/** + * Escape a string to make it xml safe. + * + * @param {string | number} text + * @return {string} + */ +function escape(text) { + const characters = { + '<': '<', + '>': '>', + '&': '&', + "'": ''', + '"': '"', + }; + + return String(text).replace(/[<>&'"]/g, (char) => characters[char]); +} + +/** + * @typedef {Object} CreateElementOptions + * @property {number} [indent] + * @property {boolean} [selfClosing] + * @property {boolean} [noNewline] + */ + +/** + * Create a new XML element containing various properties. + * It can be configured to automatically add a newline, indentation and make it self closing. + * + * @param {string} tag + * @param {CreateElementOptions} options + * @param {Object} attributes + * @return {string} + */ +function createElement(tag, options, attributes) { + const element = `<${tag}`; + const closing = options.selfClosing ? ' />' : '>'; + const ending = options.noNewline ? '' : '\n'; + const properties = Object.keys(attributes) + .map((key) => `${key}="${escape(attributes[key])}"`) + .join(' '); + + return indent( + options.indent || 0, + `${element} ${properties}${closing}${ending}`, + ); +} + +/** + * Format the commitlint report as a valid JUnit XML report. + * + * @param {import('@commitlint/types').FormattableReport} report + * @return {string} + */ +function formatJunit(report = {}) { + let output = ''; + + output += indent(0, '\n'); + output += indent(0, '\n'); + + const { results = [] } = report; + + const { errorCount, warningCount, testsCount } = results.reduce( + (carry, result) => + result.input + ? carry + : { + errorCount: carry.errorCount + (result.errors?.length || 0), + warningCount: carry.warningCount + (result.warnings?.length || 0), + testsCount: + carry.testsCount + + (result.errors?.length || 0) + + (result.warnings?.length || 0), + }, + { errorCount: 0, warningCount: 0, testsCount: 0 }, + ); + + output += createElement( + 'testsuite', + { indent: 1 }, + { + name: 'commitlint', + errors: 0, + failures: errorCount + warningCount, + tests: testsCount, + }, + ); + + results.forEach((result) => { + if (!result.input) return; + const issues = [].concat(result.errors || [], result.warnings || []); + + output += createElement( + 'testsuite', + { indent: 2 }, + { + name: result.input.split('\n')[0], + errors: 0, + failures: issues.length, + tests: issues.length || 1, + }, + ); + + if (issues.length > 0) { + issues.forEach((issue) => { + const type = issue.level === 2 ? 'error' : 'warning'; + + output += createElement( + 'testcase', + { indent: 3 }, + { name: issue.name }, + ); + output += createElement( + 'failure', + { indent: 4, noNewline: true }, + { type }, + ); + output += ''; + output += '\n'; + output += indent(3, '\n'); + }); + + output += indent(2, '\n'); + } else { + output += createElement( + 'testcase', + { indent: 3, selfClosing: true }, + { name: 'valid' }, + ); + output += indent(2, '\n'); + } + }); + + output += indent(1, '\n'); + output += indent(0, '\n'); + + return output; +} + +module.exports = formatJunit; diff --git a/packages/commitlint-config/package.json b/packages/commitlint-config/package.json index 6a85ca41..7e1286b5 100644 --- a/packages/commitlint-config/package.json +++ b/packages/commitlint-config/package.json @@ -7,8 +7,16 @@ "type": "git", "url": "git@github.com:tablecheck/frontend.git" }, + "files": [ + "index.js", + "formatters" + ], "version": "1.2.0", "main": "index.js", + "exports": { + ".": "./index.js", + "./formatters/junit": "./formatters/junit.js" + }, "dependencies": { "@commitlint/config-conventional": "^17" },