eslint-formatter-gitlab 4.0.0 → 5.0.0
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/LICENSE.md +2 -2
- package/README.md +21 -11
- package/index.js +132 -157
- package/package.json +12 -21
package/LICENSE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Copyright © 2018 Remco Haszing
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
-
associated documentation files (the
|
|
6
|
+
associated documentation files (the “Software”), to deal in the Software without restriction,
|
|
7
7
|
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
|
8
8
|
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
|
9
9
|
furnished to do so, subject to the following conditions:
|
|
@@ -11,7 +11,7 @@ furnished to do so, subject to the following conditions:
|
|
|
11
11
|
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
12
|
portions of the Software.
|
|
13
13
|
|
|
14
|
-
THE SOFTWARE IS PROVIDED
|
|
14
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
|
15
15
|
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
16
16
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
|
17
17
|
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
package/README.md
CHANGED
|
@@ -2,11 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Show ESLint results directly in the
|
|
4
4
|
[GitLab code quality](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html)
|
|
5
|
-
results
|
|
5
|
+
results.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Requirements](#requirements)
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [Usage](#usage)
|
|
12
|
+
- [Example](#example)
|
|
13
|
+
- [Configuration](#configuration)
|
|
14
|
+
- [License](#license)
|
|
6
15
|
|
|
7
16
|
## Requirements
|
|
8
17
|
|
|
9
|
-
This package requires at least Node.js
|
|
18
|
+
This package requires at least Node.js 18 and ESLint 5.
|
|
10
19
|
|
|
11
20
|
## Installation
|
|
12
21
|
|
|
@@ -24,7 +33,7 @@ _.gitlab-ci.yml_:
|
|
|
24
33
|
|
|
25
34
|
```yaml
|
|
26
35
|
eslint:
|
|
27
|
-
image: node:
|
|
36
|
+
image: node:20-alpine
|
|
28
37
|
script:
|
|
29
38
|
- npm ci
|
|
30
39
|
- npx eslint --format gitlab .
|
|
@@ -33,8 +42,8 @@ eslint:
|
|
|
33
42
|
codequality: gl-codequality.json
|
|
34
43
|
```
|
|
35
44
|
|
|
36
|
-
The formatter
|
|
37
|
-
|
|
45
|
+
The formatter automatically detects a GitLab CI environment. It detects where to output the code
|
|
46
|
+
quality report based on the GitLab configuration file.
|
|
38
47
|
|
|
39
48
|
## Example
|
|
40
49
|
|
|
@@ -42,12 +51,13 @@ An example of the results can be seen in
|
|
|
42
51
|
[Merge Request !1](https://gitlab.com/remcohaszing/eslint-formatter-gitlab/merge_requests/1) of
|
|
43
52
|
`eslint-formatter-gitlab` itself.
|
|
44
53
|
|
|
45
|
-
## Configuration
|
|
54
|
+
## Configuration
|
|
46
55
|
|
|
47
|
-
ESLint formatters don’t take any configuration options. `eslint-formatter-gitlab` uses GitLab
|
|
48
|
-
environment variables
|
|
49
|
-
|
|
56
|
+
ESLint formatters don’t take any configuration options. `eslint-formatter-gitlab` uses GitLab’s
|
|
57
|
+
[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.
|
|
50
60
|
|
|
51
|
-
|
|
61
|
+
## License
|
|
52
62
|
|
|
53
|
-
[MIT](LICENSE.md)
|
|
63
|
+
[MIT](LICENSE.md) © [Remco Haszing](https://gitlab.com/remcohaszing)
|
package/index.js
CHANGED
|
@@ -2,75 +2,26 @@
|
|
|
2
2
|
* @typedef {import('eslint').ESLint.LintResult} LintResult
|
|
3
3
|
* @typedef {import('eslint').ESLint.LintResultData} LintResultData
|
|
4
4
|
* @typedef {import('eslint').Linter.LintMessage} LintMessage
|
|
5
|
+
* @typedef {import('codeclimate-types').Issue} Issue
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @typedef {object} GitLabArtifacts
|
|
14
|
-
* @property {GitLabReports} [reports]
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {object} GitLabJob
|
|
19
|
-
* @property {GitLabArtifacts} [artifacts]
|
|
20
|
-
*/
|
|
8
|
+
const { createHash } = require('node:crypto')
|
|
9
|
+
const { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } = require('node:fs')
|
|
10
|
+
const { EOL } = require('node:os')
|
|
11
|
+
const { dirname, join, relative, resolve } = require('node:path')
|
|
21
12
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @typedef {object} CodeClimateLines
|
|
28
|
-
* @property {number} begin
|
|
29
|
-
* @property {number} end
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @typedef {object} CodeClimateContents
|
|
34
|
-
* @property {string} body
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @typedef {object} CodeClimateLocation
|
|
39
|
-
* https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#locations
|
|
40
|
-
* @property {string} path
|
|
41
|
-
* @property {CodeClimateLines} lines
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @typedef {object} CodeClimateIssue
|
|
46
|
-
* https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#issues
|
|
47
|
-
* @property {'issue'} type
|
|
48
|
-
* @property {string} check_name
|
|
49
|
-
* @property {string} description
|
|
50
|
-
* @property {CodeClimateContents} [contents]
|
|
51
|
-
* @property {'info' | 'minor' | 'major' | 'critical' | 'blocker'} severity
|
|
52
|
-
* @property {string} [fingerprint]
|
|
53
|
-
* @property {CodeClimateLocation} location
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
|
-
const { createHash } = require('node:crypto');
|
|
57
|
-
const { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } = require('node:fs');
|
|
58
|
-
const { EOL } = require('node:os');
|
|
59
|
-
const { dirname, join, relative, resolve } = require('node:path');
|
|
60
|
-
|
|
61
|
-
const chalk = require('chalk');
|
|
62
|
-
const yaml = require('yaml');
|
|
13
|
+
const chalk = require('chalk')
|
|
14
|
+
const yaml = require('yaml')
|
|
63
15
|
|
|
64
16
|
const {
|
|
17
|
+
CI_COMMIT_SHORT_SHA,
|
|
65
18
|
CI_CONFIG_PATH = '.gitlab-ci.yml',
|
|
66
19
|
CI_JOB_NAME,
|
|
67
20
|
CI_PROJECT_DIR = process.cwd(),
|
|
68
21
|
CI_PROJECT_URL,
|
|
69
|
-
CI_COMMIT_SHORT_SHA,
|
|
70
22
|
ESLINT_CODE_QUALITY_REPORT,
|
|
71
|
-
GITLAB_CI
|
|
72
|
-
|
|
73
|
-
} = process.env;
|
|
23
|
+
GITLAB_CI
|
|
24
|
+
} = process.env
|
|
74
25
|
|
|
75
26
|
/**
|
|
76
27
|
* @type {yaml.CollectionTag}
|
|
@@ -81,105 +32,123 @@ const reference = {
|
|
|
81
32
|
default: false,
|
|
82
33
|
resolve() {
|
|
83
34
|
// We only allow the syntax. We don’t actually resolve the reference.
|
|
84
|
-
}
|
|
85
|
-
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
86
37
|
|
|
87
38
|
/**
|
|
88
39
|
* @returns {string} The output path of the code quality artifact.
|
|
89
40
|
*/
|
|
90
41
|
function getOutputPath() {
|
|
91
|
-
const configPath = join(CI_PROJECT_DIR, CI_CONFIG_PATH)
|
|
42
|
+
const configPath = join(CI_PROJECT_DIR, CI_CONFIG_PATH)
|
|
92
43
|
// GitlabCI allows a custom configuration path which can be a URL or a path relative to another
|
|
93
44
|
// project. In these cases CI_CONFIG_PATH is empty and we'll have to require the user provide
|
|
94
45
|
// ESLINT_CODE_QUALITY_REPORT.
|
|
95
46
|
if (!existsSync(configPath) || !lstatSync(configPath).isFile()) {
|
|
96
47
|
throw new Error(
|
|
97
48
|
'Could not resolve .gitlab-ci.yml to automatically detect report artifact path.' +
|
|
98
|
-
' Please manually provide a path via the ESLINT_CODE_QUALITY_REPORT variable.'
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
const jobs = /** @type {GitLabCI} */ (
|
|
102
|
-
yaml.parse(readFileSync(configPath, 'utf8'), { version: '1.1', customTags: [reference] })
|
|
103
|
-
);
|
|
104
|
-
const { artifacts } = jobs[/** @type {string} */ (CI_JOB_NAME)];
|
|
105
|
-
const location = artifacts?.reports?.codequality;
|
|
106
|
-
const msg = `Expected ${CI_JOB_NAME}.artifacts.reports.codequality to be one exact path`;
|
|
107
|
-
if (!location) {
|
|
108
|
-
throw new Error(`${msg}, but no value was found.`);
|
|
49
|
+
' Please manually provide a path via the ESLINT_CODE_QUALITY_REPORT variable.'
|
|
50
|
+
)
|
|
109
51
|
}
|
|
110
|
-
|
|
111
|
-
|
|
52
|
+
const doc = yaml.parseDocument(readFileSync(configPath, 'utf8'), {
|
|
53
|
+
version: '1.1',
|
|
54
|
+
customTags: [reference]
|
|
55
|
+
})
|
|
56
|
+
const path = [CI_JOB_NAME, 'artifacts', 'reports', 'codequality']
|
|
57
|
+
const location = doc.getIn(path)
|
|
58
|
+
if (typeof location !== 'string' || !location) {
|
|
59
|
+
throw new TypeError(
|
|
60
|
+
`Expected ${path.join('.')} to be one exact path, got: ${JSON.stringify(location)}`
|
|
61
|
+
)
|
|
112
62
|
}
|
|
113
|
-
return resolve(CI_PROJECT_DIR, location)
|
|
63
|
+
return resolve(CI_PROJECT_DIR, location)
|
|
114
64
|
}
|
|
115
65
|
|
|
116
66
|
/**
|
|
117
67
|
* @param {string} filePath The path to the linted file.
|
|
118
68
|
* @param {LintMessage} message The ESLint report message.
|
|
69
|
+
* @param {Set<string>} hashes Hashes already encountered. Used to avoid duplicate hashes
|
|
119
70
|
* @returns {string} The fingerprint for the ESLint report message.
|
|
120
71
|
*/
|
|
121
|
-
function createFingerprint(filePath, message) {
|
|
122
|
-
const md5 = createHash('md5')
|
|
123
|
-
md5.update(filePath)
|
|
72
|
+
function createFingerprint(filePath, message, hashes) {
|
|
73
|
+
const md5 = createHash('md5')
|
|
74
|
+
md5.update(filePath)
|
|
124
75
|
if (message.ruleId) {
|
|
125
|
-
md5.update(message.ruleId)
|
|
76
|
+
md5.update(message.ruleId)
|
|
126
77
|
}
|
|
127
|
-
md5.update(message.message)
|
|
128
|
-
|
|
78
|
+
md5.update(message.message)
|
|
79
|
+
|
|
80
|
+
// Create copy of hash since md5.digest() will finalize it, not allowing us to .update() again
|
|
81
|
+
let md5Tmp = md5.copy()
|
|
82
|
+
let hash = md5Tmp.digest('hex')
|
|
83
|
+
|
|
84
|
+
while (hashes.has(hash)) {
|
|
85
|
+
// Hash collision. This happens if we encounter the same ESLint message in one file
|
|
86
|
+
// multiple times. Keep generating new hashes until we get a unique one.
|
|
87
|
+
md5.update(hash)
|
|
88
|
+
|
|
89
|
+
md5Tmp = md5.copy()
|
|
90
|
+
hash = md5Tmp.digest('hex')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
hashes.add(hash)
|
|
94
|
+
return hash
|
|
129
95
|
}
|
|
130
96
|
|
|
131
97
|
/**
|
|
132
98
|
* @param {LintResult[]} results The ESLint report results.
|
|
133
99
|
* @param {LintResultData} data The ESLint report result data.
|
|
134
|
-
* @returns {
|
|
100
|
+
* @returns {Issue[]} The ESLint messages in the form of a GitLab code quality report.
|
|
135
101
|
*/
|
|
136
102
|
function convert(results, data) {
|
|
137
|
-
/** @type {
|
|
138
|
-
const messages = []
|
|
103
|
+
/** @type {Issue[]} */
|
|
104
|
+
const messages = []
|
|
105
|
+
|
|
106
|
+
/** @type {Set<string>} */
|
|
107
|
+
const hashes = new Set()
|
|
108
|
+
|
|
139
109
|
for (const result of results) {
|
|
140
|
-
|
|
141
|
-
const relativePath = relative(CI_PROJECT_DIR, result.filePath);
|
|
110
|
+
const relativePath = relative(CI_PROJECT_DIR, result.filePath)
|
|
142
111
|
|
|
143
|
-
|
|
112
|
+
for (const message of result.messages) {
|
|
113
|
+
/** @type {Issue} */
|
|
144
114
|
const issue = {
|
|
145
115
|
type: 'issue',
|
|
116
|
+
categories: ['Style'],
|
|
146
117
|
check_name: message.ruleId ?? '',
|
|
147
118
|
description: message.message,
|
|
148
|
-
severity: message.severity === 2 ? 'major' : 'minor',
|
|
149
|
-
fingerprint: createFingerprint(relativePath, message),
|
|
119
|
+
severity: message.fatal ? 'critical' : message.severity === 2 ? 'major' : 'minor',
|
|
120
|
+
fingerprint: createFingerprint(relativePath, message, hashes),
|
|
150
121
|
location: {
|
|
151
122
|
path: relativePath,
|
|
152
123
|
lines: {
|
|
153
124
|
begin: message.line,
|
|
154
|
-
end: message.endLine ?? message.line
|
|
155
|
-
},
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
const docs = message.ruleId ? data.rulesMeta[message.ruleId]?.docs : undefined;
|
|
159
|
-
if (docs) {
|
|
160
|
-
let body = docs.description || '';
|
|
161
|
-
if (docs.url) {
|
|
162
|
-
if (body) {
|
|
163
|
-
body += '\n\n';
|
|
125
|
+
end: message.endLine ?? message.line
|
|
164
126
|
}
|
|
165
|
-
body += `[${message.ruleId}](${docs.url})`;
|
|
166
127
|
}
|
|
167
|
-
|
|
168
|
-
|
|
128
|
+
}
|
|
129
|
+
if (message.ruleId && message.ruleId in data.rulesMeta) {
|
|
130
|
+
const { docs, type } = data.rulesMeta[message.ruleId]
|
|
131
|
+
if (type === 'problem') {
|
|
132
|
+
issue.categories.unshift('Bug Risk')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (docs) {
|
|
136
|
+
let body = docs.description || ''
|
|
137
|
+
if (docs.url) {
|
|
138
|
+
if (body) {
|
|
139
|
+
body += '\n\n'
|
|
140
|
+
}
|
|
141
|
+
body += `[${message.ruleId}](${docs.url})`
|
|
142
|
+
}
|
|
143
|
+
if (body) {
|
|
144
|
+
issue.content = { body }
|
|
145
|
+
}
|
|
169
146
|
}
|
|
170
147
|
}
|
|
171
|
-
messages.push(issue)
|
|
148
|
+
messages.push(issue)
|
|
172
149
|
}
|
|
173
150
|
}
|
|
174
|
-
return messages
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* @param {LintMessage} message The ESLint report message.
|
|
179
|
-
* @returns {boolean} `true` if the message is at error level, `false` if it represents a warning
|
|
180
|
-
*/
|
|
181
|
-
function messageIsLevelError(message) {
|
|
182
|
-
return message.fatal || message.severity === 2;
|
|
151
|
+
return messages
|
|
183
152
|
}
|
|
184
153
|
|
|
185
154
|
/**
|
|
@@ -190,76 +159,80 @@ function messageIsLevelError(message) {
|
|
|
190
159
|
* @returns {string} The formatted text.
|
|
191
160
|
*/
|
|
192
161
|
function plural(count, text) {
|
|
193
|
-
return `${count} ${text}${count === 1 ? '' : 's'}
|
|
162
|
+
return `${count} ${text}${count === 1 ? '' : 's'}`
|
|
194
163
|
}
|
|
195
164
|
|
|
196
165
|
/**
|
|
197
166
|
* @param {LintResult[]} results The ESLint report results.
|
|
198
167
|
* @returns {string} The ESLint messages converted to a format
|
|
199
|
-
*
|
|
168
|
+
* suitable as output in GitLab CI job logs.
|
|
200
169
|
*/
|
|
201
170
|
function gitlabConsoleFormatter(results) {
|
|
202
171
|
// Severity labels manually padded to have equal lengths and end with spaces
|
|
203
|
-
const
|
|
204
|
-
const
|
|
172
|
+
const labelFatal = `${chalk.magenta('fatal')} `
|
|
173
|
+
const labelError = `${chalk.red('error')} `
|
|
174
|
+
const labelWarn = `${chalk.yellow('warn')} `
|
|
205
175
|
|
|
206
|
-
const lines = ['']
|
|
176
|
+
const lines = ['']
|
|
207
177
|
|
|
208
178
|
/** @type {string | undefined} */
|
|
209
|
-
let gitLabBaseURL
|
|
179
|
+
let gitLabBaseURL
|
|
210
180
|
if (CI_PROJECT_URL && CI_COMMIT_SHORT_SHA) {
|
|
211
|
-
gitLabBaseURL = `${CI_PROJECT_URL}/-/blob/${CI_COMMIT_SHORT_SHA}
|
|
181
|
+
gitLabBaseURL = `${CI_PROJECT_URL}/-/blob/${CI_COMMIT_SHORT_SHA}/`
|
|
212
182
|
}
|
|
213
183
|
|
|
214
|
-
let
|
|
215
|
-
let
|
|
216
|
-
let
|
|
217
|
-
let
|
|
184
|
+
let fatal = 0
|
|
185
|
+
let errors = 0
|
|
186
|
+
let warnings = 0
|
|
187
|
+
let maxRuleIdLength = 0
|
|
188
|
+
let maxMsgLength = 0
|
|
218
189
|
|
|
219
190
|
for (const result of results) {
|
|
191
|
+
fatal += result.fatalErrorCount
|
|
192
|
+
errors += result.errorCount - result.fatalErrorCount
|
|
193
|
+
warnings += result.warningCount
|
|
220
194
|
for (const message of result.messages) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
? Math.max(maxRuleIdLength, message.ruleId.length)
|
|
226
|
-
: maxRuleIdLength;
|
|
227
|
-
maxMsgLength = Math.max(maxMsgLength, message.message.length);
|
|
195
|
+
if (message.ruleId) {
|
|
196
|
+
maxRuleIdLength = Math.max(maxRuleIdLength, message.ruleId.length)
|
|
197
|
+
}
|
|
198
|
+
maxMsgLength = Math.max(maxMsgLength, message.message.length)
|
|
228
199
|
}
|
|
229
200
|
}
|
|
230
201
|
|
|
231
202
|
for (const result of results) {
|
|
232
|
-
const { filePath, messages } = result
|
|
233
|
-
const repoFilePath = relative(CI_PROJECT_DIR, filePath)
|
|
203
|
+
const { filePath, messages } = result
|
|
204
|
+
const repoFilePath = relative(CI_PROJECT_DIR, filePath)
|
|
234
205
|
|
|
235
206
|
for (const message of messages) {
|
|
236
|
-
let line
|
|
237
|
-
line
|
|
238
|
-
line +=
|
|
239
|
-
line += message.message.padEnd(maxMsgLength + 2);
|
|
207
|
+
let line = message.fatal ? labelFatal : message.severity === 1 ? labelWarn : labelError
|
|
208
|
+
line += String(message.ruleId || '').padEnd(maxRuleIdLength + 2)
|
|
209
|
+
line += message.message.padEnd(maxMsgLength + 2)
|
|
240
210
|
|
|
241
211
|
if (gitLabBaseURL) {
|
|
242
212
|
// Create link to referenced file in GitLab
|
|
243
|
-
|
|
244
|
-
|
|
213
|
+
let anchor = `#L${message.line}`
|
|
214
|
+
if (message.endLine != null && message.endLine !== message.line) {
|
|
215
|
+
anchor += `-${message.endLine}`
|
|
216
|
+
}
|
|
217
|
+
line += chalk.blue(`${gitLabBaseURL}${repoFilePath}${anchor}`)
|
|
245
218
|
} else {
|
|
246
|
-
line += `${filePath}:${message.line
|
|
219
|
+
line += `${filePath}:${message.line}:${message.column}`
|
|
247
220
|
}
|
|
248
221
|
|
|
249
|
-
lines.push(line)
|
|
222
|
+
lines.push(line)
|
|
250
223
|
}
|
|
251
224
|
}
|
|
252
225
|
|
|
253
|
-
const total = warnings + errors
|
|
226
|
+
const total = warnings + errors + fatal
|
|
254
227
|
if (total > 0) {
|
|
255
|
-
const details = `(${plural(errors, 'error')}, ${plural(warnings, 'warning')})
|
|
256
|
-
lines.push('', `${chalk.red('✖')} ${plural(total, 'problem')} ${details}`)
|
|
228
|
+
const details = `(${fatal} fatal, ${plural(errors, 'error')}, ${plural(warnings, 'warning')})`
|
|
229
|
+
lines.push('', `${chalk.red('✖')} ${plural(total, 'problem')} ${details}`)
|
|
257
230
|
} else {
|
|
258
|
-
lines.push(`${chalk.green('✔')} No problems found`)
|
|
231
|
+
lines.push(`${chalk.green('✔')} No problems found`)
|
|
259
232
|
}
|
|
260
233
|
|
|
261
|
-
lines.push('')
|
|
262
|
-
return lines.join(EOL)
|
|
234
|
+
lines.push('')
|
|
235
|
+
return lines.join(EOL)
|
|
263
236
|
}
|
|
264
237
|
|
|
265
238
|
/**
|
|
@@ -267,17 +240,19 @@ function gitlabConsoleFormatter(results) {
|
|
|
267
240
|
* @param {LintResultData} data The ESLint report result data.
|
|
268
241
|
*/
|
|
269
242
|
module.exports = (results, data) => {
|
|
270
|
-
/*
|
|
271
|
-
if (GITLAB_CI === 'true'
|
|
272
|
-
chalk.level = 1
|
|
243
|
+
/* c8 ignore start */
|
|
244
|
+
if (GITLAB_CI === 'true') {
|
|
245
|
+
chalk.level = 1
|
|
273
246
|
}
|
|
247
|
+
|
|
248
|
+
/* c8 ignore stop */
|
|
274
249
|
if (CI_JOB_NAME || ESLINT_CODE_QUALITY_REPORT) {
|
|
275
|
-
const issues = convert(results, data)
|
|
276
|
-
const outputPath = ESLINT_CODE_QUALITY_REPORT || getOutputPath()
|
|
277
|
-
const dir = dirname(outputPath)
|
|
278
|
-
mkdirSync(dir, { recursive: true })
|
|
279
|
-
writeFileSync(outputPath, JSON.stringify(issues, null, 2))
|
|
250
|
+
const issues = convert(results, data)
|
|
251
|
+
const outputPath = ESLINT_CODE_QUALITY_REPORT || getOutputPath()
|
|
252
|
+
const dir = dirname(outputPath)
|
|
253
|
+
mkdirSync(dir, { recursive: true })
|
|
254
|
+
writeFileSync(outputPath, JSON.stringify(issues, null, 2))
|
|
280
255
|
}
|
|
281
256
|
|
|
282
|
-
return gitlabConsoleFormatter(results)
|
|
283
|
-
}
|
|
257
|
+
return gitlabConsoleFormatter(results)
|
|
258
|
+
}
|
package/package.json
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-formatter-gitlab",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Show ESLint results directly in the GitLab code quality results",
|
|
5
5
|
"author": "Remco Haszing <remcohaszing@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://gitlab.com/remcohaszing/eslint-formatter-gitlab#readme",
|
|
8
|
-
"repository":
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://gitlab.com/remcohaszing/eslint-formatter-gitlab.git"
|
|
11
|
-
},
|
|
8
|
+
"repository": "gitlab:remcohaszing/eslint-formatter-gitlab",
|
|
12
9
|
"funding": "https://github.com/sponsors/remcohaszing",
|
|
13
|
-
"bugs":
|
|
14
|
-
"url": "https://gitlab.com/remcohaszing/eslint-formatter-gitlab.git/issues"
|
|
15
|
-
},
|
|
10
|
+
"bugs": "https://gitlab.com/remcohaszing/eslint-formatter-gitlab/-/issues",
|
|
16
11
|
"exports": "./index.js",
|
|
17
12
|
"files": [
|
|
18
13
|
"index.js"
|
|
19
14
|
],
|
|
20
15
|
"scripts": {
|
|
21
|
-
"test": "
|
|
16
|
+
"test": "c8 node --test --test-reporter @reporters/junit --test-reporter-destination=junit.xml --test-reporter spec --test-reporter-destination stdout"
|
|
22
17
|
},
|
|
23
18
|
"keywords": [
|
|
24
19
|
"eslint",
|
|
@@ -27,9 +22,6 @@
|
|
|
27
22
|
"gitlab",
|
|
28
23
|
"gitlab-ci"
|
|
29
24
|
],
|
|
30
|
-
"engines": {
|
|
31
|
-
"node": ">=14.0.0"
|
|
32
|
-
},
|
|
33
25
|
"dependencies": {
|
|
34
26
|
"chalk": "^4.0.0",
|
|
35
27
|
"yaml": "^2.0.0"
|
|
@@ -38,17 +30,16 @@
|
|
|
38
30
|
"eslint": "^5 || ^6 || ^7 || ^8"
|
|
39
31
|
},
|
|
40
32
|
"devDependencies": {
|
|
33
|
+
"@reporters/junit": "^1.0.0",
|
|
41
34
|
"@types/eslint": "^8.0.0",
|
|
42
|
-
"@types/
|
|
43
|
-
"
|
|
35
|
+
"@types/node": "^20.0.0",
|
|
36
|
+
"c8": "^8.0.0",
|
|
37
|
+
"codeclimate-types": "^0.3.0",
|
|
44
38
|
"eslint": "^8.0.0",
|
|
45
|
-
"eslint-config-remcohaszing": "^
|
|
46
|
-
"eslint-plugin-jest": "^27.0.0",
|
|
47
|
-
"eslint-plugin-jest-formatting": "^3.0.0",
|
|
48
|
-
"jest": "^29.0.0",
|
|
49
|
-
"jest-junit": "^14.0.0",
|
|
50
|
-
"memfs": "^3.0.0",
|
|
39
|
+
"eslint-config-remcohaszing": "^9.0.0",
|
|
51
40
|
"prettier": "^2.0.0",
|
|
52
|
-
"
|
|
41
|
+
"remark-cli": "^11.0.0",
|
|
42
|
+
"remark-preset-remcohaszing": "^1.0.0",
|
|
43
|
+
"typescript": "^5.0.0"
|
|
53
44
|
}
|
|
54
45
|
}
|