Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
se.bjurr.violations.main.Runner Maven / Gradle / Ivy
package se.bjurr.violations.main;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;
import static se.bjurr.violations.git.ViolationsReporterApi.violationsReporterApi;
import static se.bjurr.violations.git.ViolationsReporterDetailLevel.VERBOSE;
import static se.bjurr.violations.lib.ViolationsApi.violationsApi;
import static se.bjurr.violations.lib.model.SEVERITY.INFO;
import static se.softhouse.jargo.Arguments.bigDecimalArgument;
import static se.softhouse.jargo.Arguments.booleanArgument;
import static se.softhouse.jargo.Arguments.enumArgument;
import static se.softhouse.jargo.Arguments.fileArgument;
import static se.softhouse.jargo.Arguments.helpArgument;
import static se.softhouse.jargo.Arguments.integerArgument;
import static se.softhouse.jargo.Arguments.optionArgument;
import static se.softhouse.jargo.Arguments.stringArgument;
import static se.softhouse.jargo.CommandLineParser.withArguments;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.script.ScriptException;
import se.bjurr.violations.git.ViolationsGit;
import se.bjurr.violations.git.ViolationsReporterDetailLevel;
import se.bjurr.violations.lib.FilteringViolationsLogger;
import se.bjurr.violations.lib.ViolationsLogger;
import se.bjurr.violations.lib.model.SEVERITY;
import se.bjurr.violations.lib.model.Violation;
import se.bjurr.violations.lib.model.codeclimate.CodeClimateTransformer;
import se.bjurr.violations.lib.model.sarif.SarifTransformer;
import se.bjurr.violations.lib.parsers.JacocoParser;
import se.bjurr.violations.lib.parsers.JacocoParserSettings;
import se.bjurr.violations.lib.parsers.ViolationsParser;
import se.bjurr.violations.lib.reports.Parser;
import se.bjurr.violations.lib.util.Filtering;
import se.bjurr.violations.violationslib.com.google.gson.Gson;
import se.bjurr.violations.violationslib.com.google.gson.GsonBuilder;
import se.softhouse.jargo.Argument;
import se.softhouse.jargo.ArgumentException;
import se.softhouse.jargo.ParsedArguments;
public class Runner {
private static final String SHOW_JSON_CONFIG = "-show-json-config";
private static final String VIOLATIONS_CONFIG = "VIOLATIONS_CONFIG";
private ViolationsConfig violationsConfig = new ViolationsConfig();
public void main(final String args[]) throws Exception {
final Argument> helpArgument = helpArgument("-h", "--help");
final String parsersString =
Arrays.asList(Parser.values()).stream()
.map((it) -> it.toString())
.collect(Collectors.joining(", "));
final Argument>> violationsArg =
stringArgument("--violations", "-v")
.arity(4)
.repeated()
.description(
"The violations to look for. where PARSER is one of: "
+ parsersString
+ "\n Example: -v \"JSHINT\" \".\" \".*/jshint.xml$\" \"JSHint\"")
.build();
final Argument minSeverityArg =
enumArgument(SEVERITY.class, "-severity", "-s")
.defaultValue(INFO)
.description("Minimum severity level to report.")
.build();
final Argument codeClimateFileArg =
fileArgument("-code-climate", "-cc")
.description("Create a CodeClimate file with all the violations.")
.build();
final Argument sarifFileArg =
fileArgument("-sarif", "-ss")
.description("Create a Sarif file with all the violations.")
.build();
final Argument violationsFileArg =
fileArgument("-violations-file", "-vf")
.description("Create a JSON file with all the violations.")
.build();
final Argument maxViolationsArg =
integerArgument("-max-violations", "-mv")
.defaultValue(Integer.MAX_VALUE)
.description("Will fail the build if total number of found violations is higher.")
.build();
final Argument detailLevelArg =
enumArgument(ViolationsReporterDetailLevel.class, "-detail-level", "-dl")
.defaultValue(VERBOSE)
.description("Verbosity")
.build();
final Argument printViolationsArg =
booleanArgument("-print-violations", "-pv")
.defaultValue(true)
.description("Will print violations found")
.build();
final Argument gitRepoArg =
fileArgument("-git-repo", "-gr")
.defaultValue(new File("."))
.description("Where to look for Git.")
.build();
final Argument diffFrom =
stringArgument("-diff-from", "-df")
.description("Can be empty (ignored), Git-commit or any Git-reference")
.build();
final Argument diffTo =
stringArgument("-diff-to", "-dt")
.description("Can be empty (ignored), Git-commit or any Git-reference")
.build();
final Argument diffMinSeverity =
enumArgument(SEVERITY.class, "-diff-severity", "-ds").defaultValue(INFO).build();
final Argument diffPrintViolations =
booleanArgument("-diff-print-violations", "-dpv")
.defaultValue(false)
.description("Will print violations found in diff")
.build();
final Argument diffMaxViolations =
integerArgument("-diff-max-violations", "-dmv")
.defaultValue(Integer.MAX_VALUE)
.description("Will fail the build if total number of found violations is higher")
.build();
final Argument diffDetailLevel =
enumArgument(ViolationsReporterDetailLevel.class, "-diff-detail-level", "-ddl")
.defaultValue(VERBOSE)
.build();
final Argument maxReporterColumnWidth =
integerArgument("-max-reporter-column-width", "-mrcw")
.description("0 means no limit")
.defaultValue(0)
.build();
final Argument maxRuleColumnWidth =
integerArgument("-max-rule-column-width", "-mrucw")
.description("0 means no limit")
.defaultValue(10)
.build();
final Argument maxSeverityColumnWidth =
integerArgument("-max-severity-column-width", "-mscw")
.description("0 means no limit")
.defaultValue(0)
.build();
final Argument maxLineColumnWidth =
integerArgument("-max-line-column-width", "-mlcw")
.description("0 means no limit")
.defaultValue(0)
.build();
final Argument maxMessageColumnWidth =
integerArgument("-max-message-column-width", "-mmcw")
.description("0 means no limit")
.defaultValue(50)
.build();
final Argument showDebugInfo =
optionArgument("-show-debug-info")
.description(
"Please run your command with this parameter and supply output when reporting bugs.")
.build();
final Argument showJsonConfig =
optionArgument(SHOW_JSON_CONFIG)
.description("Will print the given config as JSON.")
.build();
final Argument configFileArg =
fileArgument("-config-file", "-cf")
.defaultValue(new File("."))
.description(
"Will read config from given file. Can also be configured"
+ " with environment variable "
+ VIOLATIONS_CONFIG
+ ". Format is what you get from "
+ SHOW_JSON_CONFIG
+ ".")
.build();
final Argument jacocoMinLineCount =
integerArgument("-jacoco-min-line-count", "-jmlc")
.description("Minimum line count in Jacoco that will generate a violation.")
.defaultValue(JacocoParserSettings.DEFAULT_MIN_LINE_COUNT)
.build();
final Argument jacocoMinCoverage =
bigDecimalArgument("-jacoco-min-coverage", "-jmc")
.description("Minimum coverage in Jacoco that will generate a violation.")
.defaultValue(BigDecimal.valueOf(JacocoParserSettings.DEFAULT_MIN_COVERAGE))
.build();
try {
final ParsedArguments parsed =
withArguments( //
showJsonConfig, //
configFileArg, //
showDebugInfo, //
maxViolationsArg, //
helpArgument, //
violationsArg, //
minSeverityArg, //
codeClimateFileArg, //
sarifFileArg, //
violationsFileArg, //
detailLevelArg, //
printViolationsArg, //
diffFrom, //
diffTo, //
diffMinSeverity, //
diffPrintViolations, //
diffMaxViolations, //
diffDetailLevel, //
maxReporterColumnWidth, //
maxRuleColumnWidth, //
maxSeverityColumnWidth, //
maxLineColumnWidth, //
maxMessageColumnWidth, //
gitRepoArg, //
jacocoMinLineCount, //
jacocoMinCoverage) //
.parse(args);
final String violationsConfigPropertyValue = System.getenv(VIOLATIONS_CONFIG);
final boolean violationsConfigPropertyValueGiven = violationsConfigPropertyValue != null;
final boolean shouldUseConfigFile =
parsed.wasGiven(configFileArg) || violationsConfigPropertyValueGiven;
if (shouldUseConfigFile) {
Path jsonFile = null;
if (parsed.wasGiven(configFileArg)) {
jsonFile = parsed.get(configFileArg).toPath();
}
if (violationsConfigPropertyValueGiven) {
jsonFile = Paths.get(violationsConfigPropertyValue);
}
final String json = new String(Files.readAllBytes(jsonFile), UTF_8);
this.violationsConfig = new Gson().fromJson(json, ViolationsConfig.class);
} else {
this.violationsConfig.setViolations(parsed.get(violationsArg));
this.violationsConfig.setMinSeverity(parsed.get(minSeverityArg));
this.violationsConfig.setMaxViolations(parsed.get(maxViolationsArg));
this.violationsConfig.setPrintViolations(parsed.get(printViolationsArg));
this.violationsConfig.setDetailLevel(parsed.get(detailLevelArg));
this.violationsConfig.setPrintViolations(parsed.get(printViolationsArg));
this.violationsConfig.setDiffFrom(parsed.get(diffFrom));
this.violationsConfig.setDiffTo(parsed.get(diffTo));
this.violationsConfig.setDiffMinSeverity(parsed.get(diffMinSeverity));
this.violationsConfig.setDiffPrintViolations(parsed.get(diffPrintViolations));
this.violationsConfig.setDiffMaxViolations(parsed.get(diffMaxViolations));
this.violationsConfig.setDiffDetailLevel(parsed.get(diffDetailLevel));
this.violationsConfig.setMaxReporterColumnWidth(parsed.get(maxReporterColumnWidth));
this.violationsConfig.setMaxRuleColumnWidth(parsed.get(maxRuleColumnWidth));
this.violationsConfig.setMaxSeverityColumnWidth(parsed.get(maxSeverityColumnWidth));
this.violationsConfig.setMaxLineColumnWidth(parsed.get(maxLineColumnWidth));
this.violationsConfig.setMaxMessageColumnWidth(parsed.get(maxMessageColumnWidth));
this.violationsConfig.setGitRepo(parsed.get(gitRepoArg));
this.violationsConfig.setJacocoMinCoverage(parsed.get(jacocoMinCoverage).doubleValue());
this.violationsConfig.setJacocoMinLineCount(parsed.get(jacocoMinLineCount));
if (parsed.wasGiven(codeClimateFileArg)) {
this.violationsConfig.setCodeClimateFile(parsed.get(codeClimateFileArg));
} else {
this.violationsConfig.setCodeClimateFile(null);
}
if (parsed.wasGiven(sarifFileArg)) {
this.violationsConfig.setSarifFile(parsed.get(sarifFileArg));
} else {
this.violationsConfig.setSarifFile(null);
}
if (parsed.wasGiven(violationsFileArg)) {
this.violationsConfig.setViolationsFile(parsed.get(violationsFileArg));
} else {
this.violationsConfig.setViolationsFile(null);
}
this.violationsConfig.setShowDebugInfo(parsed.wasGiven(showDebugInfo));
if (this.violationsConfig.isShowDebugInfo()) {
System.out.println(
"Given parameters:\n"
+ Arrays.asList(args).stream()
.map((it) -> it.toString())
.collect(Collectors.joining(", "))
+ "\n\nParsed parameters:\n"
+ this.toString());
}
}
if (parsed.wasGiven(showJsonConfig)) {
final Gson gson = new GsonBuilder().setPrettyPrinting().create();
final String jsonString = gson.toJson(this.violationsConfig);
System.out.println(jsonString);
return;
}
this.violationsConfig.setViolationsLogger(
new ViolationsLogger() {
@Override
public void log(final Level level, final String string) {
System.out.println(level + " " + string);
}
@Override
public void log(final Level level, final String string, final Throwable t) {
final StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
System.out.println(level + " " + string + "\n" + sw.toString());
}
});
if (!this.violationsConfig.isShowDebugInfo()) {
this.violationsConfig.setViolationsLogger(
FilteringViolationsLogger.filterLevel(this.violationsConfig.getViolationsLogger()));
}
this.performTask();
} catch (final ArgumentException exception) {
System.out.println(exception.getMessageAndUsage());
System.exit(1);
}
}
public void performTask() throws Exception {
final Set allParsedViolations = new TreeSet<>();
final Set allParsedViolationsInDiff = new TreeSet<>();
for (final List configuredViolation : this.violationsConfig.getViolations()) {
final Set parsedViolations = this.getAllParsedViolations(configuredViolation);
allParsedViolations.addAll(
this.getFiltered(parsedViolations, this.violationsConfig.getMinSeverity()));
allParsedViolationsInDiff.addAll(this.getAllViolationsInDiff(parsedViolations));
}
if (this.violationsConfig.getCodeClimateFile() != null) {
this.createJsonFile(
CodeClimateTransformer.fromViolations(allParsedViolations),
this.violationsConfig.getCodeClimateFile());
}
if (this.violationsConfig.getSarifFile() != null) {
this.createJsonFile(
SarifTransformer.fromViolations(allParsedViolations),
this.violationsConfig.getSarifFile());
}
if (this.violationsConfig.getViolationsFile() != null) {
this.createJsonFile(allParsedViolations, this.violationsConfig.getViolationsFile());
}
this.checkGlobalViolations(allParsedViolations);
this.checkDiffViolations(allParsedViolationsInDiff);
}
private void createJsonFile(final Object object, final File file) throws IOException {
final String codeClimateReport = new GsonBuilder().setPrettyPrinting().create().toJson(object);
Files.write(
file.toPath(),
codeClimateReport.getBytes(StandardCharsets.UTF_8),
TRUNCATE_EXISTING,
CREATE,
WRITE);
}
private void checkGlobalViolations(final Set violations) throws ScriptException {
final boolean tooManyViolations = violations.size() > this.violationsConfig.getMaxViolations();
if (!tooManyViolations && !this.violationsConfig.isPrintViolations()) {
return;
}
final String report =
violationsReporterApi()
.withViolations(violations)
.withMaxLineColumnWidth(this.violationsConfig.getMaxLineColumnWidth())
.withMaxMessageColumnWidth(this.violationsConfig.getMaxMessageColumnWidth())
.withMaxReporterColumnWidth(this.violationsConfig.getMaxReporterColumnWidth()) //
.withMaxRuleColumnWidth(this.violationsConfig.getMaxRuleColumnWidth()) //
.withMaxSeverityColumnWidth(this.violationsConfig.getMaxSeverityColumnWidth()) //
.getReport(this.violationsConfig.getDetailLevel());
if (tooManyViolations) {
System.err.println("\nViolations in repo\n\n" + report);
throw new ScriptException(
"Too many violations found, max is "
+ this.violationsConfig.getMaxViolations()
+ " but found "
+ violations.size());
} else {
if (this.violationsConfig.isPrintViolations()) {
System.out.println("\nViolations in repo\n\n" + report);
}
}
}
private void checkDiffViolations(final Set violations) throws ScriptException {
final boolean tooManyViolations =
violations.size() > this.violationsConfig.getDiffMaxViolations();
if (!tooManyViolations && !this.violationsConfig.isDiffPrintViolations()) {
return;
}
final String report =
violationsReporterApi()
.withViolations(violations)
.withMaxLineColumnWidth(this.violationsConfig.getMaxLineColumnWidth())
.withMaxMessageColumnWidth(this.violationsConfig.getMaxMessageColumnWidth())
.withMaxReporterColumnWidth(this.violationsConfig.getMaxReporterColumnWidth()) //
.withMaxRuleColumnWidth(this.violationsConfig.getMaxRuleColumnWidth()) //
.withMaxSeverityColumnWidth(this.violationsConfig.getMaxSeverityColumnWidth()) //
.getReport(this.violationsConfig.getDiffDetailLevel());
if (tooManyViolations) {
System.err.println("\nViolations in repo\n\n" + report);
throw new ScriptException(
"Too many violations found in diff, max is "
+ this.violationsConfig.getMaxViolations()
+ " but found "
+ violations.size());
} else {
if (this.violationsConfig.isDiffPrintViolations()) {
System.out.println("\nViolations in diff\n\n" + report);
}
}
}
private Set getAllViolationsInDiff(final Set unfilteredViolations)
throws Exception {
if (!this.isDefined(this.violationsConfig.getDiffFrom())
|| !this.isDefined(this.violationsConfig.getDiffTo())) {
// No references specified, will not report violations in diff
return new TreeSet<>();
} else {
final Set candidates =
this.getFiltered(unfilteredViolations, this.violationsConfig.getDiffMinSeverity());
return new ViolationsGit(this.violationsConfig.getViolationsLogger(), candidates) //
.getViolationsInChangeset(
this.violationsConfig.getGitRepo(),
this.violationsConfig.getDiffFrom(),
this.violationsConfig.getDiffTo());
}
}
private Set getFiltered(final Set unfiltered, final SEVERITY filter) {
if (filter != null) {
return Filtering.withAtLEastSeverity(unfiltered, filter);
}
return unfiltered;
}
private Set getAllParsedViolations(final List configuredViolation) {
final String reporter = configuredViolation.size() >= 4 ? configuredViolation.get(3) : null;
ViolationsParser parser = null;
try {
final String parserName = configuredViolation.get(0);
if (parserName.equals(Parser.JACOCO.name())) {
final int minLineCount = this.violationsConfig.getJacocoMinLineCount();
final double minCoverage = this.violationsConfig.getJacocoMinCoverage();
final JacocoParserSettings settings = new JacocoParserSettings(minLineCount, minCoverage);
parser = new JacocoParser(settings);
} else {
parser = Parser.valueOf(parserName).getViolationsParser();
}
} catch (final Exception e) {
throw new RuntimeException(
Arrays.asList(Parser.values()).stream()
.map((it) -> it.toString())
.collect(Collectors.joining("\n")),
e);
}
final Set parsedViolations =
violationsApi() //
.withViolationsLogger(this.violationsConfig.getViolationsLogger()) //
.withViolationsParser(parser) //
.inFolder(configuredViolation.get(1)) //
.withPattern(configuredViolation.get(2)) //
.withReporter(reporter) //
.violations();
return parsedViolations;
}
private boolean isDefined(final String str) {
return str != null && !str.isEmpty();
}
@Override
public String toString() {
return "Runner [violations="
+ this.violationsConfig.getViolations()
+ ", minSeverity="
+ this.violationsConfig.getMinSeverity()
+ ", detailLevel="
+ this.violationsConfig.getDetailLevel()
+ ", maxViolations="
+ this.violationsConfig.getMaxViolations()
+ ", printViolations="
+ this.violationsConfig.isPrintViolations()
+ ", diffFrom="
+ this.violationsConfig.getDiffFrom()
+ ", diffTo="
+ this.violationsConfig.getDiffTo()
+ ", diffMinSeverity="
+ this.violationsConfig.getDiffMinSeverity()
+ ", gitRepo="
+ this.violationsConfig.getGitRepo()
+ ", diffPrintViolations="
+ this.violationsConfig.isDiffPrintViolations()
+ ", diffMaxViolations="
+ this.violationsConfig.getDiffMaxViolations()
+ ", diffDetailLevel="
+ this.violationsConfig.getDiffDetailLevel()
+ ", maxReporterColumnWidth="
+ this.violationsConfig.getMaxReporterColumnWidth()
+ ", maxRuleColumnWidth="
+ this.violationsConfig.getMaxRuleColumnWidth()
+ ", maxSeverityColumnWidth="
+ this.violationsConfig.getMaxSeverityColumnWidth()
+ ", maxLineColumnWidth="
+ this.violationsConfig.getMaxLineColumnWidth()
+ ", maxMessageColumnWidth="
+ this.violationsConfig.getMaxMessageColumnWidth()
+ "]";
}
}