├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── appveyor.ps1 ├── appveyor.yml ├── assembly.xml ├── cix.sh ├── it ├── .gitignore ├── pom.xml ├── projects │ ├── java-no-issues │ │ └── src │ │ │ └── test │ │ │ └── Java.txt │ ├── java-sample │ │ └── src │ │ │ └── basic │ │ │ ├── Hello.java │ │ │ └── World.java │ ├── multi-language │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── Hello.java │ │ │ └── js │ │ │ └── Hello.js │ └── no-files │ │ └── placeholder.txt └── src │ └── test │ ├── java │ └── it │ │ └── sonarlint │ │ └── cli │ │ ├── ConnectedModeTest.java │ │ ├── LanguageTest.java │ │ ├── SonarlintTest.java │ │ └── tools │ │ ├── CommandExecutor.java │ │ ├── SonarlintCli.java │ │ └── SonarlintInstaller.java │ └── resources │ └── java-sonarlint.xml ├── misc └── symlink-tester.sh ├── pom.xml ├── src ├── main │ ├── assembly │ │ └── bin │ │ │ ├── sonarlint │ │ │ └── sonarlint.bat │ ├── java │ │ └── org │ │ │ └── sonarlint │ │ │ └── cli │ │ │ ├── InputFileFinder.java │ │ │ ├── Main.java │ │ │ ├── Options.java │ │ │ ├── SonarProperties.java │ │ │ ├── Stats.java │ │ │ ├── analysis │ │ │ ├── ConnectedSonarLint.java │ │ │ ├── DefaultLogOutput.java │ │ │ ├── IssueCollector.java │ │ │ ├── SonarLint.java │ │ │ ├── SonarLintFactory.java │ │ │ ├── StandaloneSonarLint.java │ │ │ └── package-info.java │ │ │ ├── config │ │ │ ├── ConfigurationReader.java │ │ │ ├── GlobalConfiguration.java │ │ │ ├── ProjectConfiguration.java │ │ │ ├── SonarQubeServer.java │ │ │ └── package-info.java │ │ │ ├── package-info.java │ │ │ ├── report │ │ │ ├── CategoryReport.java │ │ │ ├── CategoryReportComparator.java │ │ │ ├── ConsoleReport.java │ │ │ ├── HtmlReport.java │ │ │ ├── IssueCategory.java │ │ │ ├── IssueVariation.java │ │ │ ├── IssuesReport.java │ │ │ ├── ReportFactory.java │ │ │ ├── ReportSummary.java │ │ │ ├── Reporter.java │ │ │ ├── ResourceReport.java │ │ │ ├── RichIssue.java │ │ │ ├── Severity.java │ │ │ ├── package-info.java │ │ │ └── source │ │ │ │ ├── CharactersReader.java │ │ │ │ ├── DecorationDataHolder.java │ │ │ │ ├── HtmlSourceDecorator.java │ │ │ │ ├── HtmlTextDecorator.java │ │ │ │ ├── OpeningHtmlTag.java │ │ │ │ └── package-info.java │ │ │ └── util │ │ │ ├── HtmlEntities.java │ │ │ ├── Logger.java │ │ │ ├── MutableInt.java │ │ │ ├── System2.java │ │ │ ├── SystemInfo.java │ │ │ ├── Util.java │ │ │ └── package-info.java │ └── resources │ │ └── org │ │ └── sonarlint │ │ └── cli │ │ └── report │ │ ├── sonarlintreport.ftl │ │ └── sonarlintreport_files │ │ ├── DIR.png │ │ ├── FIL.png │ │ ├── PRJ.png │ │ ├── favicon.ico │ │ ├── jquery.min.js │ │ ├── rule.css │ │ ├── sep12.png │ │ ├── sonar.css │ │ ├── sonar.eot │ │ ├── sonar.svg │ │ ├── sonar.ttf │ │ ├── sonar.woff │ │ └── sonarlint.png └── test │ ├── java │ └── org │ │ └── sonarlint │ │ └── cli │ │ ├── InputFileFinderTest.java │ │ ├── MainTest.java │ │ ├── OptionsTest.java │ │ ├── StatsTest.java │ │ ├── TestUtils.java │ │ ├── analysis │ │ ├── ConnectedSonarLintTest.java │ │ ├── IssueCollectorTest.java │ │ ├── SonarLintFactoryTest.java │ │ └── StandaloneSonarLintTest.java │ │ ├── config │ │ └── ConfigurationReaderTest.java │ │ ├── report │ │ ├── CategoryReportTest.java │ │ ├── ConsoleReportTest.java │ │ ├── HtmlReportTest.java │ │ ├── IssueCategoryTest.java │ │ ├── IssueVariationTest.java │ │ ├── IssuesReportTest.java │ │ ├── ReportFactoryTest.java │ │ ├── ReportSummaryTest.java │ │ └── ResourceReportTest.java │ │ └── util │ │ ├── LoggerTest.java │ │ ├── MutableIntTest.java │ │ ├── System2Test.java │ │ ├── SystemInfoTest.java │ │ └── UtilTest.java │ └── resources │ └── org │ └── sonarlint │ └── cli │ └── config │ ├── sonarlint_global.json │ └── sonarlint_project.json ├── third-party-licenses.sh └── travis.sh /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # ---- Maven 3 | target/ 4 | dependency-reduced-pom.xml 5 | 6 | # ---- IntellijIDEA 7 | *.iws 8 | *.iml 9 | *.ipr 10 | .idea/ 11 | 12 | # ---- Eclipse 13 | .classpath 14 | .project 15 | .settings 16 | 17 | # ---- Mac OS X 18 | .DS_Store 19 | Icon? 20 | # Thumbnails 21 | ._* 22 | # Files that might appear on external disk 23 | .Spotlight-V100 24 | .Trashes 25 | 26 | # ---- Windows 27 | # Windows image file caches 28 | Thumbs.db 29 | # Folder config file 30 | Desktop.ini 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: false 3 | 4 | jdk: 5 | - oraclejdk8 6 | 7 | install: true 8 | script: ./travis.sh 9 | 10 | cache: 11 | directories: 12 | - '$HOME/.m2/repository' 13 | # for integration tests and analysis 14 | - $HOME/.sonar 15 | 16 | notifications: 17 | email: false 18 | webhooks: 19 | - secure: "LOtncSv54lCHHhLDRJ7tmVqBGWKeEvJNWXRu5oqVDVocJXy65IiaYU5OlfWmc/wn4iQC6dT3DEV4nF3wBdaIFioIp1CLO3ECo2w6LilQ1wra9Kgj47RazbcSkMrxJkz7wnn504JXok0pvX2/r9UCzJEi9D98jKQDCZ3tNw97YisiWevrhd9ExKG5tmlZea7r+AWdTpZ0EOTDOy95P+ZwPjEsArOXtkypK2DI1Bg5FDzU3xUo6CBRtICE3x5VdCmP2IdyK7Ll7ijX0YbkCrU8/BP00URmCWPNP2VmSBFpT/wXVmhjEYnHEKh21tJfMMv32U4z4ORvDlwlzZVpG4R0md3lR5Wnp5bLTqVkhkLAwgrPjNb9KIiVAV1wDMEy8xKpLHj8GXEcU/qZKi2rDxAj3Zv6ZV177QBZDRsWg5tkO8xxqSWVe9AoXhb6nHmYlFsu+dzJ/UgWZoc2s/3zrw3Kj8YwOSN0qmjDKdEE35TbGgQF/P56Vb5LooyEdK2g4RngiIyqF4OTX1AdSx5cgKbj5vDwGYLoLC0VclGpCPJDc6Vt/oDyAx+RyQOlvvgb8vaGXiIh1azE8ArDFqOb0x8vdIVCsCLnI4w+dcHOdqjVA2bOM0/eWadbRacRgP1DTGSCKfn4eUyyJPzmKicSDe4hkCm2xhhvbu5f/5AX0d0QVZs=" 20 | 21 | addons: 22 | apt: 23 | packages: 24 | # upgrade java 8 as the default version 1.8.0_31 prevents from compiling sources 25 | # https://github.com/travis-ci/travis-ci/issues/4042 26 | - oracle-java8-installer 27 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | SonarLint CLI 2 | Copyright (C) 2016-2017 SonarSource SA 3 | mailto:info AT sonarsource DOT com 4 | 5 | This product includes software developed at 6 | SonarSource (http://www.sonarsource.com/). -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SonarLint CLI [![Build Status](https://travis-ci.org/SonarSource/sonarlint-cli.svg?branch=master)](https://travis-ci.org/SonarSource/sonarlint-cli) 2 | ========================= 3 | 4 | Documentation: 5 | 6 | http://www.sonarlint.org/commandline 7 | 8 | http://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner 9 | 10 | Issue Tracker: 11 | 12 | http://jira.sonarsource.com/browse/SLCLI 13 | 14 | ### License 15 | 16 | Copyright 2016-2017 SonarSource. 17 | 18 | Licensed under the [GNU Lesser General Public License, Version 3.0](http://www.gnu.org/licenses/lgpl.txt) -------------------------------------------------------------------------------- /appveyor.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | function FetchAndUnzip 4 | { 5 | param ([string]$Url, [string]$Out) 6 | 7 | $tmp = [System.IO.Path]::GetTempFileName() 8 | [System.Reflection.Assembly]::LoadWithPartialName('System.Net.Http') | Out-Null 9 | $client = (New-Object System.Net.Http.HttpClient) 10 | try 11 | { 12 | if (-not([string]::IsNullOrEmpty($env:GITHUB_TOKEN))) 13 | { 14 | $credentials = [string]::Format([System.Globalization.CultureInfo]::InvariantCulture, "{0}:", $env:GITHUB_TOKEN); 15 | $credentials = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credentials)); 16 | $client.DefaultRequestHeaders.Authorization = (New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Basic", $credentials)); 17 | } 18 | $contents = $client.GetByteArrayAsync($url).Result; 19 | [System.IO.File]::WriteAllBytes($tmp, $contents); 20 | } 21 | finally 22 | { 23 | $client.Dispose() 24 | } 25 | 26 | if (-not(Test-Path $Out)) 27 | { 28 | mkdir $Out | Out-Null 29 | } 30 | [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null 31 | [System.IO.Compression.ZipFile]::ExtractToDirectory($tmp, $Out) 32 | } 33 | 34 | function InstallAppveyorTools 35 | { 36 | $travisUtilsVersion = "16" 37 | $localPath = "$env:USERPROFILE\.local" 38 | $travisUtilsPath = "$localPath\travis-utils-$travisUtilsVersion" 39 | if (Test-Path $travisUtilsPath) 40 | { 41 | echo "Reusing the Travis Utils version $travisUtilsVersion already downloaded under $travisUtilsPath" 42 | } 43 | else 44 | { 45 | $url = "https://github.com/SonarSource/travis-utils/archive/v$travisUtilsVersion.zip" 46 | echo "Downloading Travis Utils version $travisUtilsVersion from $url into $localPath" 47 | FetchAndUnzip $url $localPath 48 | } 49 | 50 | $mavenLocalRepository = "$env:USERPROFILE\.m2\repository" 51 | if (-not(Test-Path $mavenLocalRepository)) 52 | { 53 | mkdir $mavenLocalRepository | Out-Null 54 | } 55 | echo "Installating Travis Utils closed source Maven projects into $mavenLocalRepository" 56 | Copy-Item "$travisUtilsPath\m2repo\*" $mavenLocalRepository -Force -Recurse 57 | 58 | $env:ORCHESTRATOR_CONFIG_URL = "" 59 | $env:TRAVIS = "ORCH-332" 60 | } 61 | 62 | function Build 63 | { 64 | param ([string]$Project, [string]$Sha1) 65 | 66 | $msg = "Fetch [" + $Project + ":" + $Sha1 + "]" 67 | echo $msg 68 | 69 | $url = "https://github.com/$Project/archive/$Sha1.zip" 70 | $tmp = "c:\snapshot" 71 | if (Test-Path $tmp) 72 | { 73 | Cmd /C "rmdir /S /Q $tmp" 74 | } 75 | 76 | FetchAndUnzip $url $tmp 77 | 78 | $msg = "Build [" + $Project + ":" + $Sha1 + "]" 79 | echo $msg 80 | 81 | pushd $tmp\* 82 | try 83 | { 84 | mvn install "--batch-mode" "-DskipTests" "-Pdev" 85 | CheckLastExitCode 86 | } 87 | finally 88 | { 89 | popd 90 | } 91 | } 92 | 93 | function BuildSnapshot 94 | { 95 | param ([string]$Project) 96 | 97 | echo "Fetch and build latest green snapshot of [$Project]" 98 | 99 | $lastGreenSha1 = (new-object Net.WebClient).DownloadString("http://sonarsource-979.appspot.com/$Project/latestGreen") 100 | 101 | Build $Project $lastGreenSha1 102 | } 103 | 104 | function CheckLastExitCode 105 | { 106 | param ([int[]]$SuccessCodes = @(0)) 107 | 108 | if ($SuccessCodes -notcontains $LastExitCode) 109 | { 110 | $msg = @" 111 | EXE RETURNED EXIT CODE $LastExitCode 112 | CALLSTACK:$(Get-PSCallStack | Out-String) 113 | "@ 114 | throw $msg 115 | } 116 | } 117 | 118 | switch ($env:RUN) 119 | { 120 | "ci" 121 | { 122 | mvn verify "--batch-mode" "-B" "-e" "-V" 123 | CheckLastExitCode 124 | } 125 | 126 | "it" 127 | { 128 | InstallAppveyorTools 129 | BuildSnapshot "SonarSource/orchestrator" 130 | 131 | mvn install "--batch-mode" "-Dsource.skip=true" "-Dmaven.test.skip=true" 132 | CheckLastExitCode 133 | 134 | if ($env:SQ_VERSION -eq "DEV") 135 | { 136 | BuildSnapshot "SonarSource/sonarqube" 137 | } 138 | 139 | pushd it 140 | try 141 | { 142 | mvn install "--batch-mode" "-DsonarRunner.version=""2.5-SNAPSHOT""" "-Dsonar.runtimeVersion=""$env:SQ_VERSION""" "-Dmaven.test.redirectTestOutputToFile=false" 143 | CheckLastExitCode 144 | } 145 | finally 146 | { 147 | popd 148 | } 149 | } 150 | 151 | default 152 | { 153 | throw "Unexpected RUN mode: $env:RUN" 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | cache: 8 | - C:\Users\appveyor\.m2 -> **\pom.xml 9 | 10 | install: 11 | - set MAVEN_VERSION=3.2.5 12 | - choco install maven -version %MAVEN_VERSION% 13 | - set PATH=%PATH%;C:\bin\apache-maven-%MAVEN_VERSION%\bin 14 | - set JAVA_HOME=C:\Program Files\Java\jdk1.7.0 15 | 16 | environment: 17 | matrix: 18 | - RUN: ci 19 | 20 | build_script: 21 | - ps: ./appveyor.ps1 22 | -------------------------------------------------------------------------------- /assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | bin 6 | 7 | zip 8 | 9 | true 10 | 11 | 12 | lib 13 | true 14 | true 15 | 16 | org.freemarker:freemarker 17 | org.sonarsource.sonarlint.core:sonarlint-core 18 | 19 | 20 | 21 | 22 | 23 | src/main/assembly/bin 24 | bin 25 | 26 | sonarlint.bat 27 | 28 | dos 29 | true 30 | 31 | 32 | src/main/assembly/bin 33 | bin 34 | 35 | sonarlint 36 | 37 | unix 38 | 0755 39 | true 40 | 41 | 42 | ${project.build.directory}/plugins 43 | plugins 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /cix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | CURRENT_VERSION=`mvn help:evaluate -Dexpression="project.version" | grep -v '^\[\|Download\w\+\:'` 5 | 6 | if [[ $CURRENT_VERSION =~ "-SNAPSHOT" ]]; then 7 | echo "Running locally" 8 | else 9 | echo "Running for $CI_BUILD_NUMBER" 10 | #deploy the version built by travis 11 | mkdir -p target 12 | cd target 13 | curl --user $ARTIFACTORY_QA_READER_USERNAME:$ARTIFACTORY_QA_READER_PASSWORD -sSLO https://repox.sonarsource.com/sonarsource-public-qa/org/sonarsource/sonarlint/cli/sonarlint-cli/$CURRENT_VERSION/sonarlint-cli-$CURRENT_VERSION.zip 14 | cd .. 15 | mvn install:install-file -Dfile=target/sonarlint-cli-$CURRENT_VERSION.zip -DgroupId=org.sonarsource.sonarlint.cli \ 16 | -DartifactId=sonarlint-cli -Dversion=$CURRENT_VERSION -Dpackaging=zip 17 | fi 18 | 19 | # Run ITs 20 | cd it 21 | mvn test -Dsonarlint.version=$CURRENT_VERSION -Dsonar.runtimeVersion=LATEST_RELEASE -B -e -V 22 | -------------------------------------------------------------------------------- /it/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /it/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.sonarsource.parent 8 | parent 9 | 39 10 | 11 | 12 | 13 | com.sonarsource.it 14 | it-sonarlint-cli 15 | 1.0-SNAPSHOT 16 | SonarSource :: IT :: SonarLint CLI 17 | 2016 18 | 19 | 20 | SonarSource 21 | http://www.sonarsource.com 22 | 23 | 24 | 25 | 5.0 26 | -server 27 | 28 | 29 | 30 | 31 | 32 | junit 33 | junit 34 | 4.11 35 | 36 | 37 | org.apache.commons 38 | commons-exec 39 | 1.3 40 | 41 | 42 | org.apache.commons 43 | commons-lang3 44 | 3.4 45 | 46 | 47 | net.lingala.zip4j 48 | zip4j 49 | 1.3.2 50 | 51 | 52 | commons-io 53 | commons-io 54 | 2.4 55 | 56 | 57 | org.slf4j 58 | slf4j-api 59 | 1.7.2 60 | 61 | 62 | org.sonarsource.orchestrator 63 | sonar-orchestrator 64 | 3.14.0.887 65 | 66 | 67 | ch.qos.logback 68 | logback-classic 69 | 1.0.13 70 | 71 | 72 | com.google.code.findbugs 73 | jsr305 74 | 3.0.0 75 | 76 | 77 | org.assertj 78 | assertj-core 79 | 2.1.0 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /it/projects/java-no-issues/src/test/Java.txt: -------------------------------------------------------------------------------- 1 | No source code 2 | -------------------------------------------------------------------------------- /it/projects/java-sample/src/basic/Hello.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | 3 | public class Hello { 4 | 5 | public void hello() { 6 | int i=356; 7 | if (true) i=5658; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /it/projects/java-sample/src/basic/World.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | 3 | public final class World { 4 | 5 | public void world() { 6 | System.out.println("hello world"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /it/projects/multi-language/src/main/java/Hello.java: -------------------------------------------------------------------------------- 1 | public class Hello { 2 | } 3 | -------------------------------------------------------------------------------- /it/projects/multi-language/src/main/js/Hello.js: -------------------------------------------------------------------------------- 1 | function hello() { 2 | alert("Hello World"); 3 | } 4 | -------------------------------------------------------------------------------- /it/projects/no-files/placeholder.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/it/projects/no-files/placeholder.txt -------------------------------------------------------------------------------- /it/src/test/java/it/sonarlint/cli/ConnectedModeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarSource :: IT :: SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package it.sonarlint.cli; 21 | 22 | import com.sonar.orchestrator.Orchestrator; 23 | import com.sonar.orchestrator.locator.FileLocation; 24 | import it.sonarlint.cli.tools.SonarlintCli; 25 | import java.io.IOException; 26 | import java.nio.charset.StandardCharsets; 27 | import java.nio.file.Files; 28 | import java.nio.file.Path; 29 | import org.junit.Before; 30 | import org.junit.BeforeClass; 31 | import org.junit.ClassRule; 32 | import org.junit.Rule; 33 | import org.junit.Test; 34 | import org.junit.rules.ExpectedException; 35 | import org.junit.rules.TemporaryFolder; 36 | 37 | import static org.assertj.core.api.Assertions.assertThat; 38 | 39 | public class ConnectedModeTest { 40 | private static final String PROJECT_KEY_JAVA = "sample-java"; 41 | 42 | @ClassRule 43 | public static SonarlintCli sonarlint = new SonarlintCli(); 44 | 45 | @ClassRule 46 | public static Orchestrator ORCHESTRATOR = Orchestrator.builderEnv() 47 | .setOrchestratorProperty("javaVersion", "LATEST_RELEASE") 48 | .addPlugin("java") 49 | .restoreProfileAtStartup(FileLocation.ofClasspath("/java-sonarlint.xml")) 50 | .build(); 51 | 52 | @ClassRule 53 | public static TemporaryFolder temp = new TemporaryFolder(); 54 | 55 | @Rule 56 | public ExpectedException exception = ExpectedException.none(); 57 | 58 | @BeforeClass 59 | public static void prepare() throws Exception { 60 | ORCHESTRATOR.getServer().provisionProject(PROJECT_KEY_JAVA, "Sample Java"); 61 | ORCHESTRATOR.getServer().associateProjectToQualityProfile(PROJECT_KEY_JAVA, "java", "SonarLint IT Java"); 62 | } 63 | 64 | @Before 65 | public void setUp() throws IOException { 66 | createGlobalConfig(ORCHESTRATOR.getServer().getUrl()); 67 | sonarlint.install(); 68 | } 69 | 70 | @Test 71 | public void testSimpleJava() throws IOException { 72 | Path projectRoot = sonarlint.deployProject("java-sample"); 73 | 74 | createProjectConfig(projectRoot, PROJECT_KEY_JAVA); 75 | 76 | int code = sonarlint.run(projectRoot, "-u"); 77 | assertThat(code).isEqualTo(0); 78 | 79 | assertThat(sonarlint.getOut()).contains("No storage for server"); 80 | assertThat(sonarlint.getOut()).contains("Updating binding"); 81 | assertThat(sonarlint.getOut()).contains("Using storage for server"); 82 | 83 | assertThat(sonarlint.getOut()).contains("1 issue"); 84 | assertThat(sonarlint.getOut()).contains("1 major"); 85 | assertThat(sonarlint.getOut()).contains("3 files analyzed"); 86 | } 87 | 88 | private void createProjectConfig(Path projectRoot, String projectKey) throws IOException { 89 | Path configFile = projectRoot.resolve("sonarlint.json"); 90 | String json = "{serverId=\"local\", projectKey=" + projectKey + "}"; 91 | Files.write(configFile, json.getBytes(StandardCharsets.UTF_8)); 92 | } 93 | 94 | private void createGlobalConfig(String serverUrl) throws IOException { 95 | Path configDir = temp.getRoot().toPath().resolve(".sonarlint").resolve("conf"); 96 | Files.createDirectories(configDir); 97 | Path configFile = configDir.resolve("global.json"); 98 | String json = "{servers=[{id=\"local\",url=\"" + serverUrl + "\"}]}"; 99 | Files.write(configFile, json.getBytes(StandardCharsets.UTF_8)); 100 | sonarlint.addEnv("SONARLINT_OPTS", "-Duser.home=" + temp.getRoot().toPath().toAbsolutePath().toString()); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /it/src/test/java/it/sonarlint/cli/LanguageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarSource :: IT :: SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package it.sonarlint.cli; 21 | 22 | import it.sonarlint.cli.tools.SonarlintCli; 23 | import java.io.IOException; 24 | import java.nio.file.Path; 25 | import org.apache.commons.io.FileUtils; 26 | import org.junit.Before; 27 | import org.junit.ClassRule; 28 | import org.junit.Test; 29 | 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | 32 | public class LanguageTest { 33 | @ClassRule 34 | public static SonarlintCli sonarlint = new SonarlintCli(); 35 | 36 | @Before 37 | public void setUp() { 38 | sonarlint.install(); 39 | } 40 | 41 | @Test 42 | public void testSimpleJava() { 43 | int code = sonarlint.deployAndRunProject("java-sample"); 44 | assertThat(code).isEqualTo(0); 45 | 46 | assertThat(sonarlint.getOut()).contains("6 issues"); 47 | assertThat(sonarlint.getOut()).contains("5 major"); 48 | assertThat(sonarlint.getOut()).contains("1 minor"); 49 | assertThat(sonarlint.getOut()).contains("2 files analyzed"); 50 | } 51 | 52 | @Test 53 | public void testRunTwice() throws IOException { 54 | Path project = sonarlint.deployProject("java-sample"); 55 | int code = sonarlint.run(project); 56 | assertThat(code).isEqualTo(0); 57 | 58 | assertThat(sonarlint.getOut()).contains("6 issues"); 59 | assertThat(sonarlint.getOut()).contains("5 major"); 60 | assertThat(sonarlint.getOut()).contains("1 minor"); 61 | assertThat(sonarlint.getOut()).contains("2 files analyzed"); 62 | 63 | FileUtils.deleteDirectory(project.resolve(".sonarlint").toFile()); 64 | code = sonarlint.run(project); 65 | assertThat(code).isEqualTo(0); 66 | 67 | assertThat(sonarlint.getOut()).contains("6 issues"); 68 | assertThat(sonarlint.getOut()).contains("5 major"); 69 | assertThat(sonarlint.getOut()).contains("1 minor"); 70 | assertThat(sonarlint.getOut()).contains("2 files analyzed"); 71 | } 72 | 73 | @Test 74 | public void testMultiLanguage() { 75 | int code = sonarlint.deployAndRunProject("multi-language", "-X"); 76 | assertThat(code).isEqualTo(0); 77 | 78 | assertThat(sonarlint.getOut()).contains("src/main/js/Hello.js' is detected to be 'js'"); 79 | assertThat(sonarlint.getOut()).contains("src/main/java/Hello.java' is detected to be 'java'"); 80 | 81 | assertThat(sonarlint.getOut()).contains("3 issues"); 82 | assertThat(sonarlint.getOut()).contains("3 minor"); 83 | 84 | // 1 of each lang 85 | assertThat(sonarlint.getOut()).contains("2 files analyzed"); 86 | } 87 | 88 | @Test 89 | public void testNoIssues() { 90 | int code = sonarlint.deployAndRunProject("java-no-issues"); 91 | assertThat(code).isEqualTo(0); 92 | 93 | assertThat(sonarlint.getOut()).contains("No issues to display"); 94 | assertThat(sonarlint.getOut()).contains("1 file analyzed"); 95 | } 96 | 97 | @Test 98 | public void testNoFiles() { 99 | int code = sonarlint.deployAndRunProject("no-files", "-X", "--src", "src/**"); 100 | assertThat(code).isEqualTo(0); 101 | 102 | assertThat(sonarlint.getOut()).contains("No files to analyze"); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /it/src/test/java/it/sonarlint/cli/SonarlintTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarSource :: IT :: SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package it.sonarlint.cli; 21 | 22 | import it.sonarlint.cli.tools.SonarlintCli; 23 | import org.junit.Before; 24 | import org.junit.ClassRule; 25 | import org.junit.Test; 26 | 27 | import java.io.IOException; 28 | import java.nio.file.Files; 29 | import java.nio.file.Path; 30 | import java.nio.file.Paths; 31 | 32 | import static org.assertj.core.api.Assertions.assertThat; 33 | 34 | public class SonarlintTest { 35 | @ClassRule 36 | public static SonarlintCli sonarlint = new SonarlintCli(); 37 | 38 | @Before 39 | public void setUp() { 40 | sonarlint.install(); 41 | } 42 | 43 | @Test 44 | public void testHelp() { 45 | int code = sonarlint.run(Paths.get(""), "-h"); 46 | assertThat(sonarlint.getOut()).contains("usage: sonarlint"); 47 | assertThat(code).isEqualTo(0); 48 | } 49 | 50 | @Test 51 | public void testVersion() { 52 | int code = sonarlint.run(Paths.get(""), "-v"); 53 | String version = System.getProperty("sonarlint.version"); 54 | assertThat(sonarlint.getOut()).contains(version); 55 | assertThat(code).isEqualTo(0); 56 | } 57 | 58 | @Test 59 | public void testInvalidArg() { 60 | int code = sonarlint.run(Paths.get(""), "-q"); 61 | assertThat(sonarlint.getErr()).contains("Error parsing arguments"); 62 | assertThat(sonarlint.getOut()).contains("usage: sonarlint"); 63 | assertThat(code).isEqualTo(1); 64 | } 65 | 66 | @Test 67 | public void testPluginsInstalled() throws IOException { 68 | Path installation = sonarlint.getSonarlintInstallation(); 69 | Path plugins = installation.resolve("plugins"); 70 | assertThat(Files.isDirectory(plugins)).isTrue(); 71 | assertThat(Files.newDirectoryStream(plugins)).isNotEmpty(); 72 | } 73 | 74 | @Test 75 | public void testNoFilesToAnalyse() throws IOException { 76 | Path empty = Files.createTempDirectory("empty"); 77 | int code = sonarlint.run(empty); 78 | assertThat(code).isEqualTo(0); 79 | assertThat(sonarlint.getOut()).contains("WARN: No files to analyze"); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /it/src/test/java/it/sonarlint/cli/tools/CommandExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarSource :: IT :: SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package it.sonarlint.cli.tools; 21 | 22 | import org.apache.commons.exec.CommandLine; 23 | import org.apache.commons.exec.DefaultExecutor; 24 | import org.apache.commons.exec.ExecuteStreamHandler; 25 | import org.apache.commons.exec.ExecuteWatchdog; 26 | import org.apache.commons.exec.PumpStreamHandler; 27 | import org.apache.commons.io.output.TeeOutputStream; 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | 31 | import javax.annotation.Nullable; 32 | 33 | import java.io.ByteArrayOutputStream; 34 | import java.io.IOException; 35 | import java.io.InputStream; 36 | import java.io.OutputStream; 37 | import java.io.PipedInputStream; 38 | import java.io.PipedOutputStream; 39 | import java.nio.charset.Charset; 40 | import java.nio.file.Files; 41 | import java.nio.file.Path; 42 | import java.nio.file.attribute.PosixFilePermission; 43 | import java.util.Collections; 44 | import java.util.HashMap; 45 | import java.util.HashSet; 46 | import java.util.Map; 47 | import java.util.Set; 48 | 49 | public class CommandExecutor { 50 | private static final Logger LOG = LoggerFactory.getLogger(CommandExecutor.class); 51 | private static final int TIMEOUT = 60_000; 52 | private Path file; 53 | 54 | private ByteArrayOutputStream out; 55 | private ByteArrayOutputStream err; 56 | private OutputStream in; 57 | 58 | public CommandExecutor(Path file) { 59 | this.file = file; 60 | } 61 | 62 | public int execute(String[] args) throws IOException { 63 | return execute(args, null, Collections.emptyMap()); 64 | } 65 | 66 | public int execute(String[] args, @Nullable Path workingDir, Map addEnv) throws IOException { 67 | if (!Files.isExecutable(file)) { 68 | Set perms = new HashSet(); 69 | perms.add(PosixFilePermission.OWNER_READ); 70 | perms.add(PosixFilePermission.OWNER_EXECUTE); 71 | Files.setPosixFilePermissions(file, perms); 72 | } 73 | 74 | ExecuteWatchdog watchdog = new ExecuteWatchdog(TIMEOUT); 75 | CommandLine cmd = new CommandLine(file.toFile()); 76 | cmd.addArguments(args); 77 | DefaultExecutor exec = new DefaultExecutor(); 78 | exec.setWatchdog(watchdog); 79 | exec.setStreamHandler(createStreamHandler()); 80 | exec.setExitValues(null); 81 | if (workingDir != null) { 82 | exec.setWorkingDirectory(workingDir.toFile()); 83 | } 84 | in.close(); 85 | LOG.info("Executing: {}", cmd.toString()); 86 | Map env = new HashMap<>(System.getenv()); 87 | env.putAll(addEnv); 88 | return exec.execute(cmd, env); 89 | } 90 | 91 | public String getStdOut() { 92 | return getLogs(out); 93 | } 94 | 95 | public String getStdErr() { 96 | return getLogs(err); 97 | } 98 | 99 | private static String getLogs(ByteArrayOutputStream stream) { 100 | return new String(stream.toByteArray(), Charset.defaultCharset()); 101 | } 102 | 103 | private ExecuteStreamHandler createStreamHandler() throws IOException { 104 | out = new ByteArrayOutputStream(); 105 | err = new ByteArrayOutputStream(); 106 | PipedOutputStream outPiped = new PipedOutputStream(); 107 | InputStream inPiped = new PipedInputStream(outPiped); 108 | in = outPiped; 109 | 110 | TeeOutputStream teeOut = new TeeOutputStream(out, System.out); 111 | TeeOutputStream teeErr = new TeeOutputStream(err, System.err); 112 | 113 | return new PumpStreamHandler(teeOut, teeErr, inPiped); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /it/src/test/java/it/sonarlint/cli/tools/SonarlintCli.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarSource :: IT :: SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package it.sonarlint.cli.tools; 21 | 22 | import java.io.IOException; 23 | import java.nio.file.Files; 24 | import java.nio.file.Path; 25 | import java.nio.file.Paths; 26 | import java.util.HashMap; 27 | import java.util.Map; 28 | 29 | import org.apache.commons.io.FileUtils; 30 | import org.junit.rules.ExternalResource; 31 | import org.slf4j.Logger; 32 | import org.slf4j.LoggerFactory; 33 | 34 | public class SonarlintCli extends ExternalResource { 35 | private static final Logger LOG = LoggerFactory.getLogger(SonarlintCli.class); 36 | private Path script; 37 | private Path installPath; 38 | private Path project; 39 | private CommandExecutor exec; 40 | private Map env = new HashMap<>(); 41 | 42 | public void install() { 43 | String version = System.getProperty("sonarlint.version"); 44 | if (version == null) { 45 | throw new IllegalStateException("No sonarlint-cli version specified. Use '-Dsonarlint.version'."); 46 | } 47 | install(version); 48 | } 49 | 50 | public void install(String version) { 51 | SonarlintInstaller installer = new SonarlintInstaller(); 52 | this.script = installer.install(installPath, version); 53 | } 54 | 55 | public void addEnv(String key, String value) { 56 | env.put(key, value); 57 | } 58 | 59 | public int run(Path workingDir, String... args) { 60 | LOG.info("Running SonarLint CLI in '{}'", workingDir.toAbsolutePath()); 61 | try { 62 | exec = new CommandExecutor(script); 63 | return exec.execute(args, workingDir.toAbsolutePath(), env); 64 | } catch (IOException e) { 65 | throw new IllegalStateException(e); 66 | } 67 | } 68 | 69 | public int deployAndRunProject(String location, String... args) { 70 | LOG.info("Running SonarLint CLI on project '{}'", location); 71 | try { 72 | Path project = deployProject(location); 73 | exec = new CommandExecutor(script); 74 | return exec.execute(args, project, env); 75 | } catch (IOException e) { 76 | throw new IllegalStateException(e); 77 | } 78 | } 79 | 80 | public Path deployProject(String location) throws IOException { 81 | Path originalLoc = Paths.get("projects").resolve(location); 82 | String projectName = originalLoc.getFileName().toString(); 83 | 84 | if (!Files.isDirectory(originalLoc)) { 85 | throw new IllegalArgumentException("Couldn't find project directory: " + originalLoc.toAbsolutePath().toString()); 86 | } 87 | 88 | cleanProject(); 89 | project = Files.createTempDirectory(projectName); 90 | FileUtils.copyDirectory(originalLoc.toFile(), project.toFile()); 91 | return project; 92 | } 93 | 94 | private void cleanProject() { 95 | if (project != null) { 96 | FileUtils.deleteQuietly(project.toFile()); 97 | project = null; 98 | } 99 | } 100 | 101 | protected void before() throws Throwable { 102 | installPath = Files.createTempDirectory("sonarlint-cli"); 103 | } 104 | 105 | protected void after() { 106 | cleanProject(); 107 | if (installPath != null) { 108 | FileUtils.deleteQuietly(installPath.toFile()); 109 | installPath = null; 110 | } 111 | } 112 | 113 | public String getOut() { 114 | return exec.getStdOut(); 115 | } 116 | 117 | public String[] getOutLines() { 118 | return getOut().split(System.lineSeparator()); 119 | } 120 | 121 | public Path getProject() { 122 | return project; 123 | } 124 | 125 | public Path getSonarlintInstallation() { 126 | return script.getParent().getParent(); 127 | } 128 | 129 | public String getErr() { 130 | return exec.getStdErr(); 131 | } 132 | 133 | public String[] getErrLines() { 134 | return getErr().split(System.lineSeparator()); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /it/src/test/java/it/sonarlint/cli/tools/SonarlintInstaller.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarSource :: IT :: SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package it.sonarlint.cli.tools; 21 | 22 | import net.lingala.zip4j.core.ZipFile; 23 | import org.apache.commons.lang3.SystemUtils; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | import java.nio.file.Files; 28 | import java.nio.file.Path; 29 | import java.nio.file.Paths; 30 | 31 | /** 32 | * Attempts to install a specific version of SonarLint CLI from the local maven repository. 33 | * The location of the local maven repository can be passed with the environmental variable 'MAVEN_LOCAL_REPOSITORY'. 34 | */ 35 | public class SonarlintInstaller { 36 | private static final String GROUP_ID = "org.sonarsource.sonarlint.cli"; 37 | private static final String ARTIFACT_ID = "sonarlint-cli"; 38 | private static final Logger LOG = LoggerFactory.getLogger(SonarlintInstaller.class); 39 | 40 | public Path install(Path installPath, String version) { 41 | if (!isInstalled(installPath, version)) { 42 | Path zipFile = locateZipInLocalMaven(version); 43 | installZip(zipFile, installPath); 44 | } 45 | 46 | return locateScript(version, installPath); 47 | } 48 | 49 | private static Path locateScript(String version, Path installPath) { 50 | String directoryName = "sonarlint-cli-" + version; 51 | String fileName = SystemUtils.IS_OS_WINDOWS ? "sonarlint.bat" : "sonarlint"; 52 | 53 | Path script = installPath.resolve(directoryName).resolve("bin").resolve(fileName); 54 | 55 | if (!Files.exists(script)) { 56 | throw new IllegalStateException("File does not exist: " + script); 57 | } 58 | return script; 59 | } 60 | 61 | private boolean isInstalled(Path installPath, String version) { 62 | String directoryName = "sonarlint-cli-" + version; 63 | 64 | Path sonarlint = installPath.resolve(directoryName); 65 | 66 | if (Files.isDirectory(sonarlint)) { 67 | LOG.debug("SonarLint CLI {} already exists in {}", version, installPath); 68 | return true; 69 | } 70 | return false; 71 | } 72 | 73 | private void installZip(Path zipFilePath, Path toDir) { 74 | try { 75 | ZipFile zipFile = new ZipFile(zipFilePath.toFile()); 76 | zipFile.extractAll(toDir.toString()); 77 | } catch (Exception e) { 78 | throw new IllegalStateException("Fail to unzip sonarlint cli to" + toDir, e); 79 | } 80 | } 81 | 82 | private Path locateZipInLocalMaven(String version) { 83 | String fileName = "sonarlint-cli-" + version + ".zip"; 84 | 85 | LOG.info("Searching for SonarLint CLI {} in maven repositories", version); 86 | 87 | Path mvnRepo = getMavenLocalRepository(); 88 | Path file = getMavenFilePath(mvnRepo, GROUP_ID, ARTIFACT_ID, version, fileName); 89 | 90 | if (!Files.exists(file)) { 91 | throw new IllegalArgumentException("Couldn't find in local repo: sonarlint cli " + file.toString()); 92 | } 93 | return file; 94 | } 95 | 96 | private static Path getMavenFilePath(Path mvnRepo, String groupId, String artifactId, String version, String fileName) { 97 | Path p = mvnRepo; 98 | String[] split = groupId.split("\\."); 99 | 100 | for (String s : split) { 101 | p = p.resolve(s); 102 | } 103 | 104 | p = p.resolve(artifactId); 105 | p = p.resolve(version); 106 | return p.resolve(fileName); 107 | } 108 | 109 | private Path getMavenLocalRepository() { 110 | if (System.getenv("MAVEN_LOCAL_REPOSITORY") != null) { 111 | Path repo = Paths.get(System.getenv("MAVEN_LOCAL_REPOSITORY")); 112 | if (!Files.isDirectory(repo)) { 113 | throw new IllegalArgumentException("Maven local repository is not valid: " + System.getenv("MAVEN_LOCAL_REPOSITORY")); 114 | } 115 | return repo; 116 | } 117 | 118 | String home = System.getProperty("user.home"); 119 | Path repo = Paths.get(home).resolve(".m2").resolve("repository"); 120 | 121 | if (!Files.isDirectory(repo)) { 122 | throw new IllegalArgumentException("Couldn't find maven repository. Please define MAVEN_LOCAL_REPOSITORY in the environment."); 123 | } 124 | 125 | LOG.info("Using maven repository: {}", repo); 126 | return repo; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /it/src/test/resources/java-sonarlint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | SonarLint IT Java 4 | java 5 | 6 | 7 | 8 | squid 9 | S106 10 | MAJOR 11 | 12 | 13 | 14 | squid 15 | S2325 16 | MAJOR 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /misc/symlink-tester.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | usage() { 4 | echo usage: $0 path/to/sonarlint 5 | exit 1 6 | } 7 | 8 | test -f "$1" && test -x "$1" || usage 9 | 10 | sonarlint=$1 11 | 12 | if type mktemp &>/dev/null; then 13 | tempdir=$(mktemp -d) 14 | else 15 | tempdir=/tmp/"$(basename "$0")-$$" 16 | mkdir -p "$tempdir" 17 | fi 18 | 19 | cleanup() { 20 | rm -fr "$tempdir" 21 | } 22 | 23 | trap 'cleanup; exit 1' 1 2 3 15 24 | 25 | abspath() { 26 | (cd "$(dirname "$1")"; echo $PWD/"$(basename "$1")") 27 | } 28 | 29 | verify() { 30 | printf '%s -> ' "$1" 31 | shift 32 | "$@" &>/dev/null && echo ok || echo failed 33 | } 34 | 35 | relpath_to_root() { 36 | ( 37 | cd "$1" 38 | relpath=. 39 | while test "$PWD" != /; do 40 | cd .. 41 | relpath=$relpath/.. 42 | done 43 | echo $relpath 44 | ) 45 | } 46 | 47 | ln -s "$(abspath "$sonarlint")" "$tempdir"/sonarlint 48 | verify 'launch from abs symlink to abs path' "$tempdir"/sonarlint -h 49 | 50 | ln -s $(relpath_to_root "$tempdir")/"$(abspath "$sonarlint")" "$tempdir"/sonarlint-rel 51 | verify 'symlink to rel path is valid' test -f "$tempdir"/sonarlint-rel 52 | verify 'launch from abs symlink to rel path' "$tempdir"/sonarlint-rel -h 53 | 54 | mkdir "$tempdir/x" 55 | ln -s ../sonarlint "$tempdir"/x/sonarlint 56 | verify 'symlink to rel symlink is valid' test -f "$tempdir"/x/sonarlint 57 | verify 'launch from abs symlink that is rel symlink to abs path' "$tempdir"/x/sonarlint -h 58 | 59 | cleanup 60 | -------------------------------------------------------------------------------- /src/main/assembly/bin/sonarlint: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # SonarLint Startup Script for Unix 4 | # 5 | # Optional ENV vars: 6 | # SONARLINT_OPTS - parameters passed to the Java VM when running SonarLint 7 | 8 | real_path() { 9 | target=$1 10 | 11 | ( 12 | while true; do 13 | cd "$(dirname "$target")" 14 | target=$(basename "$target") 15 | link=$(readlink "$target") 16 | test "$link" || break 17 | target=$link 18 | done 19 | 20 | echo "$(pwd -P)/$target" 21 | ) 22 | } 23 | 24 | script_path="$0" 25 | 26 | if [ -h "$script_path" ]; then 27 | # resolve symlinks 28 | script_path=$(real_path "$script_path") 29 | fi 30 | 31 | sonarlint_home=$(dirname "$script_path")/.. 32 | 33 | # make it fully qualified 34 | sonarlint_home=$(cd "$sonarlint_home" && pwd -P) 35 | 36 | # check that the sonarlint_home has been correctly set 37 | if [ ! -f "$sonarlint_home/lib/sonarlint-cli-${project.version}.jar" ] ; then 38 | echo "fatal: detected installation directory is invalid: $sonarlint_home" 39 | echo 'fatal: lib/sonarlint-cli-${project.version}.jar should exist relative from the installation directory' 40 | exit 1 41 | fi 42 | 43 | if [ -n "$JAVA_HOME" ] 44 | then 45 | java_cmd="$JAVA_HOME/bin/java" 46 | else 47 | java_cmd="$(which java)" 48 | fi 49 | 50 | jar_file="$sonarlint_home"/lib/sonarlint-cli-${project.version}.jar 51 | project_home=$PWD 52 | 53 | #echo "Info: Using sonarlint-cli in $sonarlint_home" 54 | #echo "Info: Using java at $java_cmd" 55 | #echo "Info: Using classpath $jar_file" 56 | #echo "Info: Using project $project_home" 57 | 58 | exec "$java_cmd" \ 59 | -Djava.awt.headless=true \ 60 | $SONARLINT_OPTS \ 61 | -classpath "$jar_file" \ 62 | -Dsonarlint.home="$sonarlint_home" \ 63 | -Dproject.home="$project_home" \ 64 | -Dorg.freemarker.loggerLibrary=none \ 65 | org.sonarlint.cli.Main "$@" 66 | 67 | -------------------------------------------------------------------------------- /src/main/assembly/bin/sonarlint.bat: -------------------------------------------------------------------------------- 1 | @REM SonarLint Startup Script for Windows 2 | @REM 3 | @REM Required ENV vars: 4 | @REM JAVA_HOME - location of a JDK home dir 5 | @REM 6 | @REM Optional ENV vars: 7 | @REM SONARLINT_HOME - location of SonarLint's installed home dir 8 | @REM SONARLINT_OPTS - parameters passed to the Java VM when running SonarLint 9 | 10 | @echo off 11 | 12 | set ERROR_CODE=0 13 | 14 | @REM set local scope for the variables with windows NT shell 15 | @setlocal 16 | 17 | @REM ==== START VALIDATION ==== 18 | @REM *** JAVA EXEC VALIDATION *** 19 | if not "%JAVA_HOME%" == "" goto foundJavaHome 20 | 21 | for %%i in (java.exe) do set JAVA_EXEC=%%~$PATH:i 22 | 23 | if not "%JAVA_EXEC%" == "" ( 24 | set JAVA_EXEC="%JAVA_EXEC%" 25 | goto OkJava 26 | ) 27 | 28 | if not "%JAVA_EXEC%" == "" goto OkJava 29 | 30 | echo. 31 | echo ERROR: JAVA_HOME not found in your environment, and no Java 32 | echo executable present in the PATH. 33 | echo Please set the JAVA_HOME variable in your environment to match the 34 | echo location of your Java installation, or add "java.exe" to the PATH 35 | echo. 36 | goto error 37 | 38 | :foundJavaHome 39 | if EXIST "%JAVA_HOME%\bin\java.exe" goto foundJavaExeFromJavaHome 40 | 41 | echo. 42 | echo ERROR: JAVA_HOME exists but does not point to a valid Java home 43 | echo folder. No "\bin\java.exe" file can be found there. 44 | echo. 45 | goto error 46 | 47 | :foundJavaExeFromJavaHome 48 | set JAVA_EXEC="%JAVA_HOME%\bin\java.exe" 49 | 50 | @REM *** SONARLINT HOME VALIDATION *** 51 | :OkJava 52 | if NOT "%SONARLINT_HOME%"=="" goto cleanSonarLintHome 53 | set SONARLINT_HOME=%~dp0.. 54 | goto run 55 | 56 | :cleanSonarLintHome 57 | @REM If the property has a trailing backslash, remove it 58 | if "%SONARLINT_HOME:~-1%"=="\" set SONARLINT_HOME=%SONARLINT_HOME:~0,-1% 59 | 60 | @REM Check if the provided SONARLINT_HOME is a valid install dir 61 | IF EXIST "%SONARLINT_HOME%\lib\sonarlint-cli-${project.version}.jar" goto run 62 | 63 | echo. 64 | echo ERROR: SONARLINT_HOME exists but does not point to a valid install 65 | echo directory: %SONARLINT_HOME% 66 | echo. 67 | goto error 68 | 69 | 70 | 71 | @REM ==== START RUN ==== 72 | :run 73 | echo %SONARLINT_HOME% 74 | 75 | set PROJECT_HOME=%CD% 76 | if not "%SONARLINT_OPTS%"=="" set SONARLINT_OPTS="%SONARLINT_OPTS%" 77 | 78 | %JAVA_EXEC% -Djava.awt.headless=true %SONARLINT_OPTS% -cp "%SONARLINT_HOME%\lib\sonarlint-cli-${project.version}.jar" "-Dsonarlint.home=%SONARLINT_HOME%" "-Dproject.home=%PROJECT_HOME%" -Dorg.freemarker.loggerLibrary=none org.sonarlint.cli.Main %* 79 | if ERRORLEVEL 1 goto error 80 | goto end 81 | 82 | :error 83 | set ERROR_CODE=1 84 | 85 | @REM ==== END EXECUTION ==== 86 | 87 | :end 88 | @REM set local scope for the variables with windows NT shell 89 | @endlocal & set ERROR_CODE=%ERROR_CODE% 90 | 91 | @REM see http://code-bear.com/bearlog/2007/06/01/getting-the-exit-code-from-a-batch-file-that-is-run-from-a-python-program/ 92 | goto exit 93 | 94 | :returncode 95 | exit /B %1 96 | 97 | :exit 98 | call :returncode %ERROR_CODE% 99 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/InputFileFinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.nio.charset.Charset; 25 | import java.nio.file.FileSystem; 26 | import java.nio.file.FileSystems; 27 | import java.nio.file.FileVisitResult; 28 | import java.nio.file.Files; 29 | import java.nio.file.Path; 30 | import java.nio.file.PathMatcher; 31 | import java.nio.file.SimpleFileVisitor; 32 | import java.nio.file.attribute.BasicFileAttributes; 33 | import java.util.ArrayList; 34 | import java.util.List; 35 | import javax.annotation.Nullable; 36 | import org.sonarlint.cli.util.Logger; 37 | import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; 38 | 39 | public class InputFileFinder { 40 | private static final String GLOB_PREFIX = "glob:"; 41 | private static final Logger LOGGER = Logger.get(); 42 | private final PathMatcher srcMatcher; 43 | private final PathMatcher testsMatcher; 44 | private final PathMatcher excludeMatcher; 45 | private final Charset charset; 46 | 47 | private static PathMatcher acceptAll = p -> true; 48 | private static PathMatcher refuseAll = p -> false; 49 | 50 | public InputFileFinder(@Nullable String srcGlobPattern, @Nullable String testsGlobPattern, @Nullable String excludeGlobPattern, Charset charset) { 51 | this.charset = charset; 52 | FileSystem fs = FileSystems.getDefault(); 53 | try { 54 | if (srcGlobPattern != null) { 55 | srcMatcher = fs.getPathMatcher(GLOB_PREFIX + srcGlobPattern); 56 | } else { 57 | srcMatcher = acceptAll; 58 | } 59 | } catch (Exception e) { 60 | LOGGER.error("Error creating matcher for sources with pattern: " + srcGlobPattern); 61 | throw e; 62 | } 63 | 64 | try { 65 | if (testsGlobPattern != null) { 66 | testsMatcher = fs.getPathMatcher(GLOB_PREFIX + testsGlobPattern); 67 | } else { 68 | testsMatcher = refuseAll; 69 | } 70 | } catch (Exception e) { 71 | LOGGER.error("Error creating matcher for tests with pattern: " + testsGlobPattern); 72 | throw e; 73 | } 74 | 75 | try { 76 | if (excludeGlobPattern != null) { 77 | excludeMatcher = fs.getPathMatcher(GLOB_PREFIX + excludeGlobPattern); 78 | } else { 79 | excludeMatcher = refuseAll; 80 | } 81 | } catch (Exception e) { 82 | LOGGER.error("Error creating matcher for exclusions with pattern: " + excludeGlobPattern); 83 | throw e; 84 | } 85 | } 86 | 87 | public List collect(Path dir) throws IOException { 88 | final List files = new ArrayList<>(); 89 | Files.walkFileTree(dir, new FileCollector(dir, files)); 90 | return files; 91 | } 92 | 93 | private class FileCollector extends SimpleFileVisitor { 94 | private final List files; 95 | private final Path baseDir; 96 | 97 | private FileCollector(Path baseDir, List files) { 98 | this.baseDir = baseDir; 99 | this.files = files; 100 | } 101 | 102 | @Override 103 | public FileVisitResult visitFile(final Path file, BasicFileAttributes attrs) throws IOException { 104 | Path absoluteFilePath = file; 105 | Path relativeFilePath = baseDir.relativize(absoluteFilePath); 106 | boolean isSrc = srcMatcher.matches(absoluteFilePath) || srcMatcher.matches(relativeFilePath); 107 | boolean isExcluded = excludeMatcher.matches(absoluteFilePath) || excludeMatcher.matches(relativeFilePath); 108 | if (isSrc && !isExcluded) { 109 | boolean isTest = testsMatcher.matches(absoluteFilePath) || testsMatcher.matches(relativeFilePath); 110 | files.add(new DefaultClientInputFile(absoluteFilePath, isTest, charset)); 111 | } 112 | 113 | return super.visitFile(absoluteFilePath, attrs); 114 | } 115 | 116 | @Override 117 | public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { 118 | if (Files.isHidden(dir)) { 119 | LOGGER.debug("Ignoring hidden directory: " + dir.toString()); 120 | return FileVisitResult.SKIP_SUBTREE; 121 | } 122 | 123 | return super.preVisitDirectory(dir, attrs); 124 | } 125 | } 126 | 127 | public static class DefaultClientInputFile implements ClientInputFile { 128 | private final Path path; 129 | private final boolean test; 130 | private final Charset charset; 131 | 132 | public DefaultClientInputFile(Path path, boolean test, Charset charset) { 133 | this.path = path; 134 | this.test = test; 135 | this.charset = charset; 136 | } 137 | 138 | @Override 139 | public boolean isTest() { 140 | return test; 141 | } 142 | 143 | @Override 144 | public String getPath() { 145 | return path.toString(); 146 | } 147 | 148 | @Override 149 | public Charset getCharset() { 150 | return charset; 151 | } 152 | 153 | @Override 154 | public G getClientObject() { 155 | return null; 156 | } 157 | 158 | @Override 159 | public InputStream inputStream() throws IOException { 160 | return Files.newInputStream(path); 161 | } 162 | 163 | @Override 164 | public String contents() throws IOException { 165 | return new String(Files.readAllBytes(path), charset); 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/Options.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli; 21 | 22 | import java.text.ParseException; 23 | import java.util.Properties; 24 | import org.sonarlint.cli.util.Logger; 25 | 26 | public class Options { 27 | private static final Logger LOGGER = Logger.get(); 28 | private Properties props = new Properties(); 29 | private boolean verbose = false; 30 | private boolean help = false; 31 | private boolean version = false; 32 | private boolean showStack = false; 33 | private boolean interactive = false; 34 | private String htmlReport = null; 35 | private String src = null; 36 | private String tests = ""; 37 | private String exclusions = ""; 38 | private String charset = null; 39 | private boolean update = false; 40 | private String task; 41 | 42 | public static Options parse(String[] args) throws ParseException { 43 | Options options = new Options(); 44 | 45 | for (int i = 0; i < args.length; i++) { 46 | String arg = args[i]; 47 | if (i == 0 && !arg.startsWith("-")) { 48 | options.task = arg; 49 | 50 | } else if ("-h".equals(arg) || "--help".equals(arg)) { 51 | options.help = true; 52 | 53 | } else if ("-v".equals(arg) || "--version".equals(arg)) { 54 | options.version = true; 55 | 56 | } else if ("-i".equals(arg) || "--interactive".equals(arg)) { 57 | options.interactive = true; 58 | 59 | } else if ("-e".equals(arg) || "--errors".equals(arg)) { 60 | options.showStack = true; 61 | 62 | } else if ("-X".equals(arg) || "--debug".equals(arg)) { 63 | options.verbose = true; 64 | 65 | } else if ("-u".equals(arg) || "--update".equals(arg)) { 66 | options.update = true; 67 | 68 | } else if (arg.startsWith("-D") && !"-D".equals(arg)) { 69 | arg = arg.substring(2); 70 | appendPropertyTo(arg, options.props); 71 | 72 | } else { 73 | i++; 74 | 75 | if ("--html-report".equals(arg)) { 76 | checkAdditionalArg(i, args.length, arg); 77 | options.htmlReport = args[i]; 78 | 79 | } else if ("--charset".equals(arg)) { 80 | checkAdditionalArg(i, args.length, arg); 81 | options.charset = args[i]; 82 | 83 | } else if ("--src".equals(arg)) { 84 | checkAdditionalArg(i, args.length, arg); 85 | options.src = args[i]; 86 | 87 | } else if ("--tests".equals(arg)) { 88 | checkAdditionalArg(i, args.length, arg); 89 | options.tests = args[i]; 90 | 91 | } else if ("--exclude".equals(arg)) { 92 | checkAdditionalArg(i, args.length, arg); 93 | options.exclusions = args[i]; 94 | 95 | } else if ("-D".equals(arg) || "--define".equals(arg)) { 96 | checkAdditionalArg(i, args.length, arg); 97 | appendPropertyTo(args[i], options.props); 98 | 99 | } else { 100 | throw new ParseException("Unrecognized option: " + arg, i); 101 | } 102 | } 103 | } 104 | 105 | return options; 106 | } 107 | 108 | private static void checkAdditionalArg(int i, int argsLength, String arg) throws ParseException { 109 | if (i >= argsLength) { 110 | throw new ParseException("Missing argument for option " + arg, i); 111 | } 112 | } 113 | 114 | public boolean isVerbose() { 115 | return verbose; 116 | } 117 | 118 | public boolean isInteractive() { 119 | return interactive; 120 | } 121 | 122 | public boolean isHelp() { 123 | return help; 124 | } 125 | 126 | public String charset() { 127 | return charset; 128 | } 129 | 130 | public String htmlReport() { 131 | return htmlReport; 132 | } 133 | 134 | public String src() { 135 | return src; 136 | } 137 | 138 | public String tests() { 139 | return tests; 140 | } 141 | 142 | public String exclusions() { 143 | return exclusions; 144 | } 145 | 146 | public boolean isUpdate() { 147 | return update; 148 | } 149 | 150 | public boolean isVersion() { 151 | return version; 152 | } 153 | 154 | public boolean showStack() { 155 | return showStack; 156 | } 157 | 158 | public Properties properties() { 159 | return props; 160 | } 161 | 162 | public String task() { 163 | return task; 164 | } 165 | 166 | public static void printUsage() { 167 | LOGGER.info(""); 168 | LOGGER.info("usage: sonarlint [options]"); 169 | LOGGER.info(""); 170 | LOGGER.info("Options:"); 171 | LOGGER.info(" -u,--update Update binding with SonarQube server before analysis"); 172 | LOGGER.info(" -D,--define Define property"); 173 | LOGGER.info(" -e,--errors Produce execution error messages"); 174 | LOGGER.info(" -h,--help Display help information"); 175 | LOGGER.info(" -v,--version Display version information"); 176 | LOGGER.info(" -X,--debug Produce execution debug output"); 177 | LOGGER.info(" -i,--interactive Run interactively"); 178 | LOGGER.info(" --html-report HTML report output path (relative or absolute)"); 179 | LOGGER.info(" --src GLOB pattern to identify source files"); 180 | LOGGER.info(" --tests GLOB pattern to identify test files"); 181 | LOGGER.info(" --exclude GLOB pattern to exclude files"); 182 | LOGGER.info(" --charset Character encoding of the source files"); 183 | } 184 | 185 | private static void appendPropertyTo(String arg, Properties props) { 186 | final String key; 187 | final String value; 188 | 189 | int j = arg.indexOf('='); 190 | if (j == -1) { 191 | key = arg; 192 | value = "true"; 193 | } else { 194 | key = arg.substring(0, j); 195 | value = arg.substring(j + 1); 196 | } 197 | props.setProperty(key, value); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/SonarProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli; 21 | 22 | public class SonarProperties { 23 | public static final String PROPERTY_PROJECT_CONFIG_FILE = "sonar.projectConfigFile"; 24 | 25 | public static final String SONARLINT_HOME = "sonarlint.home"; 26 | public static final String PROJECT_HOME = "project.home"; 27 | 28 | public static final String DEFAULT_SOURCES = "."; 29 | public static final String DEFAULT_TESTS = "."; 30 | public static final String DEFAULT_TESTS_INCLUSIONS = "**/*Test.*,**/test/**/*"; 31 | 32 | private SonarProperties() { 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/Stats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli; 21 | 22 | import org.sonarlint.cli.util.Logger; 23 | 24 | class Stats { 25 | private static final Logger LOGGER = Logger.get(); 26 | private long startTime; 27 | 28 | Stats start() { 29 | startTime = System.currentTimeMillis(); 30 | return this; 31 | } 32 | 33 | Stats stop() { 34 | long stopTime = System.currentTimeMillis() - startTime; 35 | LOGGER.info("Total time: " + formatTime(stopTime)); 36 | 37 | System.gc(); 38 | Runtime r = Runtime.getRuntime(); 39 | long mb = 1024L * 1024; 40 | LOGGER.info("Final Memory: " + (r.totalMemory() - r.freeMemory()) / mb + "M/" + r.totalMemory() / mb + "M"); 41 | 42 | return this; 43 | } 44 | 45 | static String formatTime(long time) { 46 | long h = time / (60 * 60 * 1000); 47 | long m = (time - h * 60 * 60 * 1000) / (60 * 1000); 48 | long s = (time - h * 60 * 60 * 1000 - m * 60 * 1000) / 1000; 49 | long ms = time % 1000; 50 | final String format; 51 | if (h > 0) { 52 | format = "%1$d:%2$02d:%3$02d.%4$03ds"; 53 | } else if (m > 0) { 54 | format = "%2$d:%3$02d.%4$03ds"; 55 | } else { 56 | format = "%3$d.%4$03ds"; 57 | } 58 | return String.format(format, h, m, s, ms); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/analysis/DefaultLogOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.analysis; 21 | 22 | import org.sonarlint.cli.util.Logger; 23 | import org.sonarsource.sonarlint.core.client.api.common.LogOutput; 24 | 25 | class DefaultLogOutput implements LogOutput { 26 | 27 | private final Logger logger; 28 | private final boolean verbose; 29 | 30 | public DefaultLogOutput(Logger logger, boolean verbose) { 31 | this.logger = logger; 32 | this.verbose = verbose; 33 | } 34 | 35 | @Override 36 | public void log(String formattedMessage, Level level) { 37 | switch (level) { 38 | case TRACE: 39 | case DEBUG: 40 | if (verbose) { 41 | logger.debug(formattedMessage); 42 | } 43 | break; 44 | case ERROR: 45 | logger.error(formattedMessage); 46 | break; 47 | case INFO: 48 | case WARN: 49 | default: 50 | logger.info(formattedMessage); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/analysis/IssueCollector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.analysis; 21 | 22 | import java.util.LinkedList; 23 | import java.util.List; 24 | 25 | import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; 26 | import org.sonarsource.sonarlint.core.client.api.common.analysis.IssueListener; 27 | 28 | public class IssueCollector implements IssueListener { 29 | private List issues = new LinkedList<>(); 30 | 31 | @Override 32 | public void handle(Issue issue) { 33 | issues.add(issue); 34 | } 35 | 36 | public List get() { 37 | return issues; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/analysis/SonarLint.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.analysis; 21 | 22 | import java.io.IOException; 23 | import java.nio.file.Path; 24 | import java.util.Collection; 25 | import java.util.Date; 26 | import java.util.List; 27 | import java.util.Map; 28 | import org.sonarlint.cli.InputFileFinder; 29 | import org.sonarlint.cli.report.ReportFactory; 30 | import org.sonarlint.cli.report.Reporter; 31 | import org.sonarlint.cli.util.Logger; 32 | import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; 33 | import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; 34 | import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; 35 | import org.sonarsource.sonarlint.core.tracking.Trackable; 36 | 37 | public abstract class SonarLint { 38 | private static final Logger LOGGER = Logger.get(); 39 | 40 | public void start(boolean forceUpdate) { 41 | // do nothing by default 42 | } 43 | 44 | public void runAnalysis(Map properties, ReportFactory reportFactory, InputFileFinder finder, Path projectHome) { 45 | List inputFiles; 46 | try { 47 | inputFiles = finder.collect(projectHome); 48 | } catch (IOException e) { 49 | throw new IllegalStateException("Error preparing list of files to analyze", e); 50 | } 51 | 52 | if (inputFiles.isEmpty()) { 53 | LOGGER.warn("No files to analyze"); 54 | return; 55 | } else { 56 | LOGGER.debug(String.format("Submitting %d files for analysis", inputFiles.size())); 57 | } 58 | 59 | doAnalysis(properties, reportFactory, inputFiles, projectHome); 60 | } 61 | 62 | protected abstract RuleDetails getRuleDetails(String ruleKey); 63 | 64 | protected abstract void doAnalysis(Map properties, ReportFactory reportFactory, List inputFiles, Path baseDirPath); 65 | 66 | public abstract void stop(); 67 | 68 | protected void generateReports(Collection trackables, AnalysisResults result, ReportFactory reportFactory, String projectName, Path baseDir, Date date) { 69 | List reporters = reportFactory.createReporters(baseDir); 70 | 71 | for (Reporter r : reporters) { 72 | r.execute(projectName, date, trackables, result, this::getRuleDetails); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/analysis/StandaloneSonarLint.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.analysis; 21 | 22 | import java.nio.file.Path; 23 | import java.util.Collection; 24 | import java.util.Date; 25 | import java.util.List; 26 | import java.util.Map; 27 | import java.util.stream.Collectors; 28 | import org.sonarlint.cli.report.ReportFactory; 29 | import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; 30 | import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; 31 | import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; 32 | import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneAnalysisConfiguration; 33 | import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneSonarLintEngine; 34 | import org.sonarsource.sonarlint.core.tracking.IssueTrackable; 35 | import org.sonarsource.sonarlint.core.tracking.Trackable; 36 | 37 | public class StandaloneSonarLint extends SonarLint { 38 | private final StandaloneSonarLintEngine engine; 39 | 40 | public StandaloneSonarLint(StandaloneSonarLintEngine engine) { 41 | this.engine = engine; 42 | } 43 | 44 | @Override 45 | protected void doAnalysis(Map properties, ReportFactory reportFactory, List inputFiles, Path baseDirPath) { 46 | Date start = new Date(); 47 | 48 | IssueCollector collector = new IssueCollector(); 49 | StandaloneAnalysisConfiguration config = new StandaloneAnalysisConfiguration(baseDirPath, baseDirPath.resolve(".sonarlint"), 50 | inputFiles, properties); 51 | AnalysisResults result = engine.analyze(config, collector); 52 | Collection trackables = collector.get().stream().map(IssueTrackable::new).collect(Collectors.toList()); 53 | generateReports(trackables, result, reportFactory, baseDirPath.getFileName().toString(), baseDirPath, start); 54 | } 55 | 56 | @Override 57 | protected RuleDetails getRuleDetails(String ruleKey) { 58 | return engine.getRuleDetails(ruleKey); 59 | } 60 | 61 | @Override 62 | public void stop() { 63 | engine.stop(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/analysis/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | @ParametersAreNonnullByDefault 21 | package org.sonarlint.cli.analysis; 22 | 23 | import javax.annotation.ParametersAreNonnullByDefault; 24 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/config/ConfigurationReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.config; 21 | 22 | import com.google.common.base.Charsets; 23 | import com.google.common.io.Files; 24 | import com.google.gson.GsonBuilder; 25 | import java.io.IOException; 26 | import java.nio.file.Path; 27 | import java.util.HashSet; 28 | import java.util.Set; 29 | 30 | import javax.annotation.Nullable; 31 | 32 | import org.apache.commons.lang.StringUtils; 33 | 34 | public class ConfigurationReader { 35 | private static final String FAIL_PARSE_JSON = "Failed to parse JSON file: "; 36 | 37 | public GlobalConfiguration readGlobal(Path configFilePath) { 38 | String contents = getContents(configFilePath); 39 | GlobalConfiguration config; 40 | 41 | try { 42 | config = new GsonBuilder().create().fromJson(contents, GlobalConfiguration.class); 43 | } catch (RuntimeException ex) { 44 | throw new IllegalStateException(FAIL_PARSE_JSON + configFilePath, ex); 45 | } 46 | 47 | return validate(config, configFilePath); 48 | } 49 | 50 | public ProjectConfiguration readProject(Path configFilePath) { 51 | String contents = getContents(configFilePath); 52 | ProjectConfiguration config; 53 | 54 | try { 55 | config = new GsonBuilder().create().fromJson(contents, ProjectConfiguration.class); 56 | } catch (RuntimeException ex) { 57 | throw new IllegalStateException(FAIL_PARSE_JSON + configFilePath, ex); 58 | } 59 | 60 | return validate(config, configFilePath); 61 | } 62 | 63 | private static String getContents(Path filePath) { 64 | try { 65 | return Files.toString(filePath.toFile(), Charsets.UTF_8); 66 | } catch (IOException e) { 67 | throw new IllegalStateException("Error reading configuration file: " + filePath.toAbsolutePath(), e); 68 | } 69 | } 70 | 71 | private static ProjectConfiguration validate(@Nullable ProjectConfiguration projectConfig, Path configFilePath) { 72 | if (projectConfig == null) { 73 | throw new IllegalStateException(FAIL_PARSE_JSON + configFilePath.toAbsolutePath()); 74 | } 75 | if (StringUtils.isEmpty(projectConfig.projectKey())) { 76 | throw new IllegalStateException("Project binding must have a project key defined. Check the configuration in: " + configFilePath.toAbsolutePath()); 77 | } 78 | return projectConfig; 79 | } 80 | 81 | private static GlobalConfiguration validate(@Nullable GlobalConfiguration globalConfig, Path configFilePath) { 82 | Set serverUrls = new HashSet<>(); 83 | 84 | if (globalConfig == null) { 85 | throw new IllegalStateException(FAIL_PARSE_JSON + configFilePath.toAbsolutePath()); 86 | } 87 | if (globalConfig.servers() != null) { 88 | for (SonarQubeServer s : globalConfig.servers()) { 89 | if (StringUtils.isEmpty(s.url())) { 90 | throw new IllegalStateException("Invalid SonarQube servers configuration: server URL must be defined. Check the configuration in: " + configFilePath); 91 | } 92 | 93 | if (serverUrls.contains(s.url())) { 94 | throw new IllegalStateException("Invalid SonarQube servers configuration: Each server configured must have a unique URL. Check the configuration in: " + configFilePath); 95 | } 96 | 97 | serverUrls.add(s.url()); 98 | } 99 | } 100 | return globalConfig; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/config/GlobalConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.config; 21 | 22 | import java.util.List; 23 | 24 | import javax.annotation.CheckForNull; 25 | 26 | public class GlobalConfiguration { 27 | private List servers; 28 | 29 | @CheckForNull 30 | public List servers() { 31 | return servers; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/config/ProjectConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.config; 21 | 22 | import javax.annotation.CheckForNull; 23 | 24 | public class ProjectConfiguration { 25 | private String serverId; 26 | private String projectKey; 27 | 28 | @CheckForNull 29 | public String serverId() { 30 | return serverId; 31 | } 32 | 33 | @CheckForNull 34 | public String projectKey() { 35 | return projectKey; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/config/SonarQubeServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.config; 21 | 22 | public class SonarQubeServer { 23 | private String id; 24 | private String url; 25 | private String token; 26 | private String login; 27 | private String password; 28 | 29 | public String id() { 30 | return id; 31 | } 32 | 33 | public String url() { 34 | return url; 35 | } 36 | 37 | public String token() { 38 | return token; 39 | } 40 | 41 | public String login() { 42 | return login; 43 | } 44 | 45 | public String password() { 46 | return password; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/config/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | @ParametersAreNonnullByDefault 21 | package org.sonarlint.cli.config; 22 | 23 | import javax.annotation.ParametersAreNonnullByDefault; 24 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | @ParametersAreNonnullByDefault 21 | package org.sonarlint.cli; 22 | 23 | import javax.annotation.ParametersAreNonnullByDefault; 24 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/CategoryReport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | public final class CategoryReport { 23 | private final IssueCategory category; 24 | private final IssueVariation total = new IssueVariation(); 25 | 26 | CategoryReport(IssueCategory category) { 27 | this.category = category; 28 | } 29 | 30 | public IssueVariation getTotal() { 31 | return total; 32 | } 33 | 34 | public IssueCategory getCategory() { 35 | return category; 36 | } 37 | 38 | public String getName() { 39 | return category.getName(); 40 | } 41 | 42 | public Severity getSeverity() { 43 | return category.getSeverity(); 44 | } 45 | 46 | public String getRuleKey() { 47 | return category.getRuleKey(); 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return new StringBuilder() 53 | .append(super.toString()) 54 | .append("[reportRuleKey=") 55 | .append(category) 56 | .append(",total=") 57 | .append(total) 58 | .append("]") 59 | .toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/CategoryReportComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.util.Comparator; 23 | 24 | class CategoryReportComparator implements Comparator { 25 | @Override 26 | public int compare(CategoryReport o1, CategoryReport o2) { 27 | if (bothHaveNoNewIssue(o1, o2)) { 28 | return compareByRuleSeverityAndKey(o1, o2); 29 | } else if (bothHaveNewIssues(o1, o2)) { 30 | if (sameSeverity(o1, o2) && !sameNewIssueCount(o1, o2)) { 31 | return compareNewIssueCount(o1, o2); 32 | } else { 33 | return compareByRuleSeverityAndKey(o1, o2); 34 | } 35 | } else { 36 | return compareNewIssueCount(o1, o2); 37 | } 38 | } 39 | 40 | private static int compareByRuleSeverityAndKey(CategoryReport o1, CategoryReport o2) { 41 | return o1.getCategory().compareTo(o2.getCategory()); 42 | } 43 | 44 | private static boolean sameNewIssueCount(CategoryReport o1, CategoryReport o2) { 45 | return o2.getTotal().getNewIssuesCount() == o1.getTotal().getNewIssuesCount(); 46 | } 47 | 48 | private static boolean sameSeverity(CategoryReport o1, CategoryReport o2) { 49 | return o1.getSeverity().equals(o2.getSeverity()); 50 | } 51 | 52 | private static int compareNewIssueCount(CategoryReport o1, CategoryReport o2) { 53 | return o2.getTotal().getNewIssuesCount() - o1.getTotal().getNewIssuesCount(); 54 | } 55 | 56 | private static boolean bothHaveNewIssues(CategoryReport o1, CategoryReport o2) { 57 | return o1.getTotal().getNewIssuesCount() > 0 && o2.getTotal().getNewIssuesCount() > 0; 58 | } 59 | 60 | private static boolean bothHaveNoNewIssue(CategoryReport o1, CategoryReport o2) { 61 | return o1.getTotal().getNewIssuesCount() == 0 && o2.getTotal().getNewIssuesCount() == 0; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/ConsoleReport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.util.Collection; 23 | import java.util.Date; 24 | import java.util.function.Function; 25 | import org.sonarlint.cli.util.Logger; 26 | import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; 27 | import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; 28 | import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; 29 | import org.sonarsource.sonarlint.core.tracking.Trackable; 30 | 31 | public class ConsoleReport implements Reporter { 32 | 33 | public static final String HEADER = "------------- SonarLint Report -------------"; 34 | private static final Logger LOGGER = Logger.get(); 35 | 36 | public static final String CONSOLE_REPORT_ENABLED_KEY = "sonar.issuesReport.console.enable"; 37 | private static final int LEFT_PAD = 10; 38 | 39 | ConsoleReport() { 40 | 41 | } 42 | 43 | private static class Report { 44 | int totalIssues = 0; 45 | int blockerIssues = 0; 46 | int criticalIssues = 0; 47 | int majorIssues = 0; 48 | int minorIssues = 0; 49 | int infoIssues = 0; 50 | 51 | public void process(Issue issue) { 52 | totalIssues++; 53 | switch (issue.getSeverity()) { 54 | case "BLOCKER": 55 | blockerIssues++; 56 | break; 57 | case "CRITICAL": 58 | criticalIssues++; 59 | break; 60 | case "MAJOR": 61 | majorIssues++; 62 | break; 63 | case "MINOR": 64 | minorIssues++; 65 | break; 66 | case "INFO": 67 | infoIssues++; 68 | break; 69 | default: 70 | throw new IllegalStateException("Unknown severity: " + issue.getSeverity()); 71 | } 72 | } 73 | 74 | public boolean hasNoIssues() { 75 | return totalIssues == 0; 76 | } 77 | } 78 | 79 | @Override 80 | public void execute(String projectName, Date date, Collection trackables, AnalysisResults result, Function ruleDescriptionProducer) { 81 | Report r = new Report(); 82 | for (Trackable trackable : trackables) { 83 | r.process(trackable.getIssue()); 84 | } 85 | printReport(r, result); 86 | } 87 | 88 | public void printReport(Report r, AnalysisResults result) { 89 | StringBuilder sb = new StringBuilder(); 90 | 91 | sb.append("\n\n" + HEADER + "\n\n"); 92 | if (result.fileCount() == 0) { 93 | sb.append(" No files analyzed\n"); 94 | } else if (r.hasNoIssues()) { 95 | sb.append(" No issues to display "); 96 | filesAnalyzed(sb, result.fileCount()); 97 | sb.append("\n"); 98 | } else { 99 | printIssues(r, sb, result.fileCount()); 100 | } 101 | sb.append("\n-------------------------------------------\n\n"); 102 | 103 | LOGGER.info(sb.toString()); 104 | } 105 | 106 | private static void filesAnalyzed(StringBuilder sb, int num) { 107 | sb.append("(").append(num); 108 | if (num > 1) { 109 | sb.append(" files analyzed"); 110 | } else { 111 | sb.append(" file analyzed"); 112 | } 113 | sb.append(")"); 114 | } 115 | 116 | private static void printIssues(Report r, StringBuilder sb, int filesAnalyzed) { 117 | int issues = r.totalIssues; 118 | sb.append(leftPad(Integer.toString(issues), LEFT_PAD)) 119 | .append(" issue"); 120 | if (issues > 1) { 121 | sb.append("s"); 122 | } 123 | sb.append(" "); 124 | 125 | filesAnalyzed(sb, filesAnalyzed); 126 | sb.append("\n\n"); 127 | printIssues(sb, r.blockerIssues, "blocker"); 128 | printIssues(sb, r.criticalIssues, "critical"); 129 | printIssues(sb, r.majorIssues, "major"); 130 | printIssues(sb, r.minorIssues, "minor"); 131 | printIssues(sb, r.infoIssues, "info"); 132 | } 133 | 134 | private static void printIssues(StringBuilder sb, int issueCount, String severityLabel) { 135 | if (issueCount > 0) { 136 | sb.append(leftPad(Integer.toString(issueCount), LEFT_PAD)).append(" ").append(severityLabel).append("\n"); 137 | } 138 | } 139 | 140 | private static String leftPad(String str, int spaces) { 141 | StringBuilder sb = new StringBuilder(); 142 | 143 | for (int i = spaces; i > 0; i--) { 144 | sb.append(" "); 145 | } 146 | 147 | sb.append(str); 148 | return sb.toString(); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/IssueCategory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.util.Objects; 23 | 24 | /** 25 | * A same rule can be present with different severity if severity was manually changed so we categorize by rule key and severity 26 | * 27 | */ 28 | public class IssueCategory implements Comparable { 29 | private final String ruleKey; 30 | private final Severity severity; 31 | private final String name; 32 | 33 | IssueCategory(String ruleKey, Severity severity, String name) { 34 | this.ruleKey = ruleKey; 35 | this.severity = severity; 36 | this.name = name; 37 | } 38 | 39 | public String getRuleKey() { 40 | return ruleKey; 41 | } 42 | 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | public Severity getSeverity() { 48 | return severity; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) { 54 | return true; 55 | } 56 | if (o == null || getClass() != o.getClass()) { 57 | return false; 58 | } 59 | IssueCategory that = (IssueCategory) o; 60 | return Objects.equals(ruleKey, that.ruleKey) && Objects.equals(severity, that.severity); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | int result = ruleKey.hashCode(); 66 | result = 31 * result + severity.hashCode(); 67 | return result; 68 | } 69 | 70 | @Override 71 | public int compareTo(IssueCategory o) { 72 | if (severity == o.getSeverity()) { 73 | return getRuleKey().compareTo(o.getRuleKey()); 74 | } 75 | return o.getSeverity().compareTo(severity); 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | StringBuilder sb = new StringBuilder(); 81 | return sb.append(super.toString()) 82 | .append("[") 83 | .append("rule=").append(ruleKey).append(",severity=").append(severity) 84 | .append("]").toString(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/IssueVariation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | public class IssueVariation { 23 | 24 | private int countInCurrentAnalysis; 25 | private int newIssuesCount; 26 | private int resolvedIssuesCount; 27 | 28 | IssueVariation() { 29 | } 30 | 31 | IssueVariation(int currentCount, int newCount, int resolvedCount) { 32 | this.countInCurrentAnalysis = currentCount; 33 | this.newIssuesCount = newCount; 34 | this.resolvedIssuesCount = resolvedCount; 35 | } 36 | 37 | public int getCountInCurrentAnalysis() { 38 | return countInCurrentAnalysis; 39 | } 40 | 41 | public void incrementCountInCurrentAnalysis() { 42 | this.countInCurrentAnalysis++; 43 | } 44 | 45 | public int getNewIssuesCount() { 46 | return newIssuesCount; 47 | } 48 | 49 | public void incrementNewIssuesCount() { 50 | this.newIssuesCount++; 51 | } 52 | 53 | public int getResolvedIssuesCount() { 54 | return resolvedIssuesCount; 55 | } 56 | 57 | public void incrementResolvedIssuesCount() { 58 | this.resolvedIssuesCount++; 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | final int prime = 31; 64 | int result = 1; 65 | result = prime * result + countInCurrentAnalysis; 66 | result = prime * result + newIssuesCount; 67 | result = prime * result + resolvedIssuesCount; 68 | return result; 69 | } 70 | 71 | @Override 72 | public boolean equals(Object obj) { 73 | if (this == obj) { 74 | return true; 75 | } 76 | if (obj == null || getClass() != obj.getClass()) { 77 | return false; 78 | } 79 | IssueVariation other = (IssueVariation) obj; 80 | 81 | return countInCurrentAnalysis == other.countInCurrentAnalysis 82 | && newIssuesCount == other.newIssuesCount 83 | && resolvedIssuesCount == other.resolvedIssuesCount; 84 | } 85 | 86 | @Override 87 | public String toString() { 88 | return new StringBuilder() 89 | .append(super.toString()) 90 | .append("[countInCurrentAnalysis=") 91 | .append(countInCurrentAnalysis) 92 | .append(",newIssuesCount=") 93 | .append(newIssuesCount) 94 | .append(",resolvedIssuesCount=") 95 | .append(resolvedIssuesCount) 96 | .append("]") 97 | .toString(); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/ReportFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.io.IOException; 23 | import java.nio.charset.Charset; 24 | import java.nio.file.Files; 25 | import java.nio.file.Path; 26 | import java.nio.file.Paths; 27 | import java.util.LinkedList; 28 | import java.util.List; 29 | import javax.annotation.Nullable; 30 | 31 | public class ReportFactory { 32 | private static final String DEFAULT_REPORT_PATH = ".sonarlint/sonarlint-report.html"; 33 | private String htmlPath = null; 34 | private Charset charset; 35 | 36 | public ReportFactory(Charset charset) { 37 | this.charset = charset; 38 | } 39 | 40 | public List createReporters(Path basePath) { 41 | List list = new LinkedList<>(); 42 | 43 | list.add(new ConsoleReport()); 44 | list.add(new HtmlReport(basePath, getReportFile(basePath), charset)); 45 | 46 | return list; 47 | } 48 | 49 | public void setHtmlPath(@Nullable String path) { 50 | htmlPath = path; 51 | } 52 | 53 | Path getReportFile(Path basePath) { 54 | Path reportPath; 55 | 56 | if (htmlPath != null) { 57 | reportPath = Paths.get(htmlPath); 58 | 59 | if (!reportPath.isAbsolute()) { 60 | reportPath = basePath.resolve(reportPath).toAbsolutePath(); 61 | } 62 | } else { 63 | reportPath = basePath.resolve(DEFAULT_REPORT_PATH); 64 | } 65 | 66 | try { 67 | Files.createDirectories(reportPath.getParent()); 68 | } catch (IOException e) { 69 | throw new IllegalStateException("Fail to create the directory " + reportPath.getParent(), e); 70 | } 71 | 72 | return reportPath; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/ReportSummary.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Collections; 24 | import java.util.LinkedHashMap; 25 | import java.util.List; 26 | import java.util.Map; 27 | import org.sonarlint.cli.util.Util; 28 | 29 | public class ReportSummary { 30 | 31 | private final IssueVariation total = new IssueVariation(); 32 | 33 | private final Map reportByCategory = new LinkedHashMap<>(); 34 | private final Map totalByRuleKey = new LinkedHashMap<>(); 35 | private final Map totalBySeverity = new LinkedHashMap<>(); 36 | 37 | ReportSummary() { 38 | } 39 | 40 | public void addIssue(RichIssue issue) { 41 | Severity severity = Severity.create(issue.getSeverity()); 42 | IssueCategory category = new IssueCategory(issue.getRuleKey(), severity, issue.getRuleName()); 43 | 44 | IssueVariation byRuleKey = Util.getOrCreate(totalByRuleKey, issue.getRuleKey(), IssueVariation::new); 45 | CategoryReport byCategory = getOrCreate(reportByCategory, category); 46 | IssueVariation bySeverity = Util.getOrCreate(totalBySeverity, issue.getSeverity(), IssueVariation::new); 47 | 48 | total.incrementCountInCurrentAnalysis(); 49 | byCategory.getTotal().incrementCountInCurrentAnalysis(); 50 | byRuleKey.incrementCountInCurrentAnalysis(); 51 | bySeverity.incrementCountInCurrentAnalysis(); 52 | } 53 | 54 | public IssueVariation getTotal() { 55 | return total; 56 | } 57 | 58 | public Map getTotalBySeverity() { 59 | return totalBySeverity; 60 | } 61 | 62 | public Map getTotalByRuleKey() { 63 | return totalByRuleKey; 64 | } 65 | 66 | private static CategoryReport getOrCreate(Map m, IssueCategory key) { 67 | CategoryReport report = m.get(key); 68 | if (report != null) { 69 | return report; 70 | } 71 | 72 | report = new CategoryReport(key); 73 | m.put(key, report); 74 | return report; 75 | } 76 | 77 | public List getCategoryReports() { 78 | List result = new ArrayList<>(reportByCategory.values()); 79 | Collections.sort(result, new CategoryReportComparator()); 80 | return result; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/Reporter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.util.Collection; 23 | import java.util.Date; 24 | import java.util.function.Function; 25 | import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; 26 | import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; 27 | import org.sonarsource.sonarlint.core.tracking.Trackable; 28 | 29 | @FunctionalInterface 30 | public interface Reporter { 31 | void execute(String projectName, Date date, Collection trackables, AnalysisResults result, Function ruleDescriptionProducer); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/ResourceReport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.nio.file.Path; 23 | import java.nio.file.Paths; 24 | import java.util.ArrayList; 25 | import java.util.Collections; 26 | import java.util.EnumMap; 27 | import java.util.HashMap; 28 | import java.util.LinkedList; 29 | import java.util.List; 30 | import java.util.Map; 31 | import javax.annotation.CheckForNull; 32 | import javax.annotation.Nullable; 33 | import org.sonarlint.cli.util.MutableInt; 34 | 35 | import static org.sonarlint.cli.util.Util.getOrCreate; 36 | 37 | public final class ResourceReport { 38 | private final Path filePath; 39 | private final IssueVariation total = new IssueVariation(); 40 | private final List issues = new ArrayList<>(); 41 | 42 | private final Map reportByCategory = new HashMap<>(); 43 | private final Map> issuesPerLine = new HashMap<>(); 44 | 45 | private final Map issuesByRule = new HashMap<>(); 46 | private final EnumMap issuesBySeverity = new EnumMap<>(Severity.class); 47 | private Path basePath; 48 | 49 | ResourceReport(Path basePath, @Nullable Path filePath) { 50 | this.basePath = basePath; 51 | this.filePath = filePath; 52 | } 53 | 54 | @CheckForNull 55 | public Path getPath() { 56 | return filePath; 57 | } 58 | 59 | public String getName() { 60 | return basePath.toAbsolutePath().relativize(filePath.toAbsolutePath()).toString(); 61 | } 62 | 63 | public String getType() { 64 | if (filePath == null || filePath.equals(Paths.get(""))) { 65 | return "PRJ"; 66 | } else { 67 | return "FIL"; 68 | } 69 | } 70 | 71 | public IssueVariation getTotal() { 72 | return total; 73 | } 74 | 75 | public List getIssues() { 76 | return issues; 77 | } 78 | 79 | public Map> getIssuesPerLine() { 80 | return issuesPerLine; 81 | } 82 | 83 | public List getIssuesAtLine(int lineId) { 84 | if (issuesPerLine.containsKey(lineId)) { 85 | return issuesPerLine.get(lineId); 86 | } 87 | return Collections.emptyList(); 88 | } 89 | 90 | public void addIssue(RichIssue issue) { 91 | Severity severity = Severity.create(issue.getSeverity()); 92 | String ruleKey = issue.getRuleKey(); 93 | IssueCategory reportRuleKey = new IssueCategory(ruleKey, severity, issue.getRuleName()); 94 | 95 | initMaps(reportRuleKey); 96 | issues.add(issue); 97 | Integer line = issue.getStartLine(); 98 | line = line != null ? line : 0; 99 | 100 | getOrCreate(issuesPerLine, line, LinkedList::new).add(issue); 101 | getOrCreate(issuesByRule, ruleKey, MutableInt::new).inc(); 102 | getOrCreate(issuesBySeverity, severity, MutableInt::new).inc(); 103 | 104 | reportByCategory.get(reportRuleKey).getTotal().incrementCountInCurrentAnalysis(); 105 | total.incrementCountInCurrentAnalysis(); 106 | } 107 | 108 | private void initMaps(IssueCategory reportRuleKey) { 109 | if (!reportByCategory.containsKey(reportRuleKey)) { 110 | reportByCategory.put(reportRuleKey, new CategoryReport(reportRuleKey)); 111 | } 112 | } 113 | 114 | public boolean isDisplayableLine(@Nullable Integer lineNumber) { 115 | if (lineNumber == null || lineNumber < 1) { 116 | return false; 117 | } 118 | for (int i = lineNumber - 2; i <= lineNumber + 2; i++) { 119 | if (hasIssues(i)) { 120 | return true; 121 | } 122 | } 123 | return false; 124 | } 125 | 126 | private boolean hasIssues(Integer lineId) { 127 | List issuesAtLine = issuesPerLine.get(lineId); 128 | return issuesAtLine != null && !issuesAtLine.isEmpty(); 129 | } 130 | 131 | public List getCategoryReports() { 132 | List result = new ArrayList<>(reportByCategory.values()); 133 | Collections.sort(result, new CategoryReportComparator()); 134 | return result; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/RichIssue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; 23 | 24 | /** 25 | * Issue, enriched with additional information. 26 | */ 27 | public interface RichIssue extends Issue { 28 | 29 | int id(); 30 | 31 | String ruleDescriptionFileName(); 32 | 33 | String creationDate(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/Severity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | enum Severity { 26 | INFO, 27 | MINOR, 28 | MAJOR, 29 | CRITICAL, 30 | BLOCKER; 31 | 32 | private static final Map MAP; 33 | 34 | Severity() { 35 | } 36 | 37 | static { 38 | MAP = new HashMap<>(); 39 | for (Severity s : Severity.values()) { 40 | MAP.put(s.name(), s); 41 | } 42 | } 43 | 44 | static Severity create(String severity) { 45 | Severity s = MAP.get(severity); 46 | if (s == null) { 47 | throw new IllegalArgumentException("Invalid severity: " + severity); 48 | } 49 | return s; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | @ParametersAreNonnullByDefault 21 | package org.sonarlint.cli.report; 22 | 23 | import javax.annotation.ParametersAreNonnullByDefault; 24 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/source/CharactersReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report.source; 21 | 22 | import java.io.BufferedReader; 23 | import java.io.IOException; 24 | import java.util.ArrayDeque; 25 | import java.util.Deque; 26 | 27 | class CharactersReader { 28 | 29 | static final int END_OF_STREAM = -1; 30 | 31 | private final BufferedReader stringBuffer; 32 | private final Deque openTags; 33 | 34 | private int currentValue; 35 | private int currentIndex = -1; 36 | 37 | public CharactersReader(BufferedReader stringBuffer) { 38 | this.stringBuffer = stringBuffer; 39 | this.openTags = new ArrayDeque<>(); 40 | } 41 | 42 | boolean readNextChar() throws IOException { 43 | currentValue = stringBuffer.read(); 44 | currentIndex++; 45 | return currentValue != END_OF_STREAM; 46 | } 47 | 48 | int getCurrentValue() { 49 | return currentValue; 50 | } 51 | 52 | int getCurrentIndex() { 53 | return currentIndex; 54 | } 55 | 56 | void registerOpenTag(String textType) { 57 | openTags.push(textType); 58 | } 59 | 60 | void removeLastOpenTag() { 61 | openTags.remove(); 62 | } 63 | 64 | Deque getOpenTags() { 65 | return openTags; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/source/DecorationDataHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report.source; 21 | 22 | import com.google.common.collect.Lists; 23 | import java.util.Iterator; 24 | import java.util.List; 25 | import org.sonarlint.cli.report.RichIssue; 26 | 27 | class DecorationDataHolder { 28 | 29 | private List openingTagsEntries; 30 | private int openingTagsIndex; 31 | private List closingTagsOffsets; 32 | private int closingTagsIndex; 33 | 34 | DecorationDataHolder() { 35 | openingTagsEntries = Lists.newArrayList(); 36 | closingTagsOffsets = Lists.newArrayList(); 37 | } 38 | 39 | void loadIssues(List issues, int currentLineIdx, int currentLineLength) { 40 | for (RichIssue issue : issues) { 41 | int startOffset = issue.getStartLine() == currentLineIdx && issue.getStartLineOffset() != null ? issue.getStartLineOffset() : 0; 42 | int endOffset = issue.getEndLine() == currentLineIdx && issue.getEndLineOffset() != null ? issue.getEndLineOffset() : currentLineLength; 43 | if (startOffset < endOffset) { 44 | insertAndPreserveOrder(new OpeningHtmlTag(startOffset, "issue-" + issue.id()), openingTagsEntries); 45 | insertAndPreserveOrder(endOffset, closingTagsOffsets); 46 | } 47 | } 48 | } 49 | 50 | OpeningHtmlTag getCurrentOpeningTagEntry() { 51 | return openingTagsIndex < openingTagsEntries.size() ? openingTagsEntries.get(openingTagsIndex) : null; 52 | } 53 | 54 | void nextOpeningTagEntry() { 55 | openingTagsIndex++; 56 | } 57 | 58 | int getCurrentClosingTagOffset() { 59 | return closingTagsIndex < closingTagsOffsets.size() ? closingTagsOffsets.get(closingTagsIndex) : -1; 60 | } 61 | 62 | void nextClosingTagOffset() { 63 | closingTagsIndex++; 64 | } 65 | 66 | private static void insertAndPreserveOrder(OpeningHtmlTag newEntry, List openingHtmlTags) { 67 | int insertionIndex = 0; 68 | Iterator tagIterator = openingHtmlTags.iterator(); 69 | while (tagIterator.hasNext() && tagIterator.next().getStartOffset() <= newEntry.getStartOffset()) { 70 | insertionIndex++; 71 | } 72 | openingHtmlTags.add(insertionIndex, newEntry); 73 | } 74 | 75 | private static void insertAndPreserveOrder(int newOffset, List orderedOffsets) { 76 | int insertionIndex = 0; 77 | Iterator entriesIterator = orderedOffsets.iterator(); 78 | while (entriesIterator.hasNext() && entriesIterator.next() <= newOffset) { 79 | insertionIndex++; 80 | } 81 | orderedOffsets.add(insertionIndex, newOffset); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/source/HtmlSourceDecorator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report.source; 21 | 22 | import java.util.List; 23 | import javax.annotation.CheckForNull; 24 | import javax.annotation.Nullable; 25 | import org.sonarlint.cli.report.RichIssue; 26 | 27 | public class HtmlSourceDecorator { 28 | 29 | private HtmlSourceDecorator() { 30 | // utility class, forbidden constructor 31 | } 32 | 33 | @CheckForNull 34 | public static String getDecoratedSourceAsHtml(@Nullable String sourceLine, int currentLineIdx, List issues) { 35 | if (sourceLine == null) { 36 | return null; 37 | } 38 | DecorationDataHolder decorationDataHolder = new DecorationDataHolder(); 39 | decorationDataHolder.loadIssues(issues, currentLineIdx, sourceLine.length()); 40 | HtmlTextDecorator textDecorator = new HtmlTextDecorator(); 41 | return textDecorator.decorateLineWithHtml(sourceLine, decorationDataHolder); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/source/HtmlTextDecorator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report.source; 21 | 22 | import java.io.BufferedReader; 23 | import java.io.IOException; 24 | import java.io.StringReader; 25 | import java.util.Collection; 26 | 27 | import static com.google.common.collect.Lists.newArrayList; 28 | 29 | class HtmlTextDecorator { 30 | 31 | static final char HTML_OPENING = '<'; 32 | static final char HTML_CLOSING = '>'; 33 | static final char AMPERSAND = '&'; 34 | static final String ENCODED_HTML_OPENING = "<"; 35 | static final String ENCODED_HTML_CLOSING = ">"; 36 | static final String ENCODED_AMPERSAND = "&"; 37 | 38 | String decorateLineWithHtml(String line, DecorationDataHolder decorationDataHolder) { 39 | 40 | StringBuilder currentHtmlLine = new StringBuilder(); 41 | 42 | BufferedReader stringBuffer = new BufferedReader(new StringReader(line)); 43 | 44 | CharactersReader charsReader = new CharactersReader(stringBuffer); 45 | 46 | try { 47 | while (charsReader.readNextChar()) { 48 | addCharToCurrentLine(charsReader, currentHtmlLine, decorationDataHolder); 49 | } 50 | } catch (IOException e) { 51 | throw new IllegalStateException("Error when decorating source", e); 52 | } 53 | 54 | closeCurrentSyntaxTags(charsReader, currentHtmlLine); 55 | 56 | return currentHtmlLine.toString(); 57 | 58 | } 59 | 60 | private static void addCharToCurrentLine(CharactersReader charsReader, StringBuilder currentHtmlLine, DecorationDataHolder decorationDataHolder) { 61 | int numberOfTagsToClose = getNumberOfTagsToClose(charsReader.getCurrentIndex(), decorationDataHolder); 62 | closeCompletedTags(charsReader, numberOfTagsToClose, currentHtmlLine); 63 | 64 | Collection tagsToOpen = getTagsToOpen(charsReader.getCurrentIndex(), decorationDataHolder); 65 | openNewTags(charsReader, tagsToOpen, currentHtmlLine); 66 | 67 | char currentChar = (char) charsReader.getCurrentValue(); 68 | currentHtmlLine.append(normalize(currentChar)); 69 | } 70 | 71 | private static char[] normalize(char currentChar) { 72 | char[] normalizedChars; 73 | if (currentChar == HTML_OPENING) { 74 | normalizedChars = ENCODED_HTML_OPENING.toCharArray(); 75 | } else if (currentChar == HTML_CLOSING) { 76 | normalizedChars = ENCODED_HTML_CLOSING.toCharArray(); 77 | } else if (currentChar == AMPERSAND) { 78 | normalizedChars = ENCODED_AMPERSAND.toCharArray(); 79 | } else { 80 | normalizedChars = new char[] {currentChar}; 81 | } 82 | return normalizedChars; 83 | } 84 | 85 | private static int getNumberOfTagsToClose(int currentIndex, DecorationDataHolder dataHolder) { 86 | int numberOfTagsToClose = 0; 87 | 88 | while (currentIndex == dataHolder.getCurrentClosingTagOffset()) { 89 | numberOfTagsToClose++; 90 | dataHolder.nextClosingTagOffset(); 91 | } 92 | return numberOfTagsToClose; 93 | } 94 | 95 | private static Collection getTagsToOpen(int currentIndex, DecorationDataHolder dataHolder) { 96 | Collection tagsToOpen = newArrayList(); 97 | while (dataHolder.getCurrentOpeningTagEntry() != null && currentIndex == dataHolder.getCurrentOpeningTagEntry().getStartOffset()) { 98 | tagsToOpen.add(dataHolder.getCurrentOpeningTagEntry().getCssClass()); 99 | dataHolder.nextOpeningTagEntry(); 100 | } 101 | return tagsToOpen; 102 | } 103 | 104 | private static void closeCompletedTags(CharactersReader charactersReader, int numberOfTagsToClose, 105 | StringBuilder decoratedText) { 106 | for (int i = 0; i < numberOfTagsToClose; i++) { 107 | injectClosingHtml(decoratedText); 108 | charactersReader.removeLastOpenTag(); 109 | } 110 | } 111 | 112 | private static void openNewTags(CharactersReader charactersReader, Collection tagsToOpen, 113 | StringBuilder decoratedText) { 114 | for (String tagToOpen : tagsToOpen) { 115 | injectOpeningHtmlForRule(tagToOpen, decoratedText); 116 | charactersReader.registerOpenTag(tagToOpen); 117 | } 118 | } 119 | 120 | private static void closeCurrentSyntaxTags(CharactersReader charactersReader, StringBuilder decoratedText) { 121 | for (int i = 0; i < charactersReader.getOpenTags().size(); i++) { 122 | injectClosingHtml(decoratedText); 123 | } 124 | } 125 | 126 | private static void injectOpeningHtmlForRule(String textType, StringBuilder decoratedText) { 127 | decoratedText.append(""); 128 | } 129 | 130 | private static void injectClosingHtml(StringBuilder decoratedText) { 131 | decoratedText.append(""); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/source/OpeningHtmlTag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report.source; 21 | 22 | class OpeningHtmlTag { 23 | 24 | private final int startOffset; 25 | private final String cssClass; 26 | 27 | OpeningHtmlTag(int startOffset, String cssClass) { 28 | this.startOffset = startOffset; 29 | this.cssClass = cssClass; 30 | } 31 | 32 | int getStartOffset() { 33 | return startOffset; 34 | } 35 | 36 | String getCssClass() { 37 | return cssClass; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/report/source/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | @ParametersAreNonnullByDefault 21 | package org.sonarlint.cli.report.source; 22 | 23 | import javax.annotation.ParametersAreNonnullByDefault; 24 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/util/Logger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | import java.io.PrintStream; 23 | 24 | public class Logger { 25 | private static volatile Logger instance; 26 | private boolean debugEnabled = false; 27 | private boolean displayStackTrace = false; 28 | private PrintStream stdOut; 29 | private PrintStream stdErr; 30 | 31 | private Logger() { 32 | this.stdErr = System.err; 33 | this.stdOut = System.out; 34 | } 35 | 36 | public Logger(PrintStream stdOut, PrintStream stdErr) { 37 | this.stdErr = stdErr; 38 | this.stdOut = stdOut; 39 | } 40 | 41 | public static Logger get() { 42 | if (instance == null) { 43 | instance = new Logger(); 44 | } 45 | return instance; 46 | } 47 | 48 | public static void set(PrintStream stdOut, PrintStream stdErr) { 49 | get().stdOut = stdOut; 50 | get().stdErr = stdErr; 51 | } 52 | 53 | public void setDebugEnabled(boolean debugEnabled) { 54 | this.debugEnabled = debugEnabled; 55 | } 56 | 57 | public void setDisplayStackTrace(boolean displayStackTrace) { 58 | this.displayStackTrace = displayStackTrace; 59 | } 60 | 61 | public boolean isDebugEnabled() { 62 | return debugEnabled; 63 | } 64 | 65 | public void debug(String message) { 66 | if (isDebugEnabled()) { 67 | stdOut.println("DEBUG: " + message); 68 | } 69 | } 70 | 71 | public void debug(String message, Throwable t) { 72 | if (isDebugEnabled()) { 73 | stdErr.println("DEBUG: " + message); 74 | if (displayStackTrace) { 75 | t.printStackTrace(stdErr); 76 | } 77 | } 78 | } 79 | 80 | public void info(String message) { 81 | stdOut.println("INFO: " + message); 82 | } 83 | 84 | public void warn(String message) { 85 | stdOut.println("WARN: " + message); 86 | } 87 | 88 | public void error(String message) { 89 | stdErr.println("ERROR: " + message); 90 | } 91 | 92 | public void error(String message, Throwable t) { 93 | stdErr.println("ERROR: " + message); 94 | if (displayStackTrace) { 95 | t.printStackTrace(stdErr); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/util/MutableInt.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | public class MutableInt { 23 | private int value; 24 | 25 | public MutableInt() { 26 | this(0); 27 | } 28 | 29 | public MutableInt(int value) { 30 | this.value = value; 31 | } 32 | 33 | public void set(int value) { 34 | this.value = value; 35 | } 36 | 37 | public int get() { 38 | return value; 39 | } 40 | 41 | public void inc() { 42 | value++; 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | return value; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object obj) { 52 | if (this == obj) { 53 | return true; 54 | } 55 | if (obj == null || getClass() != obj.getClass()) { 56 | return false; 57 | } 58 | MutableInt other = (MutableInt) obj; 59 | return value == other.value; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/util/System2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | import javax.annotation.CheckForNull; 23 | 24 | import java.util.Map; 25 | import java.util.Properties; 26 | 27 | /** 28 | * Proxy over {@link java.lang.System}. It aims to improve testability of classes 29 | * that interact with low-level system methods, for example : 30 | *

