Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check parse error in all files when called via CLI #74

Merged
merged 1 commit into from
Jul 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [5.7.0] 2020-07-23

- [(#62)](https://github.com/nvuillam/npm-groovy-lint/pull/74) Check parse error in all files when called via CLI . Closes [#69](https://github.com/nvuillam/npm-groovy-lint/issues/69)

## [5.6.1] 2020-07-20

Fixes:
Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Manifest-Version: 1.0
Created-By: 1.8.0_144 (Oracle Corporation)
Main-Class: com.nvuillam.CodeNarcServer
Class-Path: CodeNarc-1.5.jar groovy/lib/groovy-3.0.3.jar groovy/lib/groovy-templates-3.0.3.jar groovy/lib/groovy-xml-3.0.3.jar groovy/lib/groovy-json-3.0.3.jar slf4j-api-1.7.9.jar log4j-slf4j-impl-2.13.0.jar log4j-api-2.13.0.jar log4j-core-2.13.0.jar GMetrics-0.7.jar
Class-Path: CodeNarc-1.5.jar groovy/lib/groovy-3.0.3.jar groovy/lib/groovy-templates-3.0.3.jar groovy/lib/groovy-xml-3.0.3.jar groovy/lib/groovy-json-3.0.3.jar groovy/lib/groovy-ant-3.0.3.jar groovy/lib/ant-1.10.7.jar groovy/lib/ant-launcher-1.10.7.jar slf4j-api-1.7.9.jar log4j-slf4j-impl-2.13.0.jar log4j-api-2.13.0.jar log4j-core-2.13.0.jar GMetrics-0.7.jar
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ Based on [CodeNarc](http://codenarc.github.io/CodeNarc/) , this out of the box p

- Use option **--format** to format & prettify source code (beta)
- Use option **--fix** to activate autofixing of fixable rules (beta)
- Use option **--parse** to also detect future compilation errors

Easy to integrate in a CD/CI process (Jenkins Pipeline,CircleCI...) to lint your groovy or Jenkinsfile at each build :)

You can also use this package in [Visual Studio Code Groovy Lint extension](https://marketplace.visualstudio.com/items?itemName=NicolasVuillamy.vscode-groovy-lint)
You can also use this package in [Visual Studio Code Groovy Lint extension](https://marketplace.visualstudio.com/items?itemName=NicolasVuillamy.vscode-groovy-lint) and [Docker Image](#CALL-VIA-DOCKER)

![https://github.com/nvuillam/npm-groovy-lint/raw/master/doc/images/npm-groovy-lint-results.png](https://github.com/nvuillam/npm-groovy-lint/raw/master/doc/images/npm-groovy-lint-results.png)

Expand Down Expand Up @@ -52,7 +51,7 @@ Node.js >= 12 is required to run this package. If you can't upgrade, you can use
| -l<br/> --loglevel | String | Log level (error,warning or info)<br/>Default: info |
| --failon | String | Defines the error level where CLI will fail (return code = 1). error,warning,info or none. Each failure level includes the more critical ones. |
| -c<br/> --config | String | Custom path to [GroovyLint config file](#Configuration), or preset config `recommended|recommended-jenkinsfile|all`<br/> Default: Browse current directory to find `.groovylintrc.json|js|yml|package.json` config file, or default npm-groovy-lint config if not defined.<br/>Note: command-line arguments have priority on config file properties |
| --parse | Boolean | Try to compile the source code and return parse errors (works only with source argument) |
| --parse | Boolean | Try to compile the source code and return parse errors (since v5.7.0, default to true, use --no-parse to deactivate) |
| --format | Boolean | (beta) Format source code |
| --fix | Boolean | (beta) Automatically fix problems when possible<br/> See [Autofixable rules](#Autofixable-rules) |
| -x<br/> --fixrules | String | Option for --fix argument: List of rule identifiers to fix (if not specified, all available fixes will be applied). See [Autofixable rules](#Autofixable-rules) <br/> Examples:<br/> - `"SpaceBeforeClosingBrace,SpaceAfterClosingBrace,UnusedImport"`<br/> - `"Indentation"`<br/> |
Expand Down Expand Up @@ -372,6 +371,10 @@ This package uses :

## RELEASE NOTES

### [5.7.0] 2020-07-23

- [(#62)](https://github.com/nvuillam/npm-groovy-lint/pull/74) Check parse error in all files when called via CLI . Closes [#69](https://github.com/nvuillam/npm-groovy-lint/issues/69)

### [5.6.1] 2020-07-20

Fixes:
Expand Down
97 changes: 65 additions & 32 deletions groovy/src/main/com/nvuillam/CodeNarcServer.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ package com.nvuillam
import com.sun.net.httpserver.HttpServer
import com.sun.net.httpserver.HttpExchange
import java.net.InetSocketAddress
import java.io.PrintStream

// Concurrency & Timer management
import java.util.concurrent.ConcurrentHashMap
Expand All @@ -19,7 +18,6 @@ import java.util.concurrent.ExecutorService
import java.util.concurrent.TimeUnit
import java.util.concurrent.ThreadFactory
import java.util.Timer
import java.util.TimerTask

// Groovy Json Management
import groovy.json.JsonSlurper
Expand Down Expand Up @@ -130,31 +128,8 @@ class CodeNarcServer {
storeThread(requestKey, thread, ex)
}

// Try to parse if requested to get compilation errors
if (bodyObj.parse == true && bodyObj.file) {
try {
new GroovyShell().parse(new File(bodyObj.file))
println 'PARSE SUCCESS'
respObj.parseErrors = []
}
catch (MultipleCompilationErrorsException ep) {
def excptnJsonTxt = JsonOutput.toJson(ep)
def compileErrors = ep.getErrorCollector().getErrors()
respObj.parseErrors = compileErrors
println 'PARSE ERROR (MultipleCompilationErrorsException)\n' + excptnJsonTxt
}
catch (CompilationFailedException ep) {
def excptnJsonTxt = JsonOutput.toJson(ep)
def compileErrors = ep.getErrorCollector().getErrors()
respObj.parseErrors = compileErrors
println 'Parse error (CompilationFailedException)\n' + excptnJsonTxt
}
catch (Exception ep) {
def excptnJsonTxt = JsonOutput.toJson(ep)
respObj.parseErrors = compileErrors
println 'Parse error (Other)\n' + excptnJsonTxt
}
}
// Parse files to detect parse errors
respObj.parseErrors = parseFiles(bodyObj)

// Call CodeNarc
def codeNarcArgs = bodyObj.codeNarcArgs
Expand All @@ -163,7 +138,7 @@ class CodeNarcServer {
http.responseHeaders.add('Content-type', 'application/json')
http.sendResponseHeaders(200, 0)
respObj.status = 'success'
respObj.stdout = StorePrintStream.printList.join('\n')
respObj.stdout = StorePrintStream.collectAndReset().join('\n')

// Build response
def respJson = JsonOutput.toJson(respObj)
Expand All @@ -172,7 +147,7 @@ class CodeNarcServer {
}
} catch (InterruptedException ie) {
def respObj = [ status:'cancelledByDuplicateRequest' ,
stdout:StorePrintStream.printList.join('\n'),
stdout: StorePrintStream.collectAndReset().join('\n'),
]
def respJson = JsonOutput.toJson(respObj)
http.responseHeaders.add('Content-type', 'application/json')
Expand All @@ -184,7 +159,7 @@ class CodeNarcServer {
} catch (Throwable t) {
def respObj = [ status:'error' ,
errorDtl:t.getStackTrace().join('\n'),
stdout:StorePrintStream.printList.join('\n'),
stdout: StorePrintStream.collectAndReset().join('\n'),
exceptionType: t.getClass().getName(),
]
def respJson = JsonOutput.toJson(respObj)
Expand Down Expand Up @@ -243,9 +218,61 @@ class CodeNarcServer {
}
}

private Map<String,List<Error>> parseFiles(def bodyObj) {
def parseErrors = [:]
if (bodyObj.parse != true) {
return parseErrors
}
// Parse unique file
else if (bodyObj.file) {
File f = new File(bodyObj.file)
parseErrors.put(f.getAbsolutePath(), parseFile(f))
return parseErrors
}

// Ant style pattern is used: list all files
println 'Ant file scanner in ' + bodyObj.codeNarcBaseDir + ', includes ' + bodyObj.codeNarcIncludes + ', excludes ' + bodyObj.codeNarcExcludes
def ant = new groovy.ant.AntBuilder()
def scanner = ant.fileScanner {
fileset(dir: bodyObj.codeNarcBaseDir) {
include(name: bodyObj.codeNarcIncludes)
exclude(name : (bodyObj.codeNarcExcludes) ? bodyObj.codeNarcExcludes : 'no')
}
}
// Parse collected files
for (f in scanner) {
parseErrors.put(f.getAbsolutePath(), parseFile(f))
}
return parseErrors
}

private List<Error> parseFile(File file) {
// Try to parse if requested to get compilation errors
List<Error> parseErrors = []
try {
new GroovyShell().parse(file)
println 'PARSE SUCCESS: ' + file.getAbsolutePath()
}
catch (MultipleCompilationErrorsException ep) {
def excptnJsonTxt = JsonOutput.toJson(ep)
parseErrors = ep.getErrorCollector().getErrors()
println 'Parse error (MultipleCompilationErrorsException): ' + file.getAbsolutePath() + '\n' + excptnJsonTxt
}
catch (CompilationFailedException ep) {
def excptnJsonTxt = JsonOutput.toJson(ep)
parseErrors = ep.getErrorCollector().getErrors()
println 'Parse error (CompilationFailedException): ' + file.getAbsolutePath() + '\n' + excptnJsonTxt
}
catch (Exception ep) {
def excptnJsonTxt = JsonOutput.toJson(ep)
parseErrors = ep.getErrorCollector().getErrors()
println 'Parse error (Other): ' + file.getAbsolutePath() + '\n' + excptnJsonTxt
}
return parseErrors
}

private void storeThread(String requestKey, def thread, ExecutorService ex) {
def threadName = thread.getName()
//currentThreads.put(requestKey, [threadInstance:thread, name: threadName])
currentThreads.put(requestKey, threadName)
println 'THREADS: (var ' + currentThreads.size() + ', threadPool ' + ex.getActiveCount() + ')\n' + currentThreads.toString()
}
Expand Down Expand Up @@ -291,12 +318,18 @@ class CodeNarcServer {
@CompileDynamic
class StorePrintStream extends PrintStream {

static final List<String> printList = [] as Queue
static List<String> printList = [] as Queue

StorePrintStream(PrintStream org) {
super(org)
}

static List<String> collectAndReset() {
List<String> printListResult = printList.collect()
printList = []
return printListResult
}

@Override
void println(String line) {
printList.add(line)
Expand Down
23 changes: 19 additions & 4 deletions lib/codenarc-caller.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class CodeNarcCaller {
maximumJavaVersion: 11.99,
mainClass: "org.codenarc.CodeNarc",
classPath:
"java/CodeNarc-1.5.jar:java/groovy/lib/groovy-3.0.3.jar:java/groovy/lib/groovy-templates-3.0.3.jar:java/groovy/lib/groovy-xml-3.0.3.jar:java/groovy/lib/groovy-json-3.0.3.jar:java/slf4j-api-1.7.9.jar:java/log4j-slf4j-impl-2.13.0.jar:java/log4j-api-2.13.0.jar:java/log4j-core-2.13.0.jar:java/GMetrics-0.7.jar:java/*"
"java/CodeNarc-1.5.jar:java/groovy/lib/groovy-3.0.3.jar:java/groovy/lib/groovy-templates-3.0.3.jar:java/groovy/lib/groovy-xml-3.0.3.jar:java/groovy/lib/groovy-json-3.0.3.jar:java/groovy/lib/groovy-ant-3.0.3.jar:java/groovy/lib/ant-1.10.7.jar:java/groovy/lib/ant-launcher-1.10.7.jar:java/slf4j-api-1.7.9.jar:java/log4j-slf4j-impl-2.13.0.jar:java/log4j-api-2.13.0.jar:java/log4j-core-2.13.0.jar:java/GMetrics-0.7.jar:java/*"
}
};

Expand Down Expand Up @@ -68,7 +68,10 @@ class CodeNarcCaller {
url: requestUri,
data: {
codeNarcArgs: codeNarcArgsString,
parse: this.options.parse ? true : false,
codeNarcBaseDir: this.execOpts.codeNarcBaseDir,
codeNarcIncludes: this.execOpts.codeNarcIncludes,
codeNarcExcludes: this.execOpts.codeNarcExcludes,
parse: this.options.parse !== false && this.execOpts.onlyCodeNarc === false ? true : false,
file: this.execOpts.groovyFileName ? this.execOpts.groovyFileName : null,
requestKey: this.execOpts.requestKey || null
},
Expand Down Expand Up @@ -98,10 +101,22 @@ class CodeNarcCaller {
status: 9
};
} else {
console.error("CodeNarcServer unexpected error:\n" + JSON.stringify(e, null, 2));
console.error(
"CodeNarcServer unexpected error:\n" +
JSON.stringify(e, null, 2) +
"\n" +
(e.response && e.response.data && e.response.data.errorDtl ? JSON.stringify(e.response.data.errorDtl, null, 2) : undefined)
);
}
this.serverStatus = "error";
return { status: 2, error: { msg: e.message, stack: e.stack } };
return {
status: 2,
error: {
msg: e.message,
stack: e.stack,
responseData: e.response && e.response.data && e.response.data.errorDtl ? e.response.data.errorDtl : undefined
}
};
}

// Success result
Expand Down
Loading