From 98f4538d735ece602a5f1c28b2a083c72233898f Mon Sep 17 00:00:00 2001 From: Luolc Date: Wed, 5 Jul 2017 20:38:13 +0800 Subject: [PATCH] Issue #21: Report Component --- config/import-control.xml | 5 + config/pmd.xml | 6 + diff-tool/diff.groovy | 465 ++++++++++++++++++ diff-tool/projects-to-test-on.properties | 51 ++ pom.xml | 10 + .../regression/report/ReportGenerator.java | 65 +++ .../regression/report/ScriptDownloader.java | 50 ++ .../regression/report/package-info.java | 24 + .../report/ReportGeneratorTest.java | 31 ++ .../report/ScriptDownloaderTest.java | 36 ++ 10 files changed, 743 insertions(+) create mode 100644 diff-tool/diff.groovy create mode 100644 diff-tool/projects-to-test-on.properties create mode 100644 src/main/java/com/github/checkstyle/regression/report/ReportGenerator.java create mode 100644 src/main/java/com/github/checkstyle/regression/report/ScriptDownloader.java create mode 100644 src/main/java/com/github/checkstyle/regression/report/package-info.java create mode 100644 src/test/java/com/github/checkstyle/regression/report/ReportGeneratorTest.java create mode 100644 src/test/java/com/github/checkstyle/regression/report/ScriptDownloaderTest.java diff --git a/config/import-control.xml b/config/import-control.xml index 75a8bc0..878cfbf 100644 --- a/config/import-control.xml +++ b/config/import-control.xml @@ -29,4 +29,9 @@ + + + + + diff --git a/config/pmd.xml b/config/pmd.xml index 9e240b4..44d6d4b 100644 --- a/config/pmd.xml +++ b/config/pmd.xml @@ -64,6 +64,12 @@ + + + + + + diff --git a/diff-tool/diff.groovy b/diff-tool/diff.groovy new file mode 100644 index 0000000..6eaf29c --- /dev/null +++ b/diff-tool/diff.groovy @@ -0,0 +1,465 @@ +import java.nio.file.Paths + +import static java.lang.System.err + +static void main(String[] args) { + def cliOptions = getCliOptions(args) + if (areValidCliOptions(cliOptions)) { + def cfg = new Config(cliOptions) + + if (hasUnstagedChanges(cfg.localGitRepo)) { + def exMsg = "Error: git repository ${cfg.localGitRepo.path} has unstaged changes!" + throw new IllegalStateException(exMsg) + } + + // Delete work directories to avoid conflicts with previous reports generation + if (new File(cfg.reportsDir).exists()) { + deleteDir(cfg.reportsDir) + } + if (new File(cfg.tmpReportsDir).exists()) { + deleteDir(cfg.tmpReportsDir) + } + + def checkstyleBaseReportInfo = null + if (cfg.isDiffMode()) { + checkstyleBaseReportInfo = generateCheckstyleReport(cfg.getCheckstyleToolBaseConfig()) + } + + def checkstylePatchReportInfo = generateCheckstyleReport(cfg.getCheckstyleToolPatchConfig()) + deleteDir(cfg.reportsDir) + moveDir(cfg.tmpReportsDir, cfg.reportsDir) + + generateDiffReport(cfg.getDiffToolConfig()) + generateSummaryIndexHtml(cfg.diffDir, checkstyleBaseReportInfo, checkstylePatchReportInfo) + } + else { + throw new IllegalArgumentException('Error: invalid command line arguments!') + } +} + +def getCliOptions(args) { + def cliOptionsDescLineLength = 120 + def cli = new CliBuilder(usage:'groovy diff.groovy [options]', header: 'options:', width: cliOptionsDescLineLength) + cli.with { + r(longOpt: 'localGitRepo', args: 1, required: true, argName: 'path', + 'Path to local git repository (required)') + b(longOpt: 'baseBranch', args: 1, required: false, argName: 'branch_name', + 'Base branch name. Default is master (optional, default is master)') + p(longOpt: 'patchBranch', args: 1, required: true, argName: 'branch_name', + 'Name of the patch branch in local git repository (required)') + bc(longOpt: 'baseConfig', args: 1, required: false, argName: 'path', 'Path to the base ' \ + + 'checkstyle config file (optional, if absent then the tool will use only ' \ + + 'patchBranch in case the tool mode is \'single\', otherwise baseBranch ' \ + + 'will be set to \'master\')') + pc(longOpt: 'patchConfig', args: 1, required: false, argName: 'path', + 'Path to the patch checkstyle config file (required if baseConfig is specified)') + c(longOpt: 'config', args: 1, required: false, argName: 'path', 'Path to the checkstyle ' \ + + 'config file (required if baseConfig and patchConfig are not secified)') + l(longOpt: 'listOfProjects', args: 1, required: true, argName: 'path', + 'Path to file which contains projects to test on (required)') + s(longOpt: 'shortFilePaths', required: false, 'Whether to save report file paths' \ + + ' as a shorter version to prevent long paths. (optional, default is false)') + m(longOpt: 'mode', args: 1, required: false, argName: 'mode', 'The mode of the tool:' \ + + ' \'diff\' or \'single\'. (optional, default is \'diff\')') + } + return cli.parse(args) +} + +def areValidCliOptions(cliOptions) { + def valid = true + def baseConfig = cliOptions.baseConfig + def patchConfig = cliOptions.patchConfig + def config = cliOptions.config + def toolMode = cliOptions.mode + def localGitRepo = new File(cliOptions.localGitRepo) + def patchBranch = cliOptions.patchBranch + def baseBranch = cliOptions.baseBranch + + if (toolMode && !('diff'.equals(toolMode) || 'single'.equals(toolMode))) { + err.println "Error: Invalid mode: \'$toolMode\'. The mode should be \'single\' or \'diff\'!" + valid = false + } + else if (!isValidCheckstyleConfigsCombination(config, baseConfig, patchConfig, toolMode)) { + valid = false + } + else if (!isValidGitRepo(localGitRepo)) { + err.println "Error: $localGitRepo is not a valid git repository!" + valid = false + } + else if (!isExistingGitBranch(localGitRepo, patchBranch)) { + err.println "Error: $patchBranch is not an exiting git branch!" + valid = false + } + else if (baseBranch && !isExistingGitBranch(localGitRepo, baseBranch)) { + err.println "Error: $baseBranch is not an existing git branch!" + valid = false + } + + return valid +} + +def isValidCheckstyleConfigsCombination(config, baseConfig, patchConfig, toolMode) { + def valid = true + if (config && (patchConfig || baseConfig)) { + err.println "Error: you should specify either \'config\'," \ + + " or \'baseConfig\' and \'patchConfig\', or \'patchConfig\' only!" + valid = false + } + else if ('diff'.equals(toolMode) && baseConfig && !patchConfig) { + err.println "Error: \'patchConfig\' should be specified!" + valid = false + } + else if ('diff'.equals(toolMode) && patchConfig && !baseConfig) { + err.println "Error: \'baseConfig\' should be specified!" + valid = false + } + else if ('single'.equals(toolMode) && (baseConfig || config)) { + err.println "Error: \'baseConfig\' and/or \'config\' should not be used in \'single\' mode!" + valid = false + } + return valid +} + +def isValidGitRepo(gitRepoDir) { + def valid = true + if (gitRepoDir.exists() && gitRepoDir.isDirectory()) { + def gitStatusCmd = "git status".execute(null, gitRepoDir) + gitStatusCmd.waitFor() + if (gitStatusCmd.exitValue() != 0) { + err.println "Error: \'${gitRepoDir.getPath()}\' is not a git repository!" + valid = false + } + } + else { + err.println "Error: \'${gitRepoDir.getPath()}\' does not exist or it is not a directory!" + valid = false + } + return valid +} + +def isExistingGitBranch(gitRepo, branchName) { + def exist = true + def gitRevParseCmd = "git rev-parse --verify $branchName".execute(null, gitRepo) + gitRevParseCmd.waitFor() + if (gitRevParseCmd.exitValue() != 0) { + err.println "Error: git repository ${gitRepo.getPath()} does not have a branch with name \'$branchName\'!" + exist = false + } + return exist +} + +def hasUnstagedChanges(gitRepo) { + def hasUnstagedChanges = true + def gitStatusCmd = "git status".execute(null, gitRepo) + gitStatusCmd.waitFor() + def gitStatusOutput = gitStatusCmd.text + if (gitStatusOutput.contains("nothing to commit")) { + hasUnstagedChanges = false + } + return hasUnstagedChanges +} + +def getCheckstyleVersionFromPomXml(pathToPomXml, xmlTagName) { + def pomXmlFile = new File(pathToPomXml) + def checkstyleVersion + pomXmlFile.eachLine { + line -> + if (line.matches("^.*<$xmlTagName>.*-SNAPSHOT.*")) { + checkstyleVersion = line.substring(line.indexOf('>') + 1, line.lastIndexOf('<')) + return true + } + } + if (checkstyleVersion == null) { + throw new GroovyRuntimeException("Error: cannot get Checkstyle version from $pathToPomXml!") + } + return checkstyleVersion +} + +def generateCheckstyleReport(cfg) { + println "Installing Checkstyle artifact ($cfg.branch) into local Maven repository ..." + executeCmd("git checkout $cfg.branch", cfg.localGitRepo) + executeCmd("git log -1 --pretty=MSG:%s%nSHA-1:%H", cfg.localGitRepo) + + def testerCheckstyleVersion = getCheckstyleVersionFromPomXml('./pom.xml', 'checkstyle.version') + def checkstyleVersionInLocalRepo = getCheckstyleVersionFromPomXml("$cfg.localGitRepo/pom.xml", 'version') + if (testerCheckstyleVersion != checkstyleVersionInLocalRepo) { + throw new GroovyRuntimeException("Error: config version mis-match!\nCheckstyle version in tester's pom.xml is $testerCheckstyleVersion\nCheckstyle version in local repo is $checkstyleVersionInLocalRepo") + } + + executeCmd("mvn -Pno-validations clean install", cfg.localGitRepo) + executeCmd("groovy launch.groovy --listOfProjects $cfg.listOfProjects --config $cfg.checkstyleCfg --ignoreExceptions --ignoreExcludes") + println "Moving Checkstyle report into $cfg.destDir ..." + moveDir("reports", cfg.destDir) + + return new CheckstyleReportInfo( + cfg.branch, + getLastCommitSha(cfg.localGitRepo, cfg.branch), + getLastCommitMsg(cfg.localGitRepo, cfg.branch) + ) +} + +def getLastCommitSha(gitRepo, branch) { + executeCmd("git checkout $branch", gitRepo) + return 'git rev-parse HEAD'.execute(null, gitRepo).text.trim() +} + +def getLastCommitMsg(gitRepo, branch) { + executeCmd("git checkout $branch", gitRepo) + return 'git log -1 --pretty=%B'.execute(null, gitRepo).text.trim() +} + +def generateDiffReport(cfg) { + def diffToolDir = Paths.get("").toAbsolutePath() + .getParent() + .resolve("patch-diff-report-tool") + .toFile() + executeCmd("mvn clean package -DskipTests", diffToolDir) + def diffToolJarPath = getPathToDiffToolJar(diffToolDir) + + println 'Starting diff report generation ...' + Paths.get(cfg.patchReportsDir).toFile().eachFile { + fileObj -> + if (fileObj.isDirectory()) { + def projectName = fileObj.getName() + def patchReportDir = new File("$cfg.patchReportsDir/$projectName") + if (patchReportDir.exists()) { + def patchReport = "$cfg.patchReportsDir/$projectName/checkstyle-result.xml" + def outputDir = "$cfg.reportsDir/diff/$projectName" + def diffCmd = "java -jar $diffToolJarPath --patchReport $patchReport " \ + + "--output $outputDir --patchConfig $cfg.patchConfig" + if ('diff'.equals(cfg.mode)) { + def baseReport = "$cfg.masterReportsDir/$projectName/checkstyle-result.xml" + diffCmd += " --baseReport $baseReport --baseConfig $cfg.baseConfig" + } + if (cfg.shortFilePaths) { + diffCmd += ' --shortFilePaths' + } + executeCmd(diffCmd) + } else { + def exMsg = "Error: patch report for project $projectName is not found!" + throw new FileNotFoundException(exMsg) + } + } + } + println 'Diff report generation finished ...' +} + +def getPathToDiffToolJar(diffToolDir) { + def targetDir = diffToolDir.getAbsolutePath() + '/target/' + def pathToDiffToolJar + Paths.get(targetDir).toFile().eachFile { + fileObj -> + def jarPattern = "patch-diff-report-tool-.*.jar-with-dependencies.jar" + def fileName = fileObj.getName() + if (fileName.matches(jarPattern)) { + pathToDiffToolJar = fileObj.getAbsolutePath() + return true + } + } + if (pathToDiffToolJar == null) { + throw new FileNotFoundException("Error: difff tool jar file is not found!") + } + return pathToDiffToolJar +} + +def generateSummaryIndexHtml(diffDir, checkstyleBaseReportInfo, checkstylePatchReportInfo) { + println 'Starting creating report summary page ...' + def projectsStatistic = getProjectsStatistic(diffDir) + def summaryIndexHtml = new File("$diffDir/index.html") + + summaryIndexHtml << ('') + summaryIndexHtml << ('\n') + summaryIndexHtml << ('

