Skip to content

Allow configuration overrides #26

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

Merged
merged 11 commits into from
Oct 13, 2017
Merged
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -39,4 +39,4 @@ RUN gradle clean build -x test

USER app
WORKDIR /code
CMD cp -R /code /tmp/ && /usr/src/app/build/codeclimate-sonar /tmp/code
CMD cp -R /code /tmp/ && /usr/src/app/build/codeclimate-sonar /tmp/code /config.json
5 changes: 3 additions & 2 deletions bin/codeclimate-sonar
Original file line number Diff line number Diff line change
@@ -6,12 +6,13 @@ LIBS=$(find ${BUILD_DIR}/libs -name "*.jar" | tr "\n" ":")
CORE=$(find ${BUILD_DIR}/libs -name "sonarlint-core*.jar" -or -name "sonarlint-client-api*.jar" | tr "\n" ":")

CODE_DIR=$1; shift
CONFIG_FILE=$1; shift

java \
-cp ${APP}:${CORE}:${LIBS} \
-Djava.awt.headless=true \
-Dsonarlint.home="${BUILD_DIR}" \
-Dproject.home="${CODE_DIR}" \
-Dconfig="/config.json" \
-Dconfig="${CONFIG_FILE}" \
-Dorg.freemarker.loggerLibrary=none \
cc.App --src "**/*.java" $@
cc.App $@
2 changes: 2 additions & 0 deletions fixtures/multiple_paths/src/test2/java/Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
public class Test {
}
43 changes: 40 additions & 3 deletions src/main/java/cc/App.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,51 @@
package cc;

import cc.files.Finder;
import org.sonarlint.cli.CustomMain;
import org.sonarlint.cli.InputFileFinder;
import org.sonarlint.cli.Options;
import org.sonarlint.cli.analysis.SonarLintFactory;
import org.sonarlint.cli.config.ConfigurationReader;
import org.sonarlint.cli.report.ReportFactory;
import org.sonarlint.cli.util.System2;

import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;

import static org.sonarlint.cli.SonarProperties.PROJECT_HOME;