31 | *

 32 |  * public class MyClass {
 33 |  *   private final System2 system;
 34 |  *
 35 |  *   public MyClass(System2 s) {
 36 |  *     this.system = s;
 37 |  *   }
 38 |  *
 39 |  *   public long xxx() {
 40 |  *     return system.now();
 41 |  *   }
 42 |  * }
 43 |  *
 44 |  * {@literal @}Test
 45 |  * public void should_return_xxx() {
 46 |  *   // using Mockito
 47 |  *   System2 system = mock(System2.class);
 48 |  *   long now = 123456789L;
 49 |  *   doReturn(now).when(system).now();
 50 |  *   assertThat(new MyClass(system).xxx()).isEqualTo(now);
 51 |  * }
 52 |  * 
53 | *

54 | * Note that the name System2 was chosen to not conflict with {@link java.lang.System}. 55 | *

56 | */ 57 | public class System2 { 58 | 59 | public static final System2 INSTANCE = new System2(); 60 | 61 | /** 62 | * Shortcut for {@link System#currentTimeMillis()} 63 | */ 64 | public long now() { 65 | return System.currentTimeMillis(); 66 | } 67 | 68 | /** 69 | * Shortcut for {@link System#getProperties()} 70 | */ 71 | public Properties properties() { 72 | return System.getProperties(); 73 | } 74 | 75 | /** 76 | * Shortcut for {@link System#getProperty(String)} 77 | */ 78 | @CheckForNull 79 | public String property(String key) { 80 | return System.getProperty(key); 81 | } 82 | 83 | /** 84 | * Shortcut for {@link System#getProperty(String)} 85 | */ 86 | @CheckForNull 87 | public String getProperty(String key) { 88 | return System.getProperty(key); 89 | } 90 | 91 | /** 92 | * Shortcut for {@link System#getenv(String)} 93 | */ 94 | @CheckForNull 95 | public String getenv(String key) { 96 | return System.getenv(key); 97 | } 98 | 99 | public void exit(int code) { 100 | System.exit(code); 101 | } 102 | 103 | /** 104 | * Shortcut for {@link System#getenv()} 105 | */ 106 | public Map envVariables() { 107 | return System.getenv(); 108 | } 109 | 110 | /** 111 | * Shortcut for {@link System#getenv(String)} 112 | */ 113 | @CheckForNull 114 | public String envVariable(String key) { 115 | return System.getenv(key); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/util/SystemInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | public class SystemInfo { 23 | private static System2 system = new System2(); 24 | 25 | private SystemInfo() { 26 | } 27 | 28 | public static void setSystem(System2 system) { 29 | SystemInfo.system = system; 30 | } 31 | 32 | public static void print(Logger logger) { 33 | logger.info(java()); 34 | logger.info(os()); 35 | String runnerOpts = system.getenv("SONARLINT_OPTS"); 36 | if (runnerOpts != null) { 37 | logger.info("SONARLINT_OPTS=" + runnerOpts); 38 | } 39 | } 40 | 41 | public static String getVersion() { 42 | String version = "unknown"; 43 | 44 | Package p = SystemInfo.class.getPackage(); 45 | if (p != null) { 46 | String implVersion = p.getImplementationVersion(); 47 | if (implVersion != null) { 48 | version = implVersion; 49 | } 50 | } 51 | 52 | return version; 53 | } 54 | 55 | public static String java() { 56 | StringBuilder sb = new StringBuilder(); 57 | sb 58 | .append("Java ") 59 | .append(system.getProperty("java.version")) 60 | .append(" ") 61 | .append(system.getProperty("java.vendor")); 62 | String bits = system.getProperty("sun.arch.data.model"); 63 | if ("32".equals(bits) || "64".equals(bits)) { 64 | sb.append(" (").append(bits).append("-bit)"); 65 | } 66 | return sb.toString(); 67 | } 68 | 69 | public static String os() { 70 | StringBuilder sb = new StringBuilder(); 71 | sb 72 | .append(system.getProperty("os.name")) 73 | .append(" ") 74 | .append(system.getProperty("os.version")) 75 | .append(" ") 76 | .append(system.getProperty("os.arch")); 77 | return sb.toString(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/util/Util.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | import java.util.Properties; 25 | import java.util.function.Supplier; 26 | 27 | public class Util { 28 | private Util() { 29 | // static only 30 | } 31 | 32 | public static U getOrCreate(Map map, T key, Supplier f) { 33 | U value = map.get(key); 34 | if (value != null) { 35 | return value; 36 | } 37 | value = f.get(); 38 | map.put(key, value); 39 | return value; 40 | } 41 | 42 | public static Map toMap(Properties properties) { 43 | return new HashMap<>((Map) properties); 44 | } 45 | 46 | public static String escapeFileName(String fileName) { 47 | return fileName.replaceAll("[^a-zA-Z0-9.-]", "_"); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/sonarlint/cli/util/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | @ParametersAreNonnullByDefault 21 | package org.sonarlint.cli.util; 22 | 23 | import javax.annotation.ParametersAreNonnullByDefault; 24 | -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/DIR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/DIR.png -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/FIL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/FIL.png -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/PRJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/PRJ.png -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/favicon.ico -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/rule.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Helvetica Neue, Segoe UI, Helvetica, Arial, sans-serif; 3 | font-size: 13px; 4 | line-height: 1.23076923; 5 | } 6 | 7 | h1 { 8 | color: #444; 9 | font-size: 14px; 10 | font-weight: 500; 11 | } 12 | 13 | h2 { 14 | line-height: 24px; 15 | color: #444; 16 | } 17 | 18 | a { 19 | border-bottom: 1px solid #cae3f2; 20 | color: #236a97; 21 | cursor: pointer; 22 | outline: none; 23 | text-decoration: none; 24 | transition: all .2s ease; 25 | } 26 | 27 | .rule-desc { 28 | line-height: 1.5; 29 | } 30 | 31 | .rule-desc { 32 | line-height: 1.5; 33 | } 34 | 35 | .rule-desc h2 { 36 | font-size: 16px; 37 | font-weight: 400; 38 | } 39 | 40 | .rule-desc code { 41 | padding: .2em .45em; 42 | margin: 0; 43 | background-color: rgba(0, 0, 0, .04); 44 | border-radius: 3px; 45 | white-space: nowrap; 46 | } 47 | 48 | .rule-desc pre { 49 | padding: 10px; 50 | border-top: 1px solid #e6e6e6; 51 | border-bottom: 1px solid #e6e6e6; 52 | line-height: 18px; 53 | overflow: auto; 54 | } 55 | 56 | .rule-desc code, .rule-desc pre { 57 | font-family: Consolas, Liberation Mono, Menlo, Courier, monospace; 58 | font-size: 12px; 59 | } 60 | 61 | .rule-desc ul { 62 | padding-left: 40px; 63 | list-style: disc; 64 | } -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sep12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sep12.png -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.eot -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.ttf -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonar.woff -------------------------------------------------------------------------------- /src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonarlint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonarlint-cli/be030e98d118c41b39762b3becb04d309653030f/src/main/resources/org/sonarlint/cli/report/sonarlintreport_files/sonarlint.png -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/OptionsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli; 21 | 22 | import java.text.ParseException; 23 | import org.junit.Rule; 24 | import org.junit.Test; 25 | import org.junit.rules.ExpectedException; 26 | 27 | import static org.assertj.core.api.Assertions.assertThat; 28 | 29 | public class OptionsTest { 30 | @Rule 31 | public ExpectedException exception = ExpectedException.none(); 32 | 33 | @Test 34 | public void testHelp() throws ParseException { 35 | Options opt = Options.parse(args("-h")); 36 | assertThat(opt.isHelp()).isTrue(); 37 | 38 | opt = Options.parse(args("--help")); 39 | assertThat(opt.isHelp()).isTrue(); 40 | } 41 | 42 | @Test 43 | public void testReport() throws ParseException { 44 | Options opt = Options.parse(args("--html-report", "myreport")); 45 | 46 | assertThat(opt.htmlReport()).isEqualTo("myreport"); 47 | } 48 | 49 | @Test 50 | public void testGlobs() throws ParseException { 51 | Options opt = Options.parse(args("--src", "source", "--tests", "tests", "--exclude", "exclude")); 52 | 53 | assertThat(opt.src()).isEqualTo("source"); 54 | assertThat(opt.tests()).isEqualTo("tests"); 55 | assertThat(opt.exclusions()).isEqualTo("exclude"); 56 | } 57 | 58 | @Test 59 | public void testStack() throws ParseException { 60 | Options opt = Options.parse(args("-e")); 61 | assertThat(opt.showStack()).isTrue(); 62 | 63 | opt = Options.parse(args("--errors")); 64 | assertThat(opt.showStack()).isTrue(); 65 | } 66 | 67 | @Test 68 | public void testCharset() throws ParseException { 69 | Options opt = Options.parse(args("--charset", "UTF-8")); 70 | assertThat(opt.charset()).isEqualTo("UTF-8"); 71 | } 72 | 73 | @Test 74 | public void testUpdate() throws ParseException { 75 | Options opt = Options.parse(args("-u")); 76 | assertThat(opt.isUpdate()).isTrue(); 77 | 78 | opt = Options.parse(args("--update")); 79 | assertThat(opt.isUpdate()).isTrue(); 80 | } 81 | 82 | @Test 83 | public void testInteractive() throws ParseException { 84 | Options opt = Options.parse(args("-i")); 85 | assertThat(opt.isInteractive()).isTrue(); 86 | 87 | opt = Options.parse(args("--interactive")); 88 | assertThat(opt.isInteractive()).isTrue(); 89 | } 90 | 91 | @Test 92 | public void testVersion() throws ParseException { 93 | Options opt = Options.parse(args("-v")); 94 | assertThat(opt.isVersion()).isTrue(); 95 | 96 | opt = Options.parse(args("--version")); 97 | assertThat(opt.isVersion()).isTrue(); 98 | } 99 | 100 | @Test 101 | public void testVerbose() throws ParseException { 102 | Options opt = Options.parse(args("-X")); 103 | assertThat(opt.isVerbose()).isTrue(); 104 | } 105 | 106 | @Test 107 | public void testTask() throws ParseException { 108 | Options opt = Options.parse(args("mytask")); 109 | assertThat(opt.task()).isEqualTo("mytask"); 110 | } 111 | 112 | @Test 113 | public void testInvalidArg() throws ParseException { 114 | exception.expect(ParseException.class); 115 | exception.expectMessage("Unrecognized option:"); 116 | Options.parse(args("-a")); 117 | } 118 | 119 | @Test 120 | public void testArgMissing() throws ParseException { 121 | exception.expect(ParseException.class); 122 | exception.expectMessage("Missing argument for option -D"); 123 | Options.parse(args("-D")); 124 | } 125 | 126 | @Test 127 | public void testProperties() throws ParseException { 128 | Options opt = Options.parse(args("-Dkey=value", "--define", "key2=value2")); 129 | 130 | assertThat(opt.properties()).containsEntry("key", "value"); 131 | assertThat(opt.properties()).containsEntry("key2", "value2"); 132 | } 133 | 134 | @Test 135 | public void testCombinedOptions() throws ParseException { 136 | Options opt = Options.parse(args("-X", "-e", "--help")); 137 | 138 | assertThat(opt.isVerbose()).isTrue(); 139 | assertThat(opt.showStack()).isTrue(); 140 | assertThat(opt.isHelp()).isTrue(); 141 | } 142 | 143 | private static String[] args(String... str) { 144 | return str; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/StatsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli; 21 | 22 | import org.mockito.Mockito; 23 | import org.sonarlint.cli.util.Logger; 24 | 25 | import java.io.PrintStream; 26 | import java.io.UnsupportedEncodingException; 27 | 28 | import static org.mockito.Mockito.verify; 29 | import static org.mockito.Mockito.mock; 30 | 31 | import org.junit.Before; 32 | import org.junit.Test; 33 | 34 | import static org.assertj.core.api.Assertions.assertThat; 35 | 36 | public class StatsTest { 37 | private PrintStream stdOut = mock(PrintStream.class); 38 | private PrintStream stdErr; 39 | 40 | @Before 41 | public void setUp() { 42 | Logger.set(stdOut, stdErr); 43 | } 44 | 45 | @Test 46 | public void shouldPrintStats() throws UnsupportedEncodingException { 47 | new Stats().start().stop(); 48 | 49 | verify(stdOut).println(Mockito.contains("Total time: ")); 50 | verify(stdOut).println(Mockito.contains("Final Memory: ")); 51 | } 52 | 53 | @Test 54 | public void shouldFormatTime() { 55 | assertThat(Stats.formatTime(1 * 60 * 60 * 1000 + 2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("1:02:03.400s"); 56 | assertThat(Stats.formatTime(2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("2:03.400s"); 57 | assertThat(Stats.formatTime(3 * 1000 + 400)).isEqualTo("3.400s"); 58 | assertThat(Stats.formatTime(400)).isEqualTo("0.400s"); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/TestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli; 21 | 22 | import org.sonarlint.cli.report.RichIssue; 23 | import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; 24 | 25 | import static org.mockito.Mockito.mock; 26 | import static org.mockito.Mockito.when; 27 | 28 | public class TestUtils { 29 | public static RichIssue createTestIssue(String filePath, String ruleKey, String severity, int line) { 30 | ClientInputFile inputFile = mock(ClientInputFile.class); 31 | when(inputFile.getPath()).thenReturn(filePath); 32 | 33 | RichIssue issue = mock(RichIssue.class); 34 | when(issue.getStartLine()).thenReturn(line); 35 | when(issue.getInputFile()).thenReturn(inputFile); 36 | when(issue.getRuleKey()).thenReturn(ruleKey); 37 | when(issue.getSeverity()).thenReturn(severity); 38 | return issue; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/analysis/IssueCollectorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.analysis; 21 | 22 | import static org.mockito.Mockito.mock; 23 | import static org.assertj.core.api.Assertions.*; 24 | 25 | import org.junit.Test; 26 | import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; 27 | 28 | public class IssueCollectorTest { 29 | @Test 30 | public void testCollector() { 31 | IssueCollector collector = new IssueCollector(); 32 | Issue i1 = mock(Issue.class); 33 | Issue i2 = mock(Issue.class); 34 | collector.handle(i1); 35 | collector.handle(i2); 36 | 37 | assertThat(collector.get()).containsExactly(i1, i2); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/analysis/StandaloneSonarLintTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.analysis; 21 | 22 | import org.junit.Before; 23 | import org.junit.Rule; 24 | import org.junit.Test; 25 | import org.junit.rules.ExpectedException; 26 | import org.junit.rules.TemporaryFolder; 27 | import org.sonarlint.cli.InputFileFinder; 28 | import org.sonarlint.cli.report.ReportFactory; 29 | import org.sonarsource.sonarlint.core.StandaloneSonarLintEngineImpl; 30 | import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; 31 | import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneGlobalConfiguration; 32 | import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneSonarLintEngine; 33 | 34 | import java.io.IOException; 35 | import java.nio.charset.StandardCharsets; 36 | import java.nio.file.Path; 37 | import java.util.Collections; 38 | import java.util.HashMap; 39 | 40 | import static org.assertj.core.api.Assertions.assertThat; 41 | import static org.mockito.Matchers.any; 42 | import static org.mockito.Mockito.mock; 43 | import static org.mockito.Mockito.verify; 44 | import static org.mockito.Mockito.when; 45 | 46 | public class StandaloneSonarLintTest { 47 | private StandaloneSonarLint sonarLint; 48 | private StandaloneSonarLintEngine engine; 49 | 50 | @Rule 51 | public TemporaryFolder temp = new TemporaryFolder(); 52 | 53 | @Rule 54 | public ExpectedException exception = ExpectedException.none(); 55 | 56 | @Before 57 | public void setUp() throws IOException { 58 | engine = new StandaloneSonarLintEngineImpl(StandaloneGlobalConfiguration.builder().build()); 59 | sonarLint = new StandaloneSonarLint(engine); 60 | } 61 | 62 | @Test 63 | public void startStop() { 64 | engine = mock(StandaloneSonarLintEngine.class); 65 | sonarLint = new StandaloneSonarLint(engine); 66 | sonarLint.stop(); 67 | verify(engine).stop(); 68 | } 69 | 70 | @Test 71 | public void run() throws IOException { 72 | InputFileFinder fileFinder = mock(InputFileFinder.class); 73 | Path inputFile = temp.newFile().toPath(); 74 | when(fileFinder.collect(any(Path.class))).thenReturn(Collections.singletonList(createInputFile(inputFile, false))); 75 | Path projectHome = temp.newFolder().toPath(); 76 | sonarLint.runAnalysis(new HashMap<>(), new ReportFactory(StandardCharsets.UTF_8), fileFinder, projectHome); 77 | 78 | verify(fileFinder).collect(projectHome); 79 | 80 | Path htmlReport = projectHome.resolve(".sonarlint").resolve("sonarlint-report.html"); 81 | assertThat(htmlReport).exists(); 82 | } 83 | 84 | @Test 85 | public void runWithoutFiles() throws IOException { 86 | InputFileFinder fileFinder = mock(InputFileFinder.class); 87 | when(fileFinder.collect(any(Path.class))).thenReturn(Collections.emptyList()); 88 | Path projectHome = temp.newFolder().toPath(); 89 | sonarLint.runAnalysis(new HashMap<>(), new ReportFactory(StandardCharsets.UTF_8), fileFinder, projectHome); 90 | 91 | Path htmlReport = projectHome.resolve(".sonarlint").resolve("sonarlint-report.html"); 92 | assertThat(htmlReport).doesNotExist(); 93 | } 94 | 95 | private static ClientInputFile createInputFile(final Path filePath, final boolean test) { 96 | return new InputFileFinder.DefaultClientInputFile(filePath, test, StandardCharsets.UTF_8); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/config/ConfigurationReaderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.config; 21 | 22 | import java.io.IOException; 23 | import java.nio.charset.StandardCharsets; 24 | import java.nio.file.Files; 25 | import java.nio.file.Path; 26 | import org.junit.Rule; 27 | import org.junit.Test; 28 | import org.junit.rules.ExpectedException; 29 | import org.junit.rules.TemporaryFolder; 30 | 31 | import static org.assertj.core.api.Assertions.assertThat; 32 | 33 | public class ConfigurationReaderTest { 34 | @Rule 35 | public TemporaryFolder temp = new TemporaryFolder(); 36 | 37 | @Rule 38 | public ExpectedException exception = ExpectedException.none(); 39 | 40 | @Test 41 | public void readProjectConfig() throws IOException { 42 | String json = "{serverId=\"localhost\",projectKey=project1}"; 43 | 44 | Path file = temp.newFile().toPath(); 45 | Files.write(file, json.getBytes(StandardCharsets.UTF_8)); 46 | ProjectConfiguration projectConfig = new ConfigurationReader().readProject(file); 47 | 48 | assertThat(projectConfig.serverId()).isEqualTo("localhost"); 49 | assertThat(projectConfig.projectKey()).isEqualTo("project1"); 50 | } 51 | 52 | @Test 53 | public void readEmptyFileProject() throws IOException { 54 | String json = ""; 55 | 56 | Path file = temp.newFile().toPath(); 57 | Files.write(file, json.getBytes(StandardCharsets.UTF_8)); 58 | exception.expect(IllegalStateException.class); 59 | exception.expectMessage("Failed to parse JSON file"); 60 | new ConfigurationReader().readProject(file); 61 | } 62 | 63 | @Test 64 | public void readEmptyFileGlobal() throws IOException { 65 | String json = ""; 66 | 67 | Path file = temp.newFile().toPath(); 68 | Files.write(file, json.getBytes(StandardCharsets.UTF_8)); 69 | exception.expect(IllegalStateException.class); 70 | exception.expectMessage("Failed to parse JSON file"); 71 | new ConfigurationReader().readGlobal(file); 72 | } 73 | 74 | @Test 75 | public void readInvalidJsonGlobal() throws IOException { 76 | String json = "{" 77 | + "servers = [" 78 | + " { ] {]}"; 79 | 80 | Path file = temp.newFile().toPath(); 81 | Files.write(file, json.getBytes(StandardCharsets.UTF_8)); 82 | exception.expect(IllegalStateException.class); 83 | exception.expectMessage("Failed to parse JSON file"); 84 | new ConfigurationReader().readGlobal(file); 85 | } 86 | 87 | @Test 88 | public void readInvalidJsonProject() throws IOException { 89 | String json = "{" 90 | + "servers = [" 91 | + " { ] {]}"; 92 | 93 | Path file = temp.newFile().toPath(); 94 | Files.write(file, json.getBytes(StandardCharsets.UTF_8)); 95 | exception.expect(IllegalStateException.class); 96 | exception.expectMessage("Failed to parse JSON file"); 97 | new ConfigurationReader().readProject(file); 98 | } 99 | 100 | @Test 101 | public void readGlobalConfig() throws IOException { 102 | String json = "{" 103 | + "servers = [{" 104 | + " url = \"http://localhost:9000\"," 105 | + " token = mytoken" 106 | + "}" 107 | + "]}"; 108 | 109 | Path file = temp.newFile().toPath(); 110 | Files.write(file, json.getBytes(StandardCharsets.UTF_8)); 111 | GlobalConfiguration config = new ConfigurationReader().readGlobal(file); 112 | 113 | assertThat(config.servers()).hasSize(1); 114 | assertThat(config.servers().get(0).url()).isEqualTo("http://localhost:9000"); 115 | assertThat(config.servers().get(0).token()).isEqualTo("mytoken"); 116 | } 117 | 118 | @Test 119 | public void failWithRepeatedServers() throws IOException { 120 | String json = "{" 121 | + "servers = [" 122 | + " {url = \"http://localhost:9000\",token = mytoken}," 123 | + " {url = \"http://localhost:9000\",token = mytoken}" 124 | + "]}"; 125 | 126 | Path file = temp.newFile().toPath(); 127 | Files.write(file, json.getBytes(StandardCharsets.UTF_8)); 128 | 129 | exception.expect(IllegalStateException.class); 130 | exception.expectMessage("Invalid SonarQube servers configuration: Each server configured must have a unique URL"); 131 | new ConfigurationReader().readGlobal(file); 132 | } 133 | 134 | @Test 135 | public void failServerWithoutUrl() throws IOException { 136 | String json = "{" 137 | + "servers = [" 138 | + " {token = mytoken}" 139 | + "]}"; 140 | 141 | Path file = temp.newFile().toPath(); 142 | Files.write(file, json.getBytes(StandardCharsets.UTF_8)); 143 | 144 | exception.expect(IllegalStateException.class); 145 | exception.expectMessage("Invalid SonarQube servers configuration: server URL must be defined"); 146 | new ConfigurationReader().readGlobal(file); 147 | } 148 | 149 | @Test 150 | public void failProjectWithoutBindingKey() throws IOException { 151 | String json = "{serverUrl=\"http://localhost:9000\"}"; 152 | 153 | Path file = temp.newFile().toPath(); 154 | Files.write(file, json.getBytes(StandardCharsets.UTF_8)); 155 | 156 | exception.expect(IllegalStateException.class); 157 | exception.expectMessage("Project binding must have a project key defined"); 158 | new ConfigurationReader().readProject(file); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/report/CategoryReportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | import static org.mockito.Mockito.mock; 27 | import static org.mockito.Mockito.when; 28 | 29 | public class CategoryReportTest { 30 | private CategoryReport report; 31 | private IssueCategory cat; 32 | 33 | @Before 34 | public void setUp() { 35 | cat = mock(IssueCategory.class); 36 | when(cat.getRuleKey()).thenReturn("rule1"); 37 | when(cat.getSeverity()).thenReturn(Severity.MINOR); 38 | report = new CategoryReport(cat); 39 | } 40 | 41 | @Test 42 | public void testGetters() { 43 | assertThat(report.getRuleKey()).isEqualTo("rule1"); 44 | assertThat(report.getSeverity()).isEqualTo(Severity.MINOR); 45 | assertThat(report.getCategory()).isEqualTo(cat); 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/report/ConsoleReportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.io.ByteArrayOutputStream; 23 | import java.io.IOException; 24 | import java.io.PrintStream; 25 | import java.nio.charset.StandardCharsets; 26 | import java.util.Date; 27 | import java.util.LinkedList; 28 | import java.util.List; 29 | import java.util.stream.Collectors; 30 | import org.junit.Before; 31 | import org.junit.Rule; 32 | import org.junit.Test; 33 | import org.junit.rules.ExpectedException; 34 | import org.sonarlint.cli.util.Logger; 35 | import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; 36 | import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; 37 | import org.sonarsource.sonarlint.core.tracking.IssueTrackable; 38 | import org.sonarsource.sonarlint.core.tracking.Trackable; 39 | 40 | import static org.assertj.core.api.Assertions.assertThat; 41 | import static org.mockito.Mockito.mock; 42 | import static org.mockito.Mockito.when; 43 | import static org.sonarlint.cli.TestUtils.createTestIssue; 44 | 45 | public class ConsoleReportTest { 46 | private final static String PROJECT_NAME = "project"; 47 | private final static Date DATE = new Date(System.currentTimeMillis()); 48 | @Rule 49 | public ExpectedException exception = ExpectedException.none(); 50 | private ConsoleReport report; 51 | private AnalysisResults result; 52 | private ByteArrayOutputStream out; 53 | private ByteArrayOutputStream err; 54 | private PrintStream stdOut; 55 | private PrintStream stdErr; 56 | 57 | @Before 58 | public void setUp() { 59 | setStreams(); 60 | report = new ConsoleReport(); 61 | result = mock(AnalysisResults.class); 62 | when(result.fileCount()).thenReturn(1); 63 | } 64 | 65 | @Test 66 | public void testLog() throws IOException { 67 | List issues = new LinkedList<>(); 68 | issues.add(createTestIssue("comp1", "rule", "MAJOR", 10)); 69 | issues.add(createTestIssue("comp1", "rule", "MINOR", 10)); 70 | issues.add(createTestIssue("comp1", "rule", "CRITICAL", 10)); 71 | issues.add(createTestIssue("comp1", "rule", "INFO", 10)); 72 | issues.add(createTestIssue("comp1", "rule", "BLOCKER", 10)); 73 | 74 | List trackables = toTrackables(issues); 75 | 76 | report.execute(PROJECT_NAME, DATE, toTrackables(issues), result, k -> null); 77 | 78 | stdOut.flush(); 79 | assertThat(getLog(out)).contains("SonarLint Report"); 80 | assertThat(getLog(out)).contains("5 issues"); 81 | assertThat(getLog(out)).contains("1 major"); 82 | assertThat(getLog(out)).contains("1 minor"); 83 | assertThat(getLog(out)).contains("1 info"); 84 | assertThat(getLog(out)).contains("1 critical"); 85 | assertThat(getLog(out)).contains("1 blocker"); 86 | 87 | assertThat(getLog(out)).doesNotContain("new"); 88 | } 89 | 90 | private List toTrackables(List issues) { 91 | return issues.stream().map(IssueTrackable::new).collect(Collectors.toList()); 92 | } 93 | 94 | @Test 95 | public void testInvalidSeverity() throws IOException { 96 | List issues = new LinkedList<>(); 97 | issues.add(createTestIssue("comp1", "rule", "INVALID", 10)); 98 | 99 | exception.expect(IllegalStateException.class); 100 | exception.expectMessage("Unknown severity"); 101 | report.execute(PROJECT_NAME, DATE, toTrackables(issues), result, k -> null); 102 | } 103 | 104 | @Test 105 | public void testReportWithoutIssues() throws IOException { 106 | List issues = new LinkedList<>(); 107 | report.execute(PROJECT_NAME, DATE, toTrackables(issues), result, k -> null); 108 | stdOut.flush(); 109 | assertThat(getLog(out)).contains("SonarLint Report"); 110 | assertThat(getLog(out)).contains("No issues to display"); 111 | assertThat(getLog(out)).contains("1 file analyzed"); 112 | } 113 | 114 | @Test 115 | public void testReportMultipleFiles() throws IOException { 116 | when(result.fileCount()).thenReturn(2); 117 | List issues = new LinkedList<>(); 118 | report.execute(PROJECT_NAME, DATE, toTrackables(issues), result, k -> null); 119 | stdOut.flush(); 120 | assertThat(getLog(out)).contains("SonarLint Report"); 121 | assertThat(getLog(out)).contains("No issues to display"); 122 | assertThat(getLog(out)).contains("2 files analyzed"); 123 | } 124 | 125 | @Test 126 | public void testReportNoFilesAnalyzed() throws IOException { 127 | List issues = new LinkedList<>(); 128 | when(result.fileCount()).thenReturn(0); 129 | report.execute(PROJECT_NAME, DATE, toTrackables(issues), result, k -> null); 130 | stdOut.flush(); 131 | assertThat(getLog(out)).contains("SonarLint Report"); 132 | assertThat(getLog(out)).contains("No files analyzed"); 133 | 134 | assertThat(getLog(out)).doesNotContain("issues"); 135 | } 136 | 137 | private String getLog(ByteArrayOutputStream byteStream) throws IOException { 138 | return new String(byteStream.toByteArray(), StandardCharsets.UTF_8); 139 | } 140 | 141 | private void setStreams() { 142 | out = new ByteArrayOutputStream(); 143 | err = new ByteArrayOutputStream(); 144 | stdOut = new PrintStream(out); 145 | stdErr = new PrintStream(err); 146 | Logger.set(stdOut, stdErr); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/report/HtmlReportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.nio.charset.StandardCharsets; 23 | import java.nio.file.Path; 24 | import java.util.Arrays; 25 | import java.util.Date; 26 | import java.util.LinkedList; 27 | import org.junit.Before; 28 | import org.junit.Rule; 29 | import org.junit.Test; 30 | import org.junit.rules.TemporaryFolder; 31 | import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; 32 | import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults; 33 | import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; 34 | import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; 35 | import org.sonarsource.sonarlint.core.tracking.IssueTrackable; 36 | import org.sonarsource.sonarlint.core.tracking.Trackable; 37 | 38 | import static org.assertj.core.api.Assertions.assertThat; 39 | import static org.mockito.Mockito.mock; 40 | import static org.mockito.Mockito.when; 41 | 42 | public class HtmlReportTest { 43 | private HtmlReport html; 44 | private AnalysisResults result; 45 | 46 | @Rule 47 | public TemporaryFolder temp = new TemporaryFolder(); 48 | private Path reportFile; 49 | 50 | @Before 51 | public void setUp() { 52 | result = mock(AnalysisResults.class); 53 | when(result.fileCount()).thenReturn(1); 54 | reportFile = temp.getRoot().toPath().resolve("report.html"); 55 | html = new HtmlReport(temp.getRoot().toPath(), reportFile, StandardCharsets.UTF_8); 56 | } 57 | 58 | @Test 59 | public void testHtml() { 60 | html.execute("project", new Date(), new LinkedList<>(), result, k -> null); 61 | } 62 | 63 | @Test 64 | public void testCopyRuleDesc() { 65 | html.execute("project", new Date(), Arrays.asList(createTestIssue("foo", "squid:1234", "bla", "MAJOR", 1)), result, 66 | k -> "squid:1234".equals(k) ? mockRuleDetails() : null); 67 | 68 | assertThat(reportFile.getParent().resolve("sonarlintreport_rules/rule.css").toFile()).exists(); 69 | assertThat(reportFile.getParent().resolve("sonarlintreport_rules/squid_1234.html").toFile()).usingCharset(StandardCharsets.UTF_8).hasContent( 70 | "

Foo (squid:1234)

foo bar
"); 71 | } 72 | 73 | @Test 74 | public void testExtendedDesc() { 75 | RuleDetails mockRuleDetailsWithExtendedDesc = mockRuleDetails(); 76 | when(mockRuleDetailsWithExtendedDesc.getExtendedDescription()).thenReturn("bar baz"); 77 | 78 | html.execute("project", new Date(), Arrays.asList(createTestIssue("foo", "squid:1234", "bla", "MAJOR", 1)), result, 79 | k -> "squid:1234".equals(k) ? mockRuleDetailsWithExtendedDesc : null); 80 | 81 | assertThat(reportFile.getParent().resolve("sonarlintreport_rules/rule.css").toFile()).exists(); 82 | assertThat(reportFile.getParent().resolve("sonarlintreport_rules/squid_1234.html").toFile()).usingCharset(StandardCharsets.UTF_8).hasContent( 83 | "

Foo (squid:1234)

foo bar\n
bar baz
"); 84 | } 85 | 86 | private RuleDetails mockRuleDetails() { 87 | RuleDetails ruleDetails = mock(RuleDetails.class); 88 | when(ruleDetails.getName()).thenReturn("Foo"); 89 | when(ruleDetails.getHtmlDescription()).thenReturn("foo bar"); 90 | when(ruleDetails.getExtendedDescription()).thenReturn(""); 91 | return ruleDetails; 92 | } 93 | 94 | private static Trackable createTestIssue(String filePath, String ruleKey, String name, String severity, int line) { 95 | ClientInputFile inputFile = mock(ClientInputFile.class); 96 | when(inputFile.getPath()).thenReturn(filePath); 97 | 98 | Issue issue = mock(Issue.class); 99 | when(issue.getStartLine()).thenReturn(line); 100 | when(issue.getStartLineOffset()).thenReturn(null); 101 | when(issue.getEndLine()).thenReturn(line); 102 | when(issue.getEndLineOffset()).thenReturn(null); 103 | when(issue.getRuleName()).thenReturn(name); 104 | when(issue.getInputFile()).thenReturn(inputFile); 105 | when(issue.getRuleKey()).thenReturn(ruleKey); 106 | when(issue.getSeverity()).thenReturn(severity); 107 | return new IssueTrackable(issue); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/report/IssueCategoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | 27 | public class IssueCategoryTest { 28 | private final static String RULE_KEY = "key"; 29 | private final static String RULE_NAME = "key name"; 30 | private final static Severity SEVERITY = Severity.MAJOR; 31 | private IssueCategory category; 32 | 33 | @Before 34 | public void setUp() { 35 | category = new IssueCategory(RULE_KEY, SEVERITY, RULE_NAME); 36 | } 37 | 38 | @Test 39 | public void getters() { 40 | assertThat(category.getRuleKey()).isEqualTo(RULE_KEY); 41 | assertThat(category.getSeverity()).isEqualTo(SEVERITY); 42 | assertThat(category.getName()).isEqualTo(RULE_NAME); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/report/IssueVariationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | 27 | public class IssueVariationTest { 28 | private IssueVariation variation; 29 | 30 | @Before 31 | public void setUp() { 32 | variation = new IssueVariation(); 33 | } 34 | 35 | @Test 36 | public void defaultZero() { 37 | assertThat(variation.getCountInCurrentAnalysis()).isZero(); 38 | assertThat(variation.getNewIssuesCount()).isZero(); 39 | assertThat(variation.getResolvedIssuesCount()).isZero(); 40 | } 41 | 42 | @Test 43 | public void incCurrent() { 44 | variation.incrementCountInCurrentAnalysis(); 45 | 46 | assertThat(variation.getCountInCurrentAnalysis()).isEqualTo(1); 47 | assertThat(variation.getNewIssuesCount()).isZero(); 48 | assertThat(variation.getResolvedIssuesCount()).isZero(); 49 | } 50 | 51 | @Test 52 | public void incNew() { 53 | variation.incrementNewIssuesCount(); 54 | 55 | assertThat(variation.getCountInCurrentAnalysis()).isZero(); 56 | assertThat(variation.getNewIssuesCount()).isEqualTo(1); 57 | assertThat(variation.getResolvedIssuesCount()).isZero(); 58 | } 59 | 60 | @Test 61 | public void incResolved() { 62 | variation.incrementResolvedIssuesCount(); 63 | 64 | assertThat(variation.getCountInCurrentAnalysis()).isZero(); 65 | assertThat(variation.getNewIssuesCount()).isZero(); 66 | assertThat(variation.getResolvedIssuesCount()).isEqualTo(1); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/report/IssuesReportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.io.IOException; 23 | import java.nio.charset.StandardCharsets; 24 | import java.nio.file.Path; 25 | import java.nio.file.Paths; 26 | import java.util.Date; 27 | import javax.annotation.Nullable; 28 | import org.apache.commons.io.FileUtils; 29 | import org.junit.Before; 30 | import org.junit.Rule; 31 | import org.junit.Test; 32 | import org.junit.rules.TemporaryFolder; 33 | import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; 34 | import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue; 35 | import org.sonarsource.sonarlint.core.tracking.IssueTrackable; 36 | import org.sonarsource.sonarlint.core.tracking.Trackable; 37 | 38 | import static org.assertj.core.api.Assertions.assertThat; 39 | import static org.mockito.Mockito.mock; 40 | import static org.mockito.Mockito.when; 41 | 42 | public class IssuesReportTest { 43 | 44 | @Rule 45 | public TemporaryFolder temp = new TemporaryFolder(); 46 | 47 | private IssuesReport report; 48 | 49 | @Before 50 | public void setUp() { 51 | report = new IssuesReport(Paths.get(""), StandardCharsets.UTF_8); 52 | } 53 | 54 | @Test 55 | public void test_round_trip() { 56 | Date d = new Date(); 57 | String title = "title"; 58 | 59 | report.setDate(d); 60 | report.setTitle(title); 61 | 62 | assertThat(report.getDate()).isEqualTo(d); 63 | assertThat(report.getTitle()).isEqualTo(title); 64 | assertThat(report.noIssues()).isTrue(); 65 | assertThat(report.noFiles()).isTrue(); 66 | 67 | report.setFilesAnalyzed(1); 68 | assertThat(report.getFilesAnalyzed()).isEqualTo(1); 69 | assertThat(report.noFiles()).isFalse(); 70 | } 71 | 72 | @Test 73 | public void should_find_added_issue() { 74 | String filePath = "comp"; 75 | String ruleKey = "rule1"; 76 | report.addIssue(createTestIssue(filePath, ruleKey, "name1", "MAJOR", 10)); 77 | report.addIssue(createTestIssue(filePath, "rule2", "name2", "MAJOR", 11)); 78 | assertThat(report.getSummary()).isNotNull(); 79 | assertThat(report.getSummary().getTotal()).isEqualTo(new IssueVariation(2, 0, 0)); 80 | 81 | assertThat(report.getResourceReportsByResource()).containsOnlyKeys(Paths.get(filePath)); 82 | assertThat(report.getRuleName(ruleKey)).isEqualTo("name1"); 83 | 84 | assertThat(report.noIssues()).isFalse(); 85 | assertThat(report.getResourceReports()).isNotEmpty(); 86 | assertThat(report.getResourcesWithReport()).isNotEmpty(); 87 | } 88 | 89 | @Test 90 | public void should_decorate_full_line_when_no_precise_location() throws Exception { 91 | Path file = temp.newFile().toPath(); 92 | FileUtils.write(file.toFile(), "if (a && b)\nif (a < b)\nif (a > b)", StandardCharsets.UTF_8); 93 | report.addIssue(createTestIssue(file.toString(), "rule1", "name1", "MAJOR", 1)); 94 | report.addIssue(createTestIssue(file.toString(), "rule2", "name2", "MAJOR", 2)); 95 | assertThat(report.getEscapedSource(file)).containsExactly("if (a && b)", "if (a < b)", 96 | "if (a > b)"); 97 | } 98 | 99 | @Test 100 | public void should_decorate_precise_location() throws Exception { 101 | Path file = temp.newFile().toPath(); 102 | FileUtils.write(file.toFile(), " foo bar ", StandardCharsets.UTF_8); 103 | Trackable issue1 = createTestIssue(file.toString(), "rule1", "name1", "MAJOR", 1); 104 | when(issue1.getIssue().getStartLineOffset()).thenReturn(1); 105 | when(issue1.getIssue().getEndLineOffset()).thenReturn(8); 106 | Trackable issue2 = createTestIssue(file.toString(), "rule2", "name2", "MAJOR", 1); 107 | when(issue2.getIssue().getStartLineOffset()).thenReturn(5); 108 | when(issue2.getIssue().getEndLineOffset()).thenReturn(8); 109 | report.addIssue(issue1); 110 | report.addIssue(issue2); 111 | assertThat(report.getEscapedSource(file)).containsExactly(" foo bar "); 112 | } 113 | 114 | @Test 115 | public void should_be_able_to_create_issue_without_file() { 116 | Trackable issueWithoutFile = createTestIssue(null, "rule1", "name1", "MAJOR", 1); 117 | report.addIssue(issueWithoutFile); 118 | assertThat(report.getSummary().getTotal().getCountInCurrentAnalysis()).isEqualTo(1); 119 | } 120 | 121 | @Test 122 | public void should_return_empty_escaped_source_for_null_path() { 123 | assertThat(report.getEscapedSource(null)).isEmpty(); 124 | } 125 | 126 | @Test 127 | public void should_return_empty_escaped_source_for_nonexistent_file() { 128 | assertThat(report.getEscapedSource(Paths.get("nonexistent"))).isEmpty(); 129 | } 130 | 131 | @Test(expected = IllegalStateException.class) 132 | public void getEscapedSource_should_throw_on_unreadable_file() throws IOException { 133 | report.getEscapedSource(temp.newFolder().toPath()); 134 | } 135 | 136 | @Test(expected = IllegalStateException.class) 137 | public void getEscapedSource_should_throw_if_file_has_no_associated_report() throws IOException { 138 | Path file = temp.newFile().toPath(); 139 | FileUtils.write(file.toFile(), "blah\nblah\n", StandardCharsets.UTF_8); 140 | report.getEscapedSource(file); 141 | } 142 | 143 | private static Trackable createTestIssue(@Nullable String filePath, String ruleKey, String name, String severity, int line) { 144 | Issue issue = mock(Issue.class); 145 | 146 | if (filePath != null) { 147 | ClientInputFile inputFile = mock(ClientInputFile.class); 148 | when(inputFile.getPath()).thenReturn(filePath); 149 | when(issue.getInputFile()).thenReturn(inputFile); 150 | } 151 | 152 | when(issue.getStartLine()).thenReturn(line); 153 | when(issue.getStartLineOffset()).thenReturn(null); 154 | when(issue.getEndLine()).thenReturn(line); 155 | when(issue.getEndLineOffset()).thenReturn(null); 156 | when(issue.getRuleName()).thenReturn(name); 157 | when(issue.getRuleKey()).thenReturn(ruleKey); 158 | when(issue.getSeverity()).thenReturn(severity); 159 | return new IssueTrackable(issue); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/report/ReportFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import org.junit.Before; 23 | import org.junit.Rule; 24 | import org.junit.Test; 25 | import org.junit.rules.TemporaryFolder; 26 | 27 | import java.nio.charset.Charset; 28 | import java.nio.file.Path; 29 | import java.nio.file.Paths; 30 | import java.util.List; 31 | 32 | import static org.assertj.core.api.Assertions.assertThat; 33 | 34 | public class ReportFactoryTest { 35 | private ReportFactory factory; 36 | 37 | @Rule 38 | public TemporaryFolder temp = new TemporaryFolder(); 39 | 40 | @Before 41 | public void setUp() { 42 | factory = new ReportFactory(Charset.defaultCharset()); 43 | } 44 | 45 | @Test 46 | public void test() { 47 | List reporters = factory.createReporters(Paths.get("test")); 48 | assertThat(reporters).hasSize(2); 49 | } 50 | 51 | @Test 52 | public void defaultReportFile() { 53 | Path report = factory.getReportFile(temp.getRoot().toPath()); 54 | assertThat(report).isEqualTo(temp.getRoot().toPath().resolve(".sonarlint").resolve("sonarlint-report.html")); 55 | } 56 | 57 | @Test 58 | public void customReportFile() { 59 | factory.setHtmlPath(Paths.get("myreport", "myfile.html").toString()); 60 | Path report = factory.getReportFile(temp.getRoot().toPath()); 61 | assertThat(report).isEqualTo(temp.getRoot().toPath().resolve("myreport").resolve("myfile.html")); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/report/ReportSummaryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.util.LinkedList; 23 | import java.util.List; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | 27 | import static org.assertj.core.api.Assertions.assertThat; 28 | import static org.assertj.core.api.Assertions.entry; 29 | import static org.sonarlint.cli.TestUtils.createTestIssue; 30 | 31 | public class ReportSummaryTest { 32 | private ReportSummary summary; 33 | 34 | @Before 35 | public void setUp() { 36 | summary = new ReportSummary(); 37 | } 38 | 39 | @Test 40 | public void test() { 41 | for (RichIssue i : createTestIssues()) { 42 | summary.addIssue(i); 43 | } 44 | 45 | assertThat(summary.getTotalByRuleKey()).contains( 46 | entry("rule1", variation(2, 0, 0)), 47 | entry("rule2", variation(2, 0, 0))); 48 | 49 | assertThat(summary.getTotalBySeverity()).contains( 50 | entry("MAJOR", variation(2, 0, 0)), 51 | entry("MINOR", variation(1, 0, 0)), 52 | entry("BLOCKER", variation(1, 0, 0))); 53 | 54 | assertThat(summary.getCategoryReports()).hasSize(3); 55 | assertVar(summary.getTotal(), 4, 0, 0); 56 | } 57 | 58 | private static IssueVariation variation(int current, int newCount, int resolved) { 59 | return new IssueVariation(current, newCount, resolved); 60 | } 61 | 62 | private static void assertVar(IssueVariation iv, int current, int newCount, int resolved) { 63 | assertThat(iv.getCountInCurrentAnalysis()).isEqualTo(current); 64 | assertThat(iv.getNewIssuesCount()).isEqualTo(newCount); 65 | assertThat(iv.getResolvedIssuesCount()).isEqualTo(resolved); 66 | } 67 | 68 | private static List createTestIssues() { 69 | List issueList = new LinkedList<>(); 70 | 71 | issueList.add(createTestIssue("comp1", "rule1", "MAJOR", 10)); 72 | issueList.add(createTestIssue("comp1", "rule2", "MINOR", 11)); 73 | issueList.add(createTestIssue("comp4", "rule1", "MAJOR", 12)); 74 | issueList.add(createTestIssue("comp2", "rule2", "BLOCKER", 13)); 75 | 76 | return issueList; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/report/ResourceReportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.report; 21 | 22 | import java.io.File; 23 | import java.nio.file.Path; 24 | import java.nio.file.Paths; 25 | import java.util.Collections; 26 | import java.util.LinkedList; 27 | import java.util.List; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | 31 | import static org.assertj.core.api.Assertions.assertThat; 32 | import static org.assertj.core.api.Assertions.entry; 33 | import static org.sonarlint.cli.TestUtils.createTestIssue; 34 | 35 | public class ResourceReportTest { 36 | private final static Path RESOURCE = Paths.get("resource"); 37 | private ResourceReport resourceReport; 38 | 39 | @Before 40 | public void setUp() { 41 | resourceReport = new ResourceReport(Paths.get(""), RESOURCE); 42 | } 43 | 44 | @Test 45 | public void testIssuesLines() { 46 | RichIssue i1 = createTestIssue("file1", "rule1", "MAJOR", 10); 47 | RichIssue i2 = createTestIssue("file1", "rule1", "MAJOR", 11); 48 | resourceReport.addIssue(i1); 49 | resourceReport.addIssue(i2); 50 | 51 | assertThat(resourceReport.getIssues()).containsOnly(i1, i2); 52 | assertThat(resourceReport.getIssuesAtLine(10)).containsExactly(i1); 53 | assertThat(resourceReport.getIssuesAtLine(20)).isEmpty(); 54 | assertThat(resourceReport.getIssuesPerLine()).containsOnly( 55 | entry(i1.getStartLine(), Collections.singletonList(i1)), 56 | entry(i2.getStartLine(), Collections.singletonList(i2))); 57 | assertThat(resourceReport.getName()).isEqualTo("resource"); 58 | assertThat(resourceReport.getPath()).isEqualTo(RESOURCE); 59 | } 60 | 61 | @Test 62 | public void testType() { 63 | assertThat(resourceReport.getType()).isEqualTo("FIL"); 64 | 65 | resourceReport = new ResourceReport(Paths.get(""), Paths.get("")); 66 | assertThat(resourceReport.getType()).isEqualTo("PRJ"); 67 | } 68 | 69 | @Test 70 | public void testName() { 71 | resourceReport = new ResourceReport(Paths.get("/tmp/test"), Paths.get("/tmp/test/src/file1")); 72 | assertThat(resourceReport.getName()).isEqualTo("src" + File.separator + "file1"); 73 | } 74 | 75 | @Test 76 | public void testCategoryReport() { 77 | RichIssue i1 = createTestIssue("file1", "rule1", "MAJOR", 10); 78 | RichIssue i2 = createTestIssue("file1", "rule1", "MINOR", 11); 79 | RichIssue i3 = createTestIssue("file1", "rule2", "MINOR", 11); 80 | RichIssue i4 = createTestIssue("file1", "rule2", "MINOR", 12); 81 | resourceReport.addIssue(i1); 82 | resourceReport.addIssue(i2); 83 | resourceReport.addIssue(i3); 84 | resourceReport.addIssue(i4); 85 | 86 | List l = new LinkedList<>(); 87 | l.add(Severity.MINOR); 88 | l.add(Severity.MAJOR); 89 | Collections.sort(l); 90 | 91 | List categoryReports = resourceReport.getCategoryReports(); 92 | assertThat(categoryReports).hasSize(3); 93 | 94 | // sort first by severity, then by rule key 95 | assertThat(categoryReports).extracting("ruleKey").containsExactly("rule1", "rule1", "rule2"); 96 | assertThat(categoryReports).extracting("severity").containsExactly(Severity.MAJOR, Severity.MINOR, Severity.MINOR); 97 | 98 | // grouping 99 | assertThat(categoryReports.get(0).getTotal().getCountInCurrentAnalysis()).isEqualTo(1); 100 | assertThat(categoryReports.get(1).getTotal().getCountInCurrentAnalysis()).isEqualTo(1); 101 | assertThat(categoryReports.get(2).getTotal().getCountInCurrentAnalysis()).isEqualTo(2); 102 | 103 | assertThat(resourceReport.getTotal().getCountInCurrentAnalysis()).isEqualTo(4); 104 | } 105 | 106 | @Test 107 | public void lineIssues() { 108 | RichIssue i1 = createTestIssue("file1", "rule1", "MAJOR", 10); 109 | RichIssue i2 = createTestIssue("file1", "rule1", "MINOR", 11); 110 | resourceReport.addIssue(i1); 111 | resourceReport.addIssue(i2); 112 | 113 | assertThat(resourceReport.isDisplayableLine(0)).isFalse(); 114 | assertThat(resourceReport.isDisplayableLine(-3)).isFalse(); 115 | assertThat(resourceReport.isDisplayableLine(null)).isFalse(); 116 | 117 | assertThat(resourceReport.isDisplayableLine(7)).isFalse(); 118 | assertThat(resourceReport.isDisplayableLine(8)).isTrue(); 119 | assertThat(resourceReport.isDisplayableLine(9)).isTrue(); 120 | assertThat(resourceReport.isDisplayableLine(10)).isTrue(); 121 | assertThat(resourceReport.isDisplayableLine(11)).isTrue(); 122 | assertThat(resourceReport.isDisplayableLine(12)).isTrue(); 123 | assertThat(resourceReport.isDisplayableLine(13)).isTrue(); 124 | assertThat(resourceReport.isDisplayableLine(14)).isFalse(); 125 | 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/util/LoggerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.mockito.Mock; 25 | import org.mockito.MockitoAnnotations; 26 | import org.sonarlint.cli.util.Logger; 27 | 28 | import java.io.PrintStream; 29 | 30 | import static org.mockito.Mockito.verifyNoMoreInteractions; 31 | import static org.mockito.Mockito.verifyZeroInteractions; 32 | import static org.mockito.Mockito.mock; 33 | import static org.mockito.Mockito.verify; 34 | 35 | public class LoggerTest { 36 | @Mock 37 | private PrintStream stdOut; 38 | 39 | @Mock 40 | private PrintStream stdErr; 41 | 42 | private Logger logger; 43 | 44 | @Before 45 | public void setUp() { 46 | MockitoAnnotations.initMocks(this); 47 | logger = new Logger(stdOut, stdErr); 48 | } 49 | 50 | @Test 51 | public void testInfo() { 52 | logger.info("info"); 53 | verify(stdOut).println("INFO: info"); 54 | verifyNoMoreInteractions(stdOut, stdErr); 55 | } 56 | 57 | @Test 58 | public void testError() { 59 | Exception e = new NullPointerException("exception"); 60 | logger.setDisplayStackTrace(false); 61 | logger.error("error1"); 62 | verify(stdErr).println("ERROR: error1"); 63 | 64 | logger.error("error2", e); 65 | verify(stdErr).println("ERROR: error2"); 66 | 67 | verifyNoMoreInteractions(stdOut, stdErr); 68 | 69 | logger.setDisplayStackTrace(true); 70 | logger.error("error3", e); 71 | verify(stdErr).println("ERROR: error3"); 72 | // other interactions to print the exception.. 73 | } 74 | 75 | @Test 76 | public void testDebugThrowableWithStack() { 77 | Throwable t = mock(Throwable.class); 78 | logger.setDebugEnabled(true); 79 | 80 | logger.setDebugEnabled(true); 81 | logger.setDisplayStackTrace(true); 82 | logger.debug("debug", t); 83 | verify(stdErr).println("DEBUG: debug"); 84 | verify(t).printStackTrace(stdErr); 85 | 86 | logger.setDebugEnabled(false); 87 | logger.debug("debug"); 88 | verifyNoMoreInteractions(stdOut, stdErr); 89 | } 90 | 91 | @Test 92 | public void testDebugThrowableWithoutStack() { 93 | Throwable t = mock(Throwable.class); 94 | logger.setDebugEnabled(true); 95 | logger.setDisplayStackTrace(false); 96 | 97 | logger.debug("debug", t); 98 | verify(stdErr).println("DEBUG: debug"); 99 | verifyZeroInteractions(t); 100 | } 101 | 102 | @Test 103 | public void testDebug() { 104 | logger.setDebugEnabled(true); 105 | 106 | logger.debug("debug"); 107 | verify(stdOut).println("DEBUG: debug"); 108 | 109 | logger.setDebugEnabled(false); 110 | logger.debug("debug"); 111 | verifyNoMoreInteractions(stdOut, stdErr); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/util/MutableIntTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.sonarlint.cli.util.MutableInt; 25 | 26 | import static org.assertj.core.api.Assertions.assertThat; 27 | 28 | public class MutableIntTest { 29 | private MutableInt integer; 30 | 31 | @Before 32 | public void setUp() { 33 | integer = new MutableInt(); 34 | } 35 | 36 | @Test 37 | public void inc() { 38 | assertThat(integer.get()).isEqualTo(0); 39 | 40 | integer.inc(); 41 | assertThat(integer.get()).isEqualTo(1); 42 | 43 | integer.inc(); 44 | assertThat(integer.get()).isEqualTo(2); 45 | } 46 | 47 | @Test 48 | public void set() { 49 | integer.set(10); 50 | assertThat(integer.get()).isEqualTo(10); 51 | } 52 | 53 | @Test 54 | public void equals() { 55 | MutableInt integer1 = new MutableInt(2); 56 | MutableInt integer2 = new MutableInt(2); 57 | MutableInt integer3 = new MutableInt(3); 58 | 59 | assertThat(integer1).isEqualTo(integer2); 60 | assertThat(integer1).isEqualTo(integer1); 61 | assertThat(integer1).isNotEqualTo(integer3); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/util/System2Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | import org.assertj.core.data.Percentage; 23 | import org.junit.Test; 24 | 25 | import java.util.Map.Entry; 26 | 27 | import static org.assertj.core.api.Assertions.assertThat; 28 | 29 | public class System2Test { 30 | @Test 31 | public void testProxy() { 32 | System.setProperty("test1", "prop1"); 33 | 34 | assertThat(System2.INSTANCE.envVariables()).isEqualTo(System.getenv()); 35 | assertThat(System2.INSTANCE.property("test1")).isEqualTo("prop1"); 36 | assertThat(System2.INSTANCE.getProperty("test1")).isEqualTo("prop1"); 37 | assertThat(System2.INSTANCE.properties()).isEqualTo(System.getProperties()); 38 | 39 | Entry envVar = System.getenv().entrySet().iterator().next(); 40 | 41 | assertThat(System2.INSTANCE.envVariable(envVar.getKey())).isEqualTo(envVar.getValue()); 42 | assertThat(System2.INSTANCE.getenv(envVar.getKey())).isEqualTo(envVar.getValue()); 43 | 44 | assertThat(System2.INSTANCE.now()).isCloseTo(System.currentTimeMillis(), Percentage.withPercentage(0.01)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/util/SystemInfoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | import static org.mockito.Mockito.mock; 27 | import static org.mockito.Mockito.verify; 28 | import static org.mockito.Mockito.verifyNoMoreInteractions; 29 | import static org.mockito.Mockito.when; 30 | 31 | public class SystemInfoTest { 32 | System2 mockSystem; 33 | Logger logger; 34 | 35 | @Before 36 | public void setUp() { 37 | mockSystem = mock(System2.class); 38 | logger = mock(Logger.class); 39 | SystemInfo.setSystem(mockSystem); 40 | } 41 | 42 | @Test 43 | public void test_java() { 44 | mockJava(); 45 | assertThat(SystemInfo.java()).isEqualTo("Java 1.9 oracle (64-bit)"); 46 | 47 | when(mockSystem.getProperty("sun.arch.data.model")).thenReturn("32"); 48 | assertThat(SystemInfo.java()).isEqualTo("Java 1.9 oracle (32-bit)"); 49 | 50 | when(mockSystem.getProperty("sun.arch.data.model")).thenReturn(null); 51 | assertThat(SystemInfo.java()).isEqualTo("Java 1.9 oracle"); 52 | } 53 | 54 | @Test 55 | public void test_os() { 56 | mockOs(); 57 | 58 | assertThat(SystemInfo.os()).isEqualTo("linux 2.5 x64"); 59 | } 60 | 61 | private void mockJava() { 62 | when(mockSystem.getProperty("java.version")).thenReturn("1.9"); 63 | when(mockSystem.getProperty("java.vendor")).thenReturn("oracle"); 64 | when(mockSystem.getProperty("sun.arch.data.model")).thenReturn("64"); 65 | } 66 | 67 | private void mockOs() { 68 | when(mockSystem.getProperty("os.version")).thenReturn("2.5"); 69 | when(mockSystem.getProperty("os.arch")).thenReturn("x64"); 70 | when(mockSystem.getProperty("os.name")).thenReturn("linux"); 71 | } 72 | 73 | @Test 74 | public void should_print() { 75 | mockOs(); 76 | mockJava(); 77 | when(mockSystem.getenv("SONARLINT_OPTS")).thenReturn("arg"); 78 | 79 | SystemInfo.print(logger); 80 | 81 | verify(mockSystem).getProperty("java.version"); 82 | verify(mockSystem).getProperty("os.version"); 83 | verify(mockSystem).getenv("SONARLINT_OPTS"); 84 | 85 | verify(logger).info("Java 1.9 oracle (64-bit)"); 86 | verify(logger).info("linux 2.5 x64"); 87 | verify(logger).info("SONARLINT_OPTS=arg"); 88 | verifyNoMoreInteractions(logger); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/org/sonarlint/cli/util/UtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarLint CLI 3 | * Copyright (C) 2016-2017 SonarSource SA 4 | * mailto:info AT sonarsource DOT com 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program; if not, write to the Free Software Foundation, 18 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | package org.sonarlint.cli.util; 21 | 22 | import static org.assertj.core.api.Assertions.assertThat; 23 | 24 | import org.junit.Test; 25 | 26 | public class UtilTest { 27 | @Test 28 | public void testEscapeFileName() { 29 | assertThat(Util.escapeFileName("myfile.html")).isEqualTo("myfile.html"); 30 | assertThat(Util.escapeFileName("myfile.h.html")).isEqualTo("myfile.h.html"); 31 | assertThat(Util.escapeFileName("invalid:name.html")).isEqualTo("invalid_name.html"); 32 | assertThat(Util.escapeFileName("name-ok.html")).isEqualTo("name-ok.html"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/resources/org/sonarlint/cli/config/sonarlint_global.json: -------------------------------------------------------------------------------- 1 | { 2 | servers: [ 3 | { 4 | "id": "local", 5 | "url": "http://localhost:9000", 6 | "login": "admin", 7 | "password": "admin" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /src/test/resources/org/sonarlint/cli/config/sonarlint_project.json: -------------------------------------------------------------------------------- 1 | { 2 | "serverId": "local", 3 | "projectKey": "myProject" 4 | } -------------------------------------------------------------------------------- /third-party-licenses.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mvn org.codehaus.mojo:license-maven-plugin:aggregate-add-third-party -Dlicense.includedScopes=compile -pl sonar-application -am 3 | 4 | cat target/generated-sources/license/THIRD-PARTY.txt 5 | -------------------------------------------------------------------------------- /travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | function installTravisTools { 6 | mkdir -p ~/.local 7 | curl -sSL https://github.com/SonarSource/travis-utils/tarball/v33 | tar zx --strip-components 1 -C ~/.local 8 | source ~/.local/bin/install 9 | } 10 | 11 | installTravisTools 12 | 13 | regular_mvn_build_deploy_analyze 14 | --------------------------------------------------------------------------------