npm-groovy-lint 10.0.1 → 10.1.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/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  ## UNRELEASED
4
4
 
5
+ ## [10.1.0] 2022-08-15
6
+
7
+ - Allow to send groovy sources as input from stdin
8
+ - If `--format` or `--fix` option is used when source is sent as stdin, the result is output as stdout
9
+
10
+ Example: `cat path/to/my/Jenkinsfile | npm-groovy-lint --format -`
11
+
12
+ ## [10.0.3] 2022-08-15
13
+
14
+ - Do not output results summary in console logs when output is json or sarif
15
+ - Add test methods for SARIF called by CLI
16
+
17
+ ## [10.0.2] 2022-08-15
18
+
19
+ - Fix error when absolute files sent as positional arguments on a linux system ([#232](https://github.com/nvuillam/npm-groovy-lint/issues/232))
20
+ - Improve performances by calculating the longest command directory to send as base path to CodeNarc
21
+
5
22
  ## [10.0.1] 2022-08-14
6
23
 
7
24
  - Fix error when files sent as positional arguments ([#232](https://github.com/nvuillam/npm-groovy-lint/issues/232))
package/README.md CHANGED
@@ -43,8 +43,6 @@ Any **question**, **problem** or **enhancement request** ? Ask [**here**](https:
43
43
  npm-groovy-lint [OPTIONS] [FILES|PATH|PATTERN]
44
44
  ```
45
45
 
46
- See [examples](#example-calls)
47
-
48
46
  | Parameter | Type | Description |
49
47
  |-------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
50
48
  | -o<br/> --output | String | Output format (txt,json,sarif,html,xml), or path to a file with one of these extensions<br/> Default: `txt`<br/> Examples:<br/> - `"txt"`<br/> - `"json"`<br/> - `"./logs/myLintResults.txt"`<br/> - `"./logs/myLintResults.sarif"`<br/> - `"./logs/myLintResults.html"`<br/> - `"./logs/myLintResults.xml"` |
@@ -72,6 +70,68 @@ See [examples](#example-calls)
72
70
  | -p<br/> --path | String | (DEPRECATED) Directory containing the files to lint<br/> Example: `./path/to/my/groovy/files` |
73
71
  | -f<br/> --files | String | (DEPRECATED) Comma-separated list of Ant-style file patterns specifying files that must be included.<br/> Default: `"**/*.groovy,**/Jenkinsfile,**/*.gradle"`<br/>Examples:<br/> - `"**/Jenkinsfile"`<br/> - `"**/*.groovy"`<br/> - `"**/*.gradle"`<br/> - `"**/mySingleFile.groovy"` |
74
72
 
73
+ ### Example calls
74
+
75
+ - Lint a file
76
+
77
+ ```shell
78
+ npm-groovy-lint path/to/my/groovy/file.groovy
79
+ ```
80
+
81
+ - Lint multiple files
82
+
83
+ ```shell
84
+ npm-groovy-lint path/to/my/groovy/file.groovy path/to/my/groovy/file2.groovy path/to/my/groovy/file3.groovy
85
+ ```
86
+
87
+ - Lint directory
88
+
89
+ ```shell
90
+ npm-groovy-lint path/to/my/groovy
91
+ ```
92
+
93
+ - Lint pattern
94
+
95
+ ```shell
96
+ npm-groovy-lint path/to/my/groovy/*.groovy
97
+ ```
98
+
99
+ - Lint groovy with JSON output
100
+
101
+ ```shell
102
+ npm-groovy-lint --output json
103
+ ```
104
+
105
+ - Format files
106
+
107
+ ```shell
108
+ npm-groovy-lint --format my/path/to/file.groovy my/path/to/file2.groovy
109
+ ```
110
+
111
+ - Format and fix files
112
+
113
+ ```shell
114
+ npm-groovy-lint --fix my/path/to/file.groovy my/path/to/file2.groovy
115
+ ```
116
+
117
+ - Get formatted sources in stdout from stdin
118
+
119
+ ```shell
120
+ cat path/to/my/Jenkinsfile | npm-groovy-lint --format -
121
+ ```
122
+
123
+ - Advanced config
124
+
125
+ ```shell
126
+ npm-groovy-lint --path "./path/to/my/groovy/files" --files "**/*.groovy" --config "./config/codenarc/.groovylintrcCustom.js" --loglevel warning --output txt
127
+ ```
128
+
129
+ - Lint using core CodeNarc parameters and generate HTML report file
130
+
131
+ ```shell
132
+ npm-groovy-lint --codenarcargs -basedir="lib/example" -rulesetfiles="file:lib/example/RuleSet-Groovy.groovy" -title="TestTitleCodenarc" -maxPriority1Violations=0' -report="html:ReportTestCodenarc.html"
133
+ ```
134
+
75
135
  ## Installation
76
136
 
77
137
  ```shell
@@ -145,50 +205,6 @@ OR
145
205
  }
146
206
  ```
147
207
 
148
- ## Example calls
149
-
150
- - Lint a file
151
-
152
- ```shell
153
- npm-groovy-lint path/to/my/groovy/file.groovy
154
- ```
155
-
156
- - Lint multiple files
157
-
158
- ```shell
159
- npm-groovy-lint path/to/my/groovy/file.groovy path/to/my/groovy/file2.groovy path/to/my/groovy/file3.groovy
160
- ```
161
-
162
- - Lint directory
163
-
164
- ```shell
165
- npm-groovy-lint path/to/my/groovy
166
- ```
167
-
168
- - Lint pattern
169
-
170
- ```shell
171
- npm-groovy-lint path/to/my/groovy/*.groovy
172
- ```
173
-
174
- - Lint groovy with JSON output
175
-
176
- ```shell
177
- npm-groovy-lint --output json
178
- ```
179
-
180
- - Advanced config
181
-
182
- ```shell
183
- npm-groovy-lint --path "./path/to/my/groovy/files" --files "**/*.groovy" --config "./config/codenarc/.groovylintrcCustom.js" --loglevel warning --output txt
184
- ```
185
-
186
- - Lint using core CodeNarc parameters and generate HTML report file
187
-
188
- ```shell
189
- npm-groovy-lint --codenarcargs -basedir="lib/example" -rulesetfiles="file:lib/example/RuleSet-Groovy.groovy" -title="TestTitleCodenarc" -maxPriority1Violations=0' -report="html:ReportTestCodenarc.html"
190
- ```
191
-
192
208
  ## Disabling rules in source
193
209
 
194
210
  You can disable rules directly by adding comment in file, using [eslint style](https://eslint.org/docs/user-guide/configuring#disabling-rules-with-inline-comments)
@@ -2,6 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  const debug = require("debug")("npm-groovy-lint");
5
+ const commondir = require("commondir");
5
6
  const fs = require("fs-extra");
6
7
  const os = require("os");
7
8
  const path = require("path");
@@ -55,8 +56,11 @@ async function prepareCodeNarcCall(options) {
55
56
 
56
57
  // Define base directory
57
58
  const baseBefore = (cnPath !== "." && cnPath.startsWith("/")) || cnPath.includes(":/") || cnPath.includes(":\\") ? "" : process.cwd() + "/";
58
- result.codeNarcBaseDir = cnPath !== "." ? baseBefore + cnPath.replace(/^"(.*)"$/, "$1") : process.cwd();
59
- result.codeNarcBaseDir = path.resolve(result.codeNarcBaseDir);
59
+ const codeNarcBaseDir = positionalArgs.length > 0 ?
60
+ (await getCodeNarcBaseDirFromFiles(positionalArgs)) :
61
+ cnPath !== "." ? baseBefore + cnPath.replace(/^"(.*)"$/, "$1") :
62
+ process.cwd();
63
+ result.codeNarcBaseDir = path.resolve(codeNarcBaseDir);
60
64
  result.codenarcArgs.push(`-basedir=${result.codeNarcBaseDir}`);
61
65
 
62
66
  // Create ruleSet groovy file if necessary
@@ -90,17 +94,18 @@ async function prepareCodeNarcCall(options) {
90
94
  if (directoryExists(resolvedPath)) {
91
95
  finalPattern = "**/" + path.normalize(pathname.replace(/[/\\]$/u, "")).replace(/\\/gu, "/") + filePatterns;
92
96
  }
93
- // Absolute or cwd - relative path file
94
- if (fs.existsSync(finalPattern)) {
97
+ // Relative with codeNarcBaseDir
98
+ else if (fs.existsSync(path.join(result.codeNarcBaseDir, finalPattern))) {
95
99
  const absolutePath = path.resolve(finalPattern).replace(/\\/gu, "/");
96
- const relativePath = path.relative(process.cwd(), path.resolve(finalPattern)).replace(/\\/gu, "/");
97
100
  fileList.push(absolutePath);
101
+ const relativePath = finalPattern.replace(/\\/gu, "/");
98
102
  finalPattern = "**/" + path.normalize(relativePath.replace(/[/\\]$/u, "")).replace(/\\/gu, "/");
99
103
  }
100
- // Relative with codeNardBaseDir
101
- else if (fs.existsSync(path.join(result.codeNarcBaseDir, finalPattern))) {
102
- const relativePath = path.relative(process.cwd(), path.join(result.codeNarcBaseDir, finalPattern)).replace(/\\/gu, "/");
103
- fileList.push(relativePath);
104
+ // Absolute or cwd - relative path file
105
+ else if (fs.existsSync(finalPattern)) {
106
+ const absolutePath = path.resolve(finalPattern).replace(/\\/gu, "/");
107
+ fileList.push(absolutePath);
108
+ const relativePath = path.relative(result.codeNarcBaseDir, path.resolve(finalPattern)).replace(/\\/gu, "/");
104
109
  finalPattern = "**/" + path.normalize(relativePath.replace(/[/\\]$/u, "")).replace(/\\/gu, "/");
105
110
  }
106
111
  // Directory or ant pattern
@@ -131,7 +136,7 @@ async function prepareCodeNarcCall(options) {
131
136
  // Output
132
137
  result.output = options.output.replace(/^"(.*)"$/, "$1");
133
138
  if (
134
- ["txt", "json", "sarif", "none"].includes(result.output) ||
139
+ ["txt", "json", "sarif", "none", "stdout"].includes(result.output) ||
135
140
  result.output.endsWith(".txt") ||
136
141
  result.output.endsWith(".sarif") ||
137
142
  result.output.endsWith(".json")
@@ -174,6 +179,25 @@ async function prepareCodeNarcCall(options) {
174
179
  return result;
175
180
  }
176
181
 
182
+ // Calculate longest base dir by analyzing the list of files
183
+ async function getCodeNarcBaseDirFromFiles(positionalArgs) {
184
+ // All arguments are not files
185
+ if (!positionalArgs.every(fileOrDirOrPattern => fs.existsSync(fileOrDirOrPattern) || directoryExists(fileOrDirOrPattern))) {
186
+ return process.cwd()
187
+ }
188
+ const folders = positionalArgs.map((fileOrDir) => {
189
+ // Dir
190
+ if (directoryExists(fileOrDir)) {
191
+ return path.resolve(fileOrDir);
192
+ }
193
+ // File dir
194
+ const fileAbsolute = path.resolve(fileOrDir);
195
+ return path.dirname(fileAbsolute);
196
+ });
197
+ const baseDirFromFiles = commondir(folders);
198
+ return baseDirFromFiles
199
+ }
200
+
177
201
  // Parse XML result file as js object
178
202
  async function parseCodeNarcResult(options, codeNarcBaseDir, codeNarcJsonResult, tmpGroovyFileName, parseErrors) {
179
203
  if (!codeNarcJsonResult || !codeNarcJsonResult.codeNarc || !codeNarcJsonResult.packages) {
@@ -1,5 +1,6 @@
1
1
  // Imports
2
2
  const debug = require("debug")("npm-groovy-lint");
3
+ const fs = require("fs-extra");
3
4
  const os = require("os");
4
5
  const performance = require("perf_hooks").performance;
5
6
 
@@ -137,6 +138,17 @@ class NpmGroovyLint {
137
138
  this.options[configProp] = configProperties[configProp];
138
139
  }
139
140
  }
141
+ // Try to catch input from stdin. if found, use it as groovy source
142
+ if (this.options._ && this.options._[0] === '-') {
143
+ const stdInData = fs.readFileSync(0, 'utf-8');
144
+ this.options.source = stdInData;
145
+ this.options._ = [];
146
+ this.options.sourcefilepath = this.options.sourcefilepath || process.cwd();
147
+ if (this.options.format || this.options.fix) {
148
+ this.options.output = 'stdout';
149
+ }
150
+ }
151
+
140
152
  } catch (err) {
141
153
  this.status = 2;
142
154
  this.error = {
@@ -459,12 +471,12 @@ class NpmGroovyLint {
459
471
  this.options.failon && this.options.failon !== "none"
460
472
  ? this.options.failon
461
473
  : this.options.failonerror
462
- ? "error"
463
- : this.options.failonwarning
464
- ? "warning"
465
- : this.options.failoninfo
466
- ? "info"
467
- : "none";
474
+ ? "error"
475
+ : this.options.failonwarning
476
+ ? "warning"
477
+ : this.options.failoninfo
478
+ ? "info"
479
+ : "none";
468
480
  if (failureLevel === "none") {
469
481
  return;
470
482
  }
@@ -475,21 +487,27 @@ class NpmGroovyLint {
475
487
 
476
488
  // Fail on error
477
489
  if (failureLevel === "error" && errorNb > 0) {
478
- console.error(`Failure: ${this.lintResult.summary.totalFoundErrorNumber} error(s) have been found`);
490
+ if (!["json", "sarif", "stdout"].includes(this.outputType)) {
491
+ console.error(`Failure: ${this.lintResult.summary.totalFoundErrorNumber} error(s) have been found`);
492
+ }
479
493
  this.status = 1;
480
494
  }
481
495
  // Fail on warning
482
496
  else if (failureLevel === "warning" && (errorNb > 0 || warningNb > 0)) {
483
- console.error(
484
- `Failure: ${this.lintResult.summary.totalFoundErrorNumber} error(s) have been found \n ${this.lintResult.summary.totalFoundWarningNumber} warning(s) have been found`
485
- );
497
+ if (!["json", "sarif", "stdout"].includes(this.outputType)) {
498
+ console.error(
499
+ `Failure: ${this.lintResult.summary.totalFoundErrorNumber} error(s) have been found \n ${this.lintResult.summary.totalFoundWarningNumber} warning(s) have been found`
500
+ );
501
+ }
486
502
  this.status = 1;
487
503
  }
488
504
  // Fail on info
489
505
  else if (failureLevel === "info" && (errorNb > 0 || warningNb > 0 || infoNb > 0)) {
490
- console.error(
491
- `Failure: ${this.lintResult.summary.totalFoundErrorNumber} error(s) have been found \n ${this.lintResult.summary.totalFoundWarningNumber} warning(s) have been found \n ${this.lintResult.summary.totalFoundInfoNumber} info(s) have been found`
492
- );
506
+ if (!["json", "sarif", "stdout"].includes(this.outputType)) {
507
+ console.error(
508
+ `Failure: ${this.lintResult.summary.totalFoundErrorNumber} error(s) have been found \n ${this.lintResult.summary.totalFoundWarningNumber} warning(s) have been found \n ${this.lintResult.summary.totalFoundInfoNumber} info(s) have been found`
509
+ );
510
+ }
493
511
  this.status = 1;
494
512
  }
495
513
  }
package/lib/output.js CHANGED
@@ -205,7 +205,9 @@ async function processOutput(outputType, output, lintResult, options, fixer = nu
205
205
  outputString = JSON.stringify(lintResult);
206
206
  console.log(outputString);
207
207
  }
208
- } else if (outputType === "sarif") {
208
+ }
209
+ // SARIF results
210
+ else if (outputType === "sarif") {
209
211
  const sarifJsonString = buildSarifResult(lintResult);
210
212
  // SARIF file
211
213
  if (output.endsWith(".sarif")) {
@@ -219,6 +221,10 @@ async function processOutput(outputType, output, lintResult, options, fixer = nu
219
221
  console.log(sarifJsonString);
220
222
  }
221
223
  }
224
+ // stdout result for format / fix with source sent as stdin
225
+ else if (outputType === "stdout") {
226
+ console.log(lintResult.files[0].updatedSource);
227
+ }
222
228
  return outputString;
223
229
  }
224
230
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "npm-groovy-lint",
3
- "version": "10.0.1",
3
+ "version": "10.1.0",
4
4
  "description": "Lint, format and auto-fix your Groovy / Jenkinsfile / Gradle files",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -49,6 +49,7 @@
49
49
  "axios": "^0.21.1",
50
50
  "chalk": "^4.1.2",
51
51
  "cli-progress": "^3.10.0",
52
+ "commondir": "^1.0.1",
52
53
  "debug": "^4.1.1",
53
54
  "decode-html": "^2.0.0",
54
55
  "find-java-home": "^1.1.0",