public class App {
static final int ERROR = 1;

public static void main(String[] args) {
execute(args, System2.INSTANCE);
execute(System2.INSTANCE);
}

public static void execute(System2 system) {
try {
Config config = Config.from(system.getProperty("config"));
Charset charset = config.getCharset();

InputFileFinder fileFinder = new Finder(config.getIncludePaths(), config.getTestsPatterns(), charset);
ReportFactory reportFactory = new cc.report.ReportFactory(charset);
ConfigurationReader reader = new ConfigurationReader();
SonarLintFactory sonarLintFactory = new SonarLintFactory(reader);
Path projectHome = getProjectHome(system);

int exitCode = new CustomMain(new Options(), sonarLintFactory, reportFactory, fileFinder, projectHome).run();
system.exit(exitCode);
} catch (Exception e) {
e.printStackTrace(System.err);
system.exit(ERROR);
}
}

public static void execute(String[] args, System2 system) {
CustomMain.execute(args, system);
private static Path getProjectHome(System2 system) {
String projectHome = system.getProperty(PROJECT_HOME);
if (projectHome == null) {
throw new IllegalStateException("Can't find project home. System property not set: " + PROJECT_HOME);
}
return Paths.get(projectHome);
}
}
39 changes: 37 additions & 2 deletions src/main/java/cc/Config.java
Original file line number Diff line number Diff line change
@@ -6,11 +6,46 @@
import com.google.gson.stream.JsonReader;

import java.io.FileReader;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;

public class Config {
public List<String> includePaths = Arrays.asList("");
private List<String> includePaths = Arrays.asList("");
private EngineConfig config = new EngineConfig();

private class EngineConfig {
String charset;
List<String> testsPatterns;
}

public List<String> getIncludePaths() {
return includePaths;
}

public Charset getCharset() {
return createCharset(config.charset);
}

public String getTestsPatterns() {
return joinPatterns(config.testsPatterns);
}

String joinPatterns(List<String> patterns) {
if (patterns == null) {
return null;
}
return "{" + String.join(",", patterns) + "}";
}


Charset createCharset(String charset) {
if (charset != null) {
return Charset.forName(charset);
} else {
return Charset.defaultCharset();
}
}

public static Config from(String file) {
try {
@@ -20,7 +55,7 @@ public static Config from(String file) {
}
}

private static Gson gson() {
static Gson gson() {
return new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package cc;
package cc.report;

import cc.models.CodeClimateIssue;
import cc.serialization.GsonFactory;
import com.google.gson.Gson;
import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;
import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;
import org.sonarsource.sonarlint.core.tracking.Trackable;

import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Arrays;
import java.util.function.Function;

import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;
import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;
import org.sonarsource.sonarlint.core.tracking.Trackable;

public class JsonReport implements org.sonarlint.cli.report.Reporter {

private static final List<String> VALID_RULE_DETAIL_TYPES = Arrays.asList(
@@ -30,6 +29,7 @@ public JsonReport(String baseDir) {
this.gson = new GsonFactory().create();
}


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(extra line)

@Override
public void execute(String projectName, Date date, Collection<Trackable> trackables, AnalysisResults result, Function<String, RuleDetails> ruleDescriptionProducer) {
for (Trackable trackable : trackables) {
@@ -43,4 +43,4 @@ public void execute(String projectName, Date date, Collection<Trackable> trackab
}
}
}
}
}
19 changes: 19 additions & 0 deletions src/main/java/cc/report/ReportFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cc.report;

import org.sonarlint.cli.report.Reporter;

import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;

public class ReportFactory extends org.sonarlint.cli.report.ReportFactory {
public ReportFactory(Charset charset) {
super(charset);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think there's any worth adding tests for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am actually fine with the SanityCheckTest testing this from an integration perspective.
Having the test in a higher level allows me to easy refactor and move stuff around without needing to update the tests as often.


@Override
public List<Reporter> createReporters(Path basePath) {
return Arrays.asList(new JsonReport(basePath.toString()));
}
}
73 changes: 3 additions & 70 deletions src/main/java/org/sonarlint/cli/CustomMain.java
Original file line number Diff line number Diff line change
@@ -19,86 +19,19 @@
*/
package org.sonarlint.cli;

import cc.Config;
import cc.files.Finder;
import cc.JsonReport;
import org.sonarlint.cli.analysis.SonarLintFactory;
import org.sonarlint.cli.config.ConfigurationReader;
import org.sonarlint.cli.report.ReportFactory;
import org.sonarlint.cli.report.Reporter;
import org.sonarlint.cli.util.Logger;
import org.sonarlint.cli.util.System2;

import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.Arrays;
import java.util.List;

import static org.sonarlint.cli.SonarProperties.PROJECT_HOME;


public class CustomMain extends org.sonarlint.cli.Main {
static final int SUCCESS = 0;
static final int ERROR = 1;
private static final Logger LOGGER = Logger.get();

public CustomMain(Options opts, SonarLintFactory sonarLintFactory, ReportFactory reportFactory, InputFileFinder fileFinder, Path projectHome) {
super(opts, sonarLintFactory, reportFactory, fileFinder, projectHome);
}

public static void execute(String[] args, System2 system) {
Options parsedOpts;
try {
parsedOpts = Options.parse(args);
} catch (ParseException e) {
LOGGER.error("Error parsing arguments: " + e.getMessage(), e);
Options.printUsage();
system.exit(ERROR);
return;
}

Charset charset;
try {
if (parsedOpts.charset() != null) {
charset = Charset.forName(parsedOpts.charset());
} else {
charset = Charset.defaultCharset();
}
} catch (Exception e) {
LOGGER.error("Error creating charset: " + parsedOpts.charset(), e);
system.exit(ERROR);
return;
}

Config config = Config.from(system.getProperty("config"));
InputFileFinder fileFinder = new Finder(config.includePaths, parsedOpts.tests(), charset);
ReportFactory reportFactory = new CustomReportFactory(charset);
ConfigurationReader reader = new ConfigurationReader();
SonarLintFactory sonarLintFactory = new SonarLintFactory(reader);

int ret = new CustomMain(parsedOpts, sonarLintFactory, reportFactory, fileFinder, getProjectHome(system)).run();
system.exit(ret);
return;
}

private static Path getProjectHome(System2 system) {
String projectHome = system.getProperty(PROJECT_HOME);
if (projectHome == null) {
throw new IllegalStateException("Can't find project home. System property not set: " + PROJECT_HOME);
}
return Paths.get(projectHome);
}

private static class CustomReportFactory extends ReportFactory {
public CustomReportFactory(Charset charset) {
super(charset);
}

@Override
public List<Reporter> createReporters(Path basePath) {
return Arrays.asList(new JsonReport(basePath.toString()));
}
@Override
public int run() {
return super.run();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to override this function if we're just delegating to the parent anyways?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needed to change the accessor to be public so we don't have to keep adding classes to that org.sornarlint.cli package :(

}
}
30 changes: 28 additions & 2 deletions src/test/java/cc/ConfigTest.java
Original file line number Diff line number Diff line change
@@ -2,19 +2,45 @@

import org.junit.Test;

import java.nio.charset.Charset;

import static org.assertj.core.api.Assertions.assertThat;

public class ConfigTest {

@Test
public void include_paths() throws Exception {
Config config = Config.from("fixtures/multiple_paths/config.json");
assertThat(config.includePaths).containsOnly("Main.java", "src/included/");
assertThat(config.getIncludePaths()).containsOnly("Main.java", "src/included/");
}

@Test
public void default_config_path_include_base_dir() throws Exception {
Config config = new Config();
assertThat(config.includePaths).containsOnly("");
assertThat(config.getIncludePaths()).containsOnly("");
}

@Test
public void fetch_charset() throws Exception {
Config config = Config.gson().fromJson("{\"config\":{\"charset\":\"utf-16\"}}", Config.class);
assertThat(config.getCharset()).isEqualTo(Charset.forName("UTF-16"));
}

@Test
public void defaults_charset_to_utf8() throws Exception {
Config config = Config.gson().fromJson("{\"config\":{}}", Config.class);
assertThat(config.getCharset()).isEqualTo(Charset.forName("UTF-8"));
}

@Test
public void fetch_tests_patterns() throws Exception {
Config config = Config.gson().fromJson("{\"config\":{\"tests_patterns\":[\"src/test/**\",\"src/test2/**\"]}}", Config.class);
assertThat(config.getTestsPatterns()).isEqualTo("{src/test/**,src/test2/**}");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also add a test case for when tests_patterns is null (or missing) in the configuration file?

}

@Test
public void null_tests_patterns_does_not_cause_error() throws Exception {
Config config = Config.gson().fromJson("{\"config\":{}}", Config.class);
assertThat(config.getTestsPatterns()).isNull();
}
}
12 changes: 12 additions & 0 deletions src/test/java/cc/files/FinderTest.java
Original file line number Diff line number Diff line change
@@ -68,4 +68,16 @@ public void differentiate_src_and_test() throws Exception {
"fixtures/multiple_paths/src/test/java/Test.java"
);
}

@Test
public void accept_multiple_test_patterns() throws Exception {
Finder finder = new Finder(Arrays.asList("src/"), "{**/test/**,**/test2/**}", Charset.defaultCharset());

List<ClientInputFile> files = finder.collect(Paths.get("fixtures/multiple_paths"));

assertThat(files.stream().filter(f -> f.isTest()).map(ClientInputFile::getPath).collect(Collectors.toList())).containsOnly(
"fixtures/multiple_paths/src/test/java/Test.java",
"fixtures/multiple_paths/src/test2/java/Test.java"
);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package cc;
package cc.report;

import org.junit.Before;
import org.junit.Test;
import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;
import org.sonarsource.sonarlint.core.tracking.Trackable;
import support.fakes.FakeRuleDetails;
import support.OutputHelper;
import support.fakes.FakeIssue;
import support.fakes.FakeRuleDetails;
import support.fakes.FakeTrackable;

import java.util.Date;
Loading
Oops, something went wrong.