eslint-formatter-gitlab 5.1.0 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,22 +1,26 @@
1
1
  # ESLint Formatter for GitLab
2
2
 
3
+ [![gitlab pipeline](https://gitlab.com/remcohaszing/eslint-formatter-gitlab/badges/main/pipeline.svg)](https://gitlab.com/remcohaszing/eslint-formatter-gitlab/-/pipelines)
4
+ [![code coverage](https://gitlab.com/remcohaszing/eslint-formatter-gitlab/badges/main/coverage.svg)](https://gitlab.com/remcohaszing/eslint-formatter-gitlab/-/pipelines)
5
+ [![sponsors](https://img.shields.io/github/sponsors/remcohaszing)](https://github.com/sponsors/remcohaszing)
6
+ [![npm version](https://img.shields.io/npm/v/eslint-formatter-gitlab)](https://www.npmjs.com/package/eslint-formatter-gitlab)
7
+ [![npm downloads](https://img.shields.io/npm/dm/eslint-formatter-gitlab)](https://www.npmjs.com/package/eslint-formatter-gitlab)
8
+
9
+ <img alt="" height="256" src="https://gitlab.com/remcohaszing/eslint-formatter-gitlab/-/avatar">
10
+
3
11
  Show ESLint results directly in the
4
- [GitLab code quality](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html)
5
- results.
12
+ [GitLab code quality](https://docs.gitlab.com/ee/ci/testing/code_quality.html) results.
6
13
 
7
14
  ## Table of Contents
8
15
 
9
- - [Requirements](#requirements)
10
16
  - [Installation](#installation)
11
17
  - [Usage](#usage)
18
+ - [Programmatic usage](#programmatic-usage)
12
19
  - [Example](#example)
13
20
  - [Configuration](#configuration)
21
+ - [Compatibility](#compatibility)
14
22
  - [License](#license)
15
23
 
16
- ## Requirements
17
-
18
- This package requires at least Node.js 18 and ESLint 5.
19
-
20
24
  ## Installation
21
25
 
22
26
  Install `eslint` and `eslint-formatter-gitlab` using your package manager.
@@ -29,21 +33,35 @@ npm install --save-dev eslint eslint-formatter-gitlab
29
33
 
30
34
  Define a GitLab job to run `eslint`.
31
35
 
32
- _.gitlab-ci.yml_:
36
+ `.gitlab-ci.yml`:
33
37
 
34
38
  ```yaml
35
39
  eslint:
36
- image: node:20-alpine
40
+ image: node:22-alpine
37
41
  script:
38
42
  - npm ci
39
- - npx eslint --format gitlab .
43
+ - npx eslint --format gitlab
40
44
  artifacts:
41
45
  reports:
42
46
  codequality: gl-codequality.json
43
47
  ```
44
48
 
45
49
  The formatter automatically detects a GitLab CI environment. It detects where to output the code
46
- quality report based on the GitLab configuration file.
50
+ quality report based on the GitLab configuration file. It also prints ESLint issues to the GitLab
51
+ job console with links.
52
+
53
+ ### Programmatic usage
54
+
55
+ The formatter can be used programmatically using ESLint.
56
+
57
+ ```js
58
+ import { ESLint } from 'eslint'
59
+
60
+ const eslint = new ESLint()
61
+ const formatter = await eslint.loadFormatter('gitlab')
62
+ const results = await eslint.lintFiles([])
63
+ const formatted = await formatter.format(results)
64
+ ```
47
65
 
48
66
  ## Example
49
67
 
@@ -55,8 +73,20 @@ An example of the results can be seen in
55
73
 
56
74
  ESLint formatters don’t take any configuration options. `eslint-formatter-gitlab` uses GitLab’s
57
75
  [predefined environment variables](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)
58
- to configure the output. In addition, the environment variable `ESLINT_CODE_QUALITY_REPORT` is used
59
- to override the location to store the code quality report.
76
+ to configure the output. The following predefined environment variables are used:
77
+
78
+ - `CI_COMMIT_SHORT_SHA` to generate a link in the console output.
79
+ - `CI_CONFIG_PATH` to determine the GitLab CI configuration file to use. (Default: `.gitlab-ci.yml`)
80
+ - `CI_JOB_NAME` to determine which job configuration to read the code quality report path from.
81
+ - `CI_PROJECT_DIR` To determine relative paths. (Default: current working directory)
82
+ - `CI_PROJECT_URL` to generate a link in the console output.
83
+
84
+ In addition, the environment variable `ESLINT_CODE_QUALITY_REPORT` is used to override the location
85
+ to store the code quality report.
86
+
87
+ ## Compatibility
88
+
89
+ This package is compatible with Node.js 20 or greater and ESLint 9 or greater.
60
90
 
61
91
  ## License
62
92
 
@@ -0,0 +1,173 @@
1
+ /**
2
+ * @import { ESLint } from 'eslint'
3
+ */
4
+
5
+ import { mkdir, readFile, writeFile } from 'node:fs/promises'
6
+ import { dirname, join, relative, resolve } from 'node:path'
7
+ import { styleText } from 'node:util'
8
+
9
+ import { toCodeClimate } from 'eslint-formatter-codeclimate'
10
+ import yaml from 'yaml'
11
+
12
+ /** @type {yaml.CollectionTag} */
13
+ const reference = {
14
+ tag: '!reference',
15
+ collection: 'seq',
16
+ default: false,
17
+ resolve() {
18
+ // We only allow the syntax. We don’t actually resolve the reference.
19
+ }
20
+ }
21
+
22
+ /**
23
+ * @param {string} projectDir
24
+ * The GitLab project directory.
25
+ * @param {string | undefined} jobName
26
+ * The GitLab CI job name.
27
+ * @returns {Promise<string>}
28
+ * The output path of the code quality artifact.
29
+ */
30
+ async function getOutputPath(projectDir, jobName) {
31
+ const configPath = join(projectDir, process.env.CI_CONFIG_PATH ?? '.gitlab-ci.yml')
32
+ // GitlabCI allows a custom configuration path which can be a URL or a path relative to another
33
+ // project. In these cases CI_CONFIG_PATH is empty and we'll have to require the user provide
34
+ // ESLINT_CODE_QUALITY_REPORT.
35
+ let configContents
36
+ try {
37
+ configContents = await readFile(configPath, 'utf8')
38
+ } catch {
39
+ throw new Error(
40
+ 'Could not resolve .gitlab-ci.yml to automatically detect report artifact path.' +
41
+ ' Please manually provide a path via the ESLINT_CODE_QUALITY_REPORT variable.'
42
+ )
43
+ }
44
+ const doc = yaml.parseDocument(configContents, {
45
+ version: '1.1',
46
+ customTags: [reference]
47
+ })
48
+ const path = [jobName, 'artifacts', 'reports', 'codequality']
49
+ const location = doc.getIn(path)
50
+ if (typeof location !== 'string' || !location) {
51
+ throw new TypeError(
52
+ `Expected ${path.join('.')} to be one exact path, got: ${JSON.stringify(location)}`
53
+ )
54
+ }
55
+ return resolve(projectDir, location)
56
+ }
57
+
58
+ /**
59
+ * Make a text singular or plural based on the count.
60
+ *
61
+ * @param {number} count
62
+ * The count of the data.
63
+ * @param {string} text
64
+ * The text to make singular or plural.
65
+ * @returns {string}
66
+ * The formatted text.
67
+ */
68
+ function plural(count, text) {
69
+ return `${count} ${text}${count === 1 ? '' : 's'}`
70
+ }
71
+
72
+ /**
73
+ * @param {ESLint.LintResult[]} results
74
+ * The ESLint report results.
75
+ * @param {string} projectDir
76
+ * The GitLab project directory.
77
+ * @returns {string}
78
+ * The ESLint messages converted to a format suitable as output in GitLab CI job logs.
79
+ */
80
+ function gitlabConsoleFormatter(results, projectDir) {
81
+ // Severity labels manually padded to have equal lengths and end with spaces
82
+ const labelFatal = `${styleText('magenta', 'fatal')} `
83
+ const labelError = `${styleText('red', 'error')} `
84
+ const labelWarn = `${styleText('yellow', 'warn')} `
85
+
86
+ const lines = ['']
87
+
88
+ /** @type {string | undefined} */
89
+ let gitLabBaseURL
90
+ const projectUrl = process.env.CI_PROJECT_URL
91
+ const commitSha = process.env.CI_COMMIT_SHORT_SHA
92
+ if (projectUrl && commitSha) {
93
+ gitLabBaseURL = `${projectUrl}/-/blob/${commitSha}/`
94
+ }
95
+
96
+ let fatal = 0
97
+ let errors = 0
98
+ let warnings = 0
99
+ let maxRuleIdLength = 0
100
+ let maxMsgLength = 0
101
+
102
+ for (const result of results) {
103
+ fatal += result.fatalErrorCount
104
+ errors += result.errorCount - result.fatalErrorCount
105
+ warnings += result.warningCount
106
+ for (const message of result.messages) {
107
+ if (message.ruleId) {
108
+ maxRuleIdLength = Math.max(maxRuleIdLength, message.ruleId.length)
109
+ }
110
+ maxMsgLength = Math.max(maxMsgLength, message.message.length)
111
+ }
112
+ }
113
+
114
+ for (const result of results) {
115
+ const { filePath, messages } = result
116
+ const repoFilePath = relative(projectDir, filePath)
117
+
118
+ for (const message of messages) {
119
+ let line = message.fatal ? labelFatal : message.severity === 1 ? labelWarn : labelError
120
+ line += String(message.ruleId || '').padEnd(maxRuleIdLength + 2)
121
+ line += message.message.padEnd(maxMsgLength + 2)
122
+
123
+ if (gitLabBaseURL) {
124
+ // Create link to referenced file in GitLab
125
+ let anchor = `#L${message.line}`
126
+ if (message.endLine != null && message.endLine !== message.line) {
127
+ anchor += `-${message.endLine}`
128
+ }
129
+ line += styleText('blue', `${gitLabBaseURL}${repoFilePath}${anchor}`)
130
+ } else {
131
+ line += `${filePath}:${message.line}:${message.column}`
132
+ }
133
+
134
+ lines.push(line)
135
+ }
136
+ }
137
+
138
+ const total = warnings + errors + fatal
139
+ if (total > 0) {
140
+ const details = `(${fatal} fatal, ${plural(errors, 'error')}, ${plural(warnings, 'warning')})`
141
+ lines.push('', `${styleText('red', '✖')} ${plural(total, 'problem')} ${details}`)
142
+ } else {
143
+ lines.push(`${styleText('green', '✔')} No problems found`)
144
+ }
145
+
146
+ lines.push('')
147
+ return lines.join('\n')
148
+ }
149
+
150
+ /**
151
+ * @param {ESLint.LintResult[]} results
152
+ * The ESLint report results.
153
+ * @param {ESLint.LintResultData} data
154
+ * The ESLint report result data.
155
+ * @returns {Promise<string>}
156
+ * The ESLint output to print to the console.
157
+ */
158
+ async function eslintFormatterGitLab(results, data) {
159
+ let outputPath = process.env.ESLINT_CODE_QUALITY_REPORT
160
+ const projectDir = process.env.CI_PROJECT_DIR ?? data.cwd
161
+ const jobName = process.env.CI_JOB_NAME
162
+ if (jobName || outputPath) {
163
+ const issues = toCodeClimate(results, data.rulesMeta, projectDir)
164
+ outputPath ||= await getOutputPath(projectDir, jobName)
165
+ const dir = dirname(outputPath)
166
+ await mkdir(dir, { recursive: true })
167
+ await writeFile(outputPath, `${JSON.stringify(issues, null, 2)}\n`)
168
+ }
169
+
170
+ return gitlabConsoleFormatter(results, projectDir)
171
+ }
172
+
173
+ export default eslintFormatterGitLab
package/package.json CHANGED
@@ -1,20 +1,27 @@
1
1
  {
2
2
  "name": "eslint-formatter-gitlab",
3
- "version": "5.1.0",
3
+ "version": "6.0.1",
4
4
  "description": "Show ESLint results directly in the GitLab code quality results",
5
+ "type": "module",
5
6
  "author": "Remco Haszing <remcohaszing@gmail.com>",
6
7
  "license": "MIT",
7
8
  "homepage": "https://gitlab.com/remcohaszing/eslint-formatter-gitlab#readme",
8
9
  "repository": "gitlab:remcohaszing/eslint-formatter-gitlab",
9
10
  "funding": "https://github.com/sponsors/remcohaszing",
10
11
  "bugs": "https://gitlab.com/remcohaszing/eslint-formatter-gitlab/-/issues",
11
- "exports": "./index.js",
12
+ "main": "./lib/eslint-formatter-gitlab.js",
13
+ "types": "./types/eslint-formatter-gitlab.d.ts",
14
+ "exports": {
15
+ "types": "./types/eslint-formatter-gitlab.d.ts",
16
+ "default": "./lib/eslint-formatter-gitlab.js"
17
+ },
12
18
  "files": [
13
- "index.*"
19
+ "lib",
20
+ "types"
14
21
  ],
15
22
  "scripts": {
16
23
  "prepack": "tsc --build",
17
- "test": "c8 node --test --test-reporter @reporters/junit --test-reporter-destination=junit.xml --test-reporter spec --test-reporter-destination stdout"
24
+ "test": "c8 node --test --test-reporter junit --test-reporter-destination=junit.xml --test-reporter spec --test-reporter-destination stdout"
18
25
  },
19
26
  "keywords": [
20
27
  "eslint",
@@ -24,23 +31,20 @@
24
31
  "gitlab-ci"
25
32
  ],
26
33
  "dependencies": {
27
- "chalk": "^4.0.0",
34
+ "eslint-formatter-codeclimate": "^1.0.0",
28
35
  "yaml": "^2.0.0"
29
36
  },
30
37
  "peerDependencies": {
31
- "eslint": ">=5"
38
+ "eslint": ">=9"
32
39
  },
33
40
  "devDependencies": {
34
- "@reporters/junit": "^1.0.0",
35
- "@types/eslint": "^8.0.0",
36
- "@types/node": "^20.0.0",
37
- "c8": "^8.0.0",
41
+ "@remcohaszing/eslint": "^11.0.0",
42
+ "@types/node": "^22.0.0",
43
+ "c8": "^10.0.0",
38
44
  "codeclimate-types": "^0.3.0",
39
- "eslint": "^8.0.0",
40
- "eslint-config-remcohaszing": "^10.0.0",
41
45
  "prettier": "^3.0.0",
42
- "remark-cli": "^11.0.0",
43
- "remark-preset-remcohaszing": "^2.0.0",
46
+ "remark-cli": "^12.0.0",
47
+ "remark-preset-remcohaszing": "^3.0.0",
44
48
  "typescript": "^5.0.0"
45
49
  }
46
50
  }
@@ -0,0 +1,12 @@
1
+ export default eslintFormatterGitLab;
2
+ /**
3
+ * @param {ESLint.LintResult[]} results
4
+ * The ESLint report results.
5
+ * @param {ESLint.LintResultData} data
6
+ * The ESLint report result data.
7
+ * @returns {Promise<string>}
8
+ * The ESLint output to print to the console.
9
+ */
10
+ declare function eslintFormatterGitLab(results: ESLint.LintResult[], data: ESLint.LintResultData): Promise<string>;
11
+ import type { ESLint } from 'eslint';
12
+ //# sourceMappingURL=eslint-formatter-gitlab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint-formatter-gitlab.d.ts","sourceRoot":"","sources":["../lib/eslint-formatter-gitlab.js"],"names":[],"mappings":";AAqJA;;;;;;;GAOG;AACH,gDAPW,iBAAiB,EAAE,QAEnB,qBAAqB,GAEnB,OAAO,CAAC,MAAM,CAAC,CAgB3B;4BAzK0B,QAAQ"}
package/index.d.ts DELETED
@@ -1,11 +0,0 @@
1
- export = eslintFormatterGitLab;
2
- /**
3
- * @param {import('eslint').ESLint.LintResult[]} results
4
- * The ESLint report results.
5
- * @param {import('eslint').ESLint.LintResultData} data
6
- * The ESLint report result data.
7
- * @returns {string}
8
- * The ESLint output to print to the console.
9
- */
10
- declare function eslintFormatterGitLab(results: import('eslint').ESLint.LintResult[], data: import('eslint').ESLint.LintResultData): string;
11
- //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":";AA0PA;;;;;;;GAOG;AACH,gDAPW,OAAO,QAAQ,EAAE,MAAM,CAAC,UAAU,EAAE,QAEpC,OAAO,QAAQ,EAAE,MAAM,CAAC,cAAc,GAEpC,MAAM,CAmBlB"}
package/index.js DELETED
@@ -1,277 +0,0 @@
1
- const { createHash } = require('node:crypto')
2
- const { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } = require('node:fs')
3
- const { EOL } = require('node:os')
4
- const { dirname, join, relative, resolve } = require('node:path')
5
-
6
- const chalk = require('chalk')
7
- const yaml = require('yaml')
8
-
9
- const {
10
- CI_COMMIT_SHORT_SHA,
11
- CI_CONFIG_PATH = '.gitlab-ci.yml',
12
- CI_JOB_NAME,
13
- CI_PROJECT_DIR = process.cwd(),
14
- CI_PROJECT_URL,
15
- ESLINT_CODE_QUALITY_REPORT,
16
- GITLAB_CI
17
- } = process.env
18
-
19
- /** @type {yaml.CollectionTag} */
20
- const reference = {
21
- tag: '!reference',
22
- collection: 'seq',
23
- default: false,
24
- resolve() {
25
- // We only allow the syntax. We don’t actually resolve the reference.
26
- }
27
- }
28
-
29
- /**
30
- * @returns {string}
31
- * The output path of the code quality artifact.
32
- */
33
- function getOutputPath() {
34
- const configPath = join(CI_PROJECT_DIR, CI_CONFIG_PATH)
35
- // GitlabCI allows a custom configuration path which can be a URL or a path relative to another
36
- // project. In these cases CI_CONFIG_PATH is empty and we'll have to require the user provide
37
- // ESLINT_CODE_QUALITY_REPORT.
38
- if (!existsSync(configPath) || !lstatSync(configPath).isFile()) {
39
- throw new Error(
40
- 'Could not resolve .gitlab-ci.yml to automatically detect report artifact path.' +
41
- ' Please manually provide a path via the ESLINT_CODE_QUALITY_REPORT variable.'
42
- )
43
- }
44
- const doc = yaml.parseDocument(readFileSync(configPath, 'utf8'), {
45
- version: '1.1',
46
- customTags: [reference]
47
- })
48
- const path = [CI_JOB_NAME, 'artifacts', 'reports', 'codequality']
49
- const location = doc.getIn(path)
50
- if (typeof location !== 'string' || !location) {
51
- throw new TypeError(
52
- `Expected ${path.join('.')} to be one exact path, got: ${JSON.stringify(location)}`
53
- )
54
- }
55
- return resolve(CI_PROJECT_DIR, location)
56
- }
57
-
58
- /**
59
- * @param {string} filePath
60
- * The path to the linted file.
61
- * @param {import('eslint').Linter.LintMessage} message
62
- * The ESLint report message.
63
- * @param {Set<string>} hashes
64
- * Hashes already encountered. Used to avoid duplicate hashes
65
- * @returns {string}
66
- * The fingerprint for the ESLint report message.
67
- */
68
- function createFingerprint(filePath, message, hashes) {
69
- const md5 = createHash('md5')
70
- md5.update(filePath)
71
- if (message.ruleId) {
72
- md5.update(message.ruleId)
73
- }
74
- md5.update(message.message)
75
-
76
- // Create copy of hash since md5.digest() will finalize it, not allowing us to .update() again
77
- let md5Tmp = md5.copy()
78
- let hash = md5Tmp.digest('hex')
79
-
80
- while (hashes.has(hash)) {
81
- // Hash collision. This happens if we encounter the same ESLint message in one file
82
- // multiple times. Keep generating new hashes until we get a unique one.
83
- md5.update(hash)
84
-
85
- md5Tmp = md5.copy()
86
- hash = md5Tmp.digest('hex')
87
- }
88
-
89
- hashes.add(hash)
90
- return hash
91
- }
92
-
93
- /**
94
- * @param {import('eslint').ESLint.LintResult[]} results
95
- * The ESLint report results.
96
- * @param {import('eslint').ESLint.LintResultData} data
97
- * The ESLint report result data.
98
- * @returns {import('codeclimate-types').Issue[]}
99
- * The ESLint messages in the form of a GitLab code quality report.
100
- */
101
- function convert(results, data) {
102
- /** @type {import('codeclimate-types').Issue[]} */
103
- const messages = []
104
-
105
- /** @type {Set<string>} */
106
- const hashes = new Set()
107
-
108
- for (const result of results) {
109
- const relativePath = relative(CI_PROJECT_DIR, result.filePath)
110
-
111
- for (const message of result.messages) {
112
- /** @type {import('codeclimate-types').Issue} */
113
- const issue = {
114
- type: 'issue',
115
- categories: ['Style'],
116
- check_name: message.ruleId ?? '',
117
- description: message.message,
118
- severity: message.fatal ? 'critical' : message.severity === 2 ? 'major' : 'minor',
119
- fingerprint: createFingerprint(relativePath, message, hashes),
120
- location: {
121
- path: relativePath,
122
- lines: {
123
- begin: message.line,
124
- end: message.endLine ?? message.line
125
- }
126
- }
127
- }
128
- messages.push(issue)
129
-
130
- if (!message.ruleId) {
131
- continue
132
- }
133
-
134
- if (!data.rulesMeta[message.ruleId]) {
135
- continue
136
- }
137
-
138
- const { docs, type } = data.rulesMeta[message.ruleId]
139
- if (type === 'problem') {
140
- issue.categories.unshift('Bug Risk')
141
- }
142
-
143
- if (!docs) {
144
- continue
145
- }
146
-
147
- let body = docs.description || ''
148
- if (docs.url) {
149
- if (body) {
150
- body += '\n\n'
151
- }
152
- body += `[${message.ruleId}](${docs.url})`
153
- }
154
-
155
- if (body) {
156
- issue.content = { body }
157
- }
158
- }
159
- }
160
- return messages
161
- }
162
-
163
- /**
164
- * Make a text singular or plural based on the count.
165
- *
166
- * @param {number} count
167
- * The count of the data.
168
- * @param {string} text
169
- * The text to make singular or plural.
170
- * @returns {string}
171
- * The formatted text.
172
- */
173
- function plural(count, text) {
174
- return `${count} ${text}${count === 1 ? '' : 's'}`
175
- }
176
-
177
- /**
178
- * @param {import('eslint').ESLint.LintResult[]} results
179
- * The ESLint report results.
180
- * @returns {string}
181
- * The ESLint messages converted to a format suitable as output in GitLab CI job logs.
182
- */
183
- function gitlabConsoleFormatter(results) {
184
- // Severity labels manually padded to have equal lengths and end with spaces
185
- const labelFatal = `${chalk.magenta('fatal')} `
186
- const labelError = `${chalk.red('error')} `
187
- const labelWarn = `${chalk.yellow('warn')} `
188
-
189
- const lines = ['']
190
-
191
- /** @type {string | undefined} */
192
- let gitLabBaseURL
193
- if (CI_PROJECT_URL && CI_COMMIT_SHORT_SHA) {
194
- gitLabBaseURL = `${CI_PROJECT_URL}/-/blob/${CI_COMMIT_SHORT_SHA}/`
195
- }
196
-
197
- let fatal = 0
198
- let errors = 0
199
- let warnings = 0
200
- let maxRuleIdLength = 0
201
- let maxMsgLength = 0
202
-
203
- for (const result of results) {
204
- fatal += result.fatalErrorCount
205
- errors += result.errorCount - result.fatalErrorCount
206
- warnings += result.warningCount
207
- for (const message of result.messages) {
208
- if (message.ruleId) {
209
- maxRuleIdLength = Math.max(maxRuleIdLength, message.ruleId.length)
210
- }
211
- maxMsgLength = Math.max(maxMsgLength, message.message.length)
212
- }
213
- }
214
-
215
- for (const result of results) {
216
- const { filePath, messages } = result
217
- const repoFilePath = relative(CI_PROJECT_DIR, filePath)
218
-
219
- for (const message of messages) {
220
- let line = message.fatal ? labelFatal : message.severity === 1 ? labelWarn : labelError
221
- line += String(message.ruleId || '').padEnd(maxRuleIdLength + 2)
222
- line += message.message.padEnd(maxMsgLength + 2)
223
-
224
- if (gitLabBaseURL) {
225
- // Create link to referenced file in GitLab
226
- let anchor = `#L${message.line}`
227
- if (message.endLine != null && message.endLine !== message.line) {
228
- anchor += `-${message.endLine}`
229
- }
230
- line += chalk.blue(`${gitLabBaseURL}${repoFilePath}${anchor}`)
231
- } else {
232
- line += `${filePath}:${message.line}:${message.column}`
233
- }
234
-
235
- lines.push(line)
236
- }
237
- }
238
-
239
- const total = warnings + errors + fatal
240
- if (total > 0) {
241
- const details = `(${fatal} fatal, ${plural(errors, 'error')}, ${plural(warnings, 'warning')})`
242
- lines.push('', `${chalk.red('✖')} ${plural(total, 'problem')} ${details}`)
243
- } else {
244
- lines.push(`${chalk.green('✔')} No problems found`)
245
- }
246
-
247
- lines.push('')
248
- return lines.join(EOL)
249
- }
250
-
251
- /**
252
- * @param {import('eslint').ESLint.LintResult[]} results
253
- * The ESLint report results.
254
- * @param {import('eslint').ESLint.LintResultData} data
255
- * The ESLint report result data.
256
- * @returns {string}
257
- * The ESLint output to print to the console.
258
- */
259
- function eslintFormatterGitLab(results, data) {
260
- /* c8 ignore start */
261
- if (GITLAB_CI === 'true') {
262
- chalk.level = 1
263
- }
264
-
265
- /* c8 ignore stop */
266
- if (CI_JOB_NAME || ESLINT_CODE_QUALITY_REPORT) {
267
- const issues = convert(results, data)
268
- const outputPath = ESLINT_CODE_QUALITY_REPORT || getOutputPath()
269
- const dir = dirname(outputPath)
270
- mkdirSync(dir, { recursive: true })
271
- writeFileSync(outputPath, JSON.stringify(issues, null, 2))
272
- }
273
-
274
- return gitlabConsoleFormatter(results)
275
- }
276
-
277
- module.exports = eslintFormatterGitLab