') + summaryIndexHtml << ('WARNING: Excludes are ignored by diff.groovy.') + summaryIndexHtml << ('

') + printReportInfoSection(summaryIndexHtml, checkstyleBaseReportInfo, checkstylePatchReportInfo) + projectsStatistic.each { + project, diffCount -> + summaryIndexHtml << ("$project") + if (diffCount.compareTo(0) != 0) { + summaryIndexHtml << (" ($diffCount)") + } + summaryIndexHtml << ('
') + summaryIndexHtml << ('\n') + } + summaryIndexHtml << ('') + + println 'Creating report summary page finished...' +} + +def printReportInfoSection(summaryIndexHtml, checkstyleBaseReportInfo, checkstylePatchReportInfo) { + summaryIndexHtml << ('
') + if (checkstyleBaseReportInfo) { + summaryIndexHtml << "Base branch: $checkstyleBaseReportInfo.branch" + summaryIndexHtml << ('
') + summaryIndexHtml << "Base branch last commit SHA: $checkstyleBaseReportInfo.commitSha" + summaryIndexHtml << ('
') + summaryIndexHtml << "Base branch last commit message: \"$checkstyleBaseReportInfo.commitMsg\"" + summaryIndexHtml << ('
') + summaryIndexHtml << ('
') + } + summaryIndexHtml << "Patch branch: $checkstylePatchReportInfo.branch" + summaryIndexHtml << ('
') + summaryIndexHtml << "Patch branch last commit SHA: $checkstylePatchReportInfo.commitSha" + summaryIndexHtml << ('
') + summaryIndexHtml << "Patch branch last commit message: \"$checkstylePatchReportInfo.commitMsg\"" + summaryIndexHtml << ('
') +} + +def getProjectsStatistic(diffDir) { + def projectsStatistic = new HashMap<>() + Paths.get(diffDir).toFile().eachFile { + fileObjf -> + if (fileObjf.isDirectory()) { + def projectName = fileObjf.getName() + def indexHtmlFile = new File(fileObjf.getAbsolutePath() + '/index.html') + indexHtmlFile.eachLine { + line -> + if (line.matches(".*totalDiff\">[0-9]+.*")) { + def totalDiff = Integer.valueOf(line.substring(line.indexOf('>') + 1, line.lastIndexOf('<'))) + projectsStatistic.put(projectName, totalDiff) + } + } + } + } + return projectsStatistic +} + +def moveDir(source, destination) { + new AntBuilder().move(todir: destination) { + fileset(dir: source) + } +} + +def deleteDir(dir) { + new AntBuilder().delete(dir: dir, failonerror: false) +} + +def executeCmd(cmd, dir = new File("").getAbsoluteFile()) { + def osSpecificCmd = getOsSpecificCmd(cmd) + def proc = osSpecificCmd.execute(null, dir) + proc.consumeProcessOutput(System.out, System.err) + proc.waitFor() + if (proc.exitValue() != 0) { + throw new GroovyRuntimeException("Error: ${proc.err.text}!") + } +} + +def getOsSpecificCmd(cmd) { + def osSpecificCmd + if (System.properties['os.name'].toLowerCase().contains('windows')) { + osSpecificCmd = "cmd /c $cmd" + } + else { + osSpecificCmd = cmd + } +} + +class Config { + def localGitRepo + def shortFilePaths + def listOfProjects + def mode + + def baseBranch + def patchBranch + + def baseConfig + def patchConfig + def config + + def reportsDir + def masterReportsDir + def patchReportsDir + def tmpReportsDir + def tmpMasterReportsDir + def tmpPatchReportsDir + def diffDir + + Config(cliOptions) { + localGitRepo = new File(cliOptions.localGitRepo) + shortFilePaths = cliOptions.shortFilePaths + listOfProjects = cliOptions.listOfProjects + + mode = cliOptions.mode + if (!mode) { + mode = 'diff' + } + + baseBranch = cliOptions.baseBranch + if (!baseBranch) { + baseBranch = 'master' + } + patchBranch = cliOptions.patchBranch + + baseConfig = cliOptions.baseConfig + patchConfig = cliOptions.patchConfig + config = cliOptions.config + if (config) { + baseConfig = config + patchConfig = config + } + + reportsDir = 'reports' + masterReportsDir = "$reportsDir/$baseBranch" + patchReportsDir = "$reportsDir/$patchBranch" + + tmpReportsDir = 'tmp_reports' + tmpMasterReportsDir = "$tmpReportsDir/$baseBranch" + tmpPatchReportsDir = "$tmpReportsDir/$patchBranch" + + diffDir = "$reportsDir/diff" + } + + def isDiffMode() { + return 'diff'.equals(mode) + } + + def isSingleMode() { + return 'single'.equals(mode) + } + + def getCheckstyleToolBaseConfig() { + return [ + localGitRepo: localGitRepo, + branch: baseBranch, + checkstyleCfg: baseConfig, + listOfProjects: listOfProjects, + destDir: tmpMasterReportsDir + ] + } + + def getCheckstyleToolPatchConfig() { + return [ + localGitRepo: localGitRepo, + branch: patchBranch, + checkstyleCfg: patchConfig, + listOfProjects: listOfProjects, + destDir: tmpPatchReportsDir + ] + } + + def getDiffToolConfig() { + return [ + reportsDir: reportsDir, + masterReportsDir: masterReportsDir, + patchReportsDir: patchReportsDir, + baseConfig: baseConfig, + patchConfig: patchConfig, + shortFilePaths: shortFilePaths, + mode: mode + ] + } +} + +class CheckstyleReportInfo { + def branch + def commitSha + def commitMsg + + CheckstyleReportInfo(branch, commitSha, commitMsg) { + this.branch = branch + this.commitSha = commitSha + this.commitMsg = commitMsg + } +} diff --git a/diff-tool/projects-to-test-on.properties b/diff-tool/projects-to-test-on.properties new file mode 100644 index 0000000..b5d011d --- /dev/null +++ b/diff-tool/projects-to-test-on.properties @@ -0,0 +1,51 @@ +# List of GIT repositories to clone / pull for checking with Checkstyle +# File format: REPO_NAME|[github|git|hg]|REPO_GIT_URL|[COMMIT_ID]|[EXCLUDE FOLDERS] +# Please note that bash comments works in this file + +# Few projects that delivers set of unusual Java constructions that shall be correctly handled by AST visitor +# 'InputAllEscapedUnicodeCharacters' must be skipped because it is too big and slows down JXR +checkstyle|git|https://github.com/checkstyle/checkstyle.git|master|**/checkstyle/src/test/resources-noncompilable/**/*,**/InputAllEscapedUnicodeCharacters.java +sevntu-checkstyle|git|https://github.com/sevntu-checkstyle/sevntu.checkstyle|master|| + +openjdk7|hg|http://hg.openjdk.java.net/jdk7/jdk7/jdk/||| +openjdk8|hg|http://hg.openjdk.java.net/jdk8/jdk8/jdk/|default|**/test/tools/pack200/typeannos/TypeUseTarget.java +#All details at checkstyle/checkstyle#3033: TypeUseTarget till checkstyle/checkstyle#3238 ; ModalDialogActivationTest till JDK-8166015 ; 'jxc/8073519/**' not compilable by design ; ', jhsdb/**' - checkstyle do not support unicode identifiers +openjdk9|hg|http://hg.openjdk.java.net/jdk9/jdk9/jdk/|default|**/test/tools/pack200/typeannos/TypeUseTarget.java,**/test/java/awt/Focus/ModalDialogActivationTest/ModalDialogActivationTest.java,**/test/javax/xml/bind/jxc/8073519/**,**/test/sun/tools/jhsdb/** +guava|git|https://github.com/google/guava|v18.0|| + +findbugs|git|https://github.com/findbugsproject/findbugs|3.0.1|| +pmd|git|https://github.com/pmd/pmd|pmd_releases/5.3.0|**/pmd/pmd-java/src/test/**/* +lombok-ast|git|https://github.com/rzwitserloot/lombok.ast|v0.2|**/lombok-ast/test/**/* + +spring-framework|git|https://github.com/spring-projects/spring-framework|v4.1.6.RELEASE|| +hibernate-orm|git|https://github.com/hibernate/hibernate-orm|4.2.19.Final|**/hibernate-orm/documentation/**/* +elasticsearch|git|https://github.com/elastic/elasticsearch|v1.5.2|| +java-design-patterns|git|https://github.com/iluwatar/java-design-patterns|dd855a376bc025aa61f6816584f79eb9854fe5d7|| +MaterialDesignLibrary|git|https://github.com/navasmdc/MaterialDesignLibrary|1.3|| +Hbase|git|https://github.com/apache/hbase|1.1.0.1|| +Orekit|git|https://github.com/CS-SI/Orekit|942785a5c79b5470baec3d41cab18f3adc78280e|| + +# Those projects are quite old and have lot of legacy code +apache-ant|git|https://github.com/apache/ant|ANT_194|**/apache-ant/src/tests/**/*,**/apache-ant/src/etc/testcases/ +apache-jsecurity|git|https://github.com/apache/jsecurity|c2ac5b90a467aedb04b52ae50a99e83207d847b3|| +android-launcher|git|https://github.com/android/platform_packages_apps_launcher|android-2.1_r2.1p2|| +apache-struts|git|https://github.com/apache/struts.git|master|**/apache-struts/**/resources/**/* + +# Projects which contain a lot of labmda expressions +infinispan|git|https://github.com/infinispan/infinispan|7.2.5.Final|| +protonpack|git|https://github.com/poetix/protonpack|protonpack-1.7|| +jOOL|git|https://github.com/jOOQ/jOOL|version-0.9.7|| +RxJava|git|https://github.com/ReactiveX/RxJava|v1.0.9|| + +# Few projects with excludes to decrease a number of checked files (usefull for some checks which specify overly strong code style policy) +checkstyle-with-excludes|git|https://github.com/checkstyle/checkstyle.git|master|**/checkstyle-with-excludes/src/test/**/*,**/checkstyle-with-excludes/src/it/resources/**/*,**/resources-noncompilable/**/* +sevntu-checkstyle-with-excludes|git|https://github.com/sevntu-checkstyle/sevntu.checkstyle|master|**/sevntu-checkstyle-with-excludes/sevntu-checks/src/test/**/* +findbugs-with-excldues|git|https://github.com/findbugsproject/findbugs|3.0.1|**/findbugs-with-excldues/eclipsePlugin-test/**/*,**/findbugs-with-excldues/findbugsTestCases/**/*,**/findbugs-with-excldues/JSR305-testCases/**/*,**/findbugs-with-excldues/findbugsTestCasesOS/**/* +hibernate-orm-with-excludes|git|https://github.com/hibernate/hibernate-orm|4.2.19.Final|**/hibernate-orm-with-excludes/documentation/**/*,**/hibernate-orm-with-excludes/**/src/test/**/* + +# Guava with excldues to generate reports only for those files which are not excluded in Guava's pom.xml for checkstyle-maven-plugin +# See https://github.com/checkstyle/checkstyle/wiki/How-to-generate-Checkstyle-report-for-Google-Guava-project +guava-mvnstyle|git|https://github.com/google/guava|master|**/guava-mvnstyle/**/test/**/*,**/guava-mvnstyle/guava-gwt/src-super/**/*,**/guava-mvnstyle/guava-gwt/test-super/**/*,**/guava-mvnstyle/guava-tests/**/* + +# custom javadoc tags +nbia-dcm4che-tools|git|https://github.com/thprakash/nbia-dcm4che-tools|c3591e6f0f84827586db25abded6708e5386ef1a|| diff --git a/pom.xml b/pom.xml index 809ead1..064928d 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,11 @@
+ + org.codehaus.groovy + groovy-all + 2.4.12 + org.apache.maven maven-jxr @@ -295,6 +300,11 @@ 28 52 + + com.github.checkstyle.regression.report.ReportGenerator + 0 + 0 + diff --git a/src/main/java/com/github/checkstyle/regression/report/ReportGenerator.java b/src/main/java/com/github/checkstyle/regression/report/ReportGenerator.java new file mode 100644 index 0000000..818b148 --- /dev/null +++ b/src/main/java/com/github/checkstyle/regression/report/ReportGenerator.java @@ -0,0 +1,65 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.checkstyle.regression.report; + +import java.io.File; +import java.io.IOException; + +/** + * Generates the regression diff report. + * @author LuoLiangchen + */ +public final class ReportGenerator { + /** Prevents instantiation. */ + private ReportGenerator() { + } + + /** + * Generates the regression diff report. + * @param testerPath the path to the directory which holds 'diff.groovy' + * @param repoPath the path to the checkstyle repository + * @param branch the name of the PR branch + * @param configPath the path to the generated config file + * @return the directory of the generated reports + * @throws InterruptedException failure of running CLI + * @throws IOException failure of running CLI + */ + public static File generate( + String testerPath, String repoPath, String branch, String configPath) + throws InterruptedException, IOException { + final ProcessBuilder builder = new ProcessBuilder() + .directory(new File(testerPath)) + .command( + "groovy", "diff.groovy", + "-r", repoPath, + "-b", "master", + "-p", branch, + "-c", configPath, + "-l", "projects-to-test-on.properties" + ) + .inheritIO(); + final Process process = builder.start(); + final int code = process.waitFor(); + if (code != 0) { + throw new IllegalStateException("an error occurs when running diff.groovy"); + } + return new File(testerPath, "reports/diff"); + } +} diff --git a/src/main/java/com/github/checkstyle/regression/report/ScriptDownloader.java b/src/main/java/com/github/checkstyle/regression/report/ScriptDownloader.java new file mode 100644 index 0000000..a03af73 --- /dev/null +++ b/src/main/java/com/github/checkstyle/regression/report/ScriptDownloader.java @@ -0,0 +1,50 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.checkstyle.regression.report; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import org.apache.commons.io.FileUtils; + +/** + * Downloads the 'diff.groovy' script from contribution repository. + * @author LuoLiangchen + */ +public final class ScriptDownloader { + /** Prevents instantiation. */ + private ScriptDownloader() { + } + + /** + * Downloads the 'diff.groovy' script from contribution repository and save it to + * the given destination. The file at {@code dest} will be overwritten if it already exists. + * @param dest the path of the script to save + * @throws IOException failure of downloading or saving + */ + public static void downloadGroovyScript(String dest) throws IOException { + final String url = "https://raw.githubusercontent.com/checkstyle/" + + "contribution/master/checkstyle-tester/diff.groovy"; + final InputStream response = new URL(url).openStream(); + FileUtils.copyInputStreamToFile(response, new File(dest)); + } +} diff --git a/src/main/java/com/github/checkstyle/regression/report/package-info.java b/src/main/java/com/github/checkstyle/regression/report/package-info.java new file mode 100644 index 0000000..9e67aaa --- /dev/null +++ b/src/main/java/com/github/checkstyle/regression/report/package-info.java @@ -0,0 +1,24 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +/** + * Contains the regression test runner and the report deployer. + * @author LuoLiangchen + */ +package com.github.checkstyle.regression.report; diff --git a/src/test/java/com/github/checkstyle/regression/report/ReportGeneratorTest.java b/src/test/java/com/github/checkstyle/regression/report/ReportGeneratorTest.java new file mode 100644 index 0000000..8735855 --- /dev/null +++ b/src/test/java/com/github/checkstyle/regression/report/ReportGeneratorTest.java @@ -0,0 +1,31 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.checkstyle.regression.report; + +import static com.github.checkstyle.regression.internal.TestUtils.assertUtilsClassHasPrivateConstructor; + +import org.junit.Test; + +public class ReportGeneratorTest { + @Test + public void testIsProperUtilsClass() throws Exception { + assertUtilsClassHasPrivateConstructor(ReportGenerator.class); + } +} diff --git a/src/test/java/com/github/checkstyle/regression/report/ScriptDownloaderTest.java b/src/test/java/com/github/checkstyle/regression/report/ScriptDownloaderTest.java new file mode 100644 index 0000000..498013c --- /dev/null +++ b/src/test/java/com/github/checkstyle/regression/report/ScriptDownloaderTest.java @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.checkstyle.regression.report; + +import static com.github.checkstyle.regression.internal.TestUtils.assertUtilsClassHasPrivateConstructor; + +import org.junit.Test; + +public class ScriptDownloaderTest { + @Test + public void testIsProperUtilsClass() throws Exception { + assertUtilsClassHasPrivateConstructor(ScriptDownloader.class); + } + + @Test + public void testDownloadGroovyScriptNoFailure() throws Exception { + ScriptDownloader.downloadGroovyScript("diff-tool/diff.groovy"); + } +}