From 1290e77dd6f5759354122cecd966074127351e15 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Tue, 3 Mar 2020 16:54:40 -0600 Subject: [PATCH] SONAR-11853 SONAR-13161 Auto-configuration pull requests and branches on Jenkins --- build.gradle | 1 + sonar-scanner-engine/build.gradle | 1 + .../org/sonar/scanner/ci/vendors/Jenkins.java | 60 ++++++++++++++++-- .../org/sonar/scanner/ci/vendors/gitrepo.zip | Bin 0 -> 17779 bytes .../sonar/scanner/ci/vendors/JenkinsTest.java | 44 +++++++++++-- 5 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 sonar-scanner-engine/src/main/resources/org/sonar/scanner/ci/vendors/gitrepo.zip diff --git a/build.gradle b/build.gradle index 4f8846cf20a..e9349ec8367 100644 --- a/build.gradle +++ b/build.gradle @@ -269,6 +269,7 @@ subprojects { } dependency 'org.elasticsearch:mocksocket:1.0' dependency 'org.codelibs.elasticsearch.module:analysis-common:6.8.4' + dependency 'org.eclipse.jgit:org.eclipse.jgit:5.6.1.202002131546-r' dependency 'org.freemarker:freemarker:2.3.20' dependency 'org.hamcrest:hamcrest-all:1.3' dependency 'org.jsoup:jsoup:1.12.1' diff --git a/sonar-scanner-engine/build.gradle b/sonar-scanner-engine/build.gradle index 4672dbe8b40..ac3497147dc 100644 --- a/sonar-scanner-engine/build.gradle +++ b/sonar-scanner-engine/build.gradle @@ -29,6 +29,7 @@ dependencies { compile 'org.codehaus.staxmate:staxmate' compile 'org.codehaus.woodstox:stax2-api' compile 'org.codehaus.woodstox:woodstox-core-lgpl' + compile 'org.eclipse.jgit:org.eclipse.jgit' compile 'org.picocontainer:picocontainer' compile 'org.slf4j:jcl-over-slf4j' compile 'org.slf4j:jul-to-slf4j' diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Jenkins.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Jenkins.java index 64d98ec4748..d79cbd7c17c 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Jenkins.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Jenkins.java @@ -19,8 +19,15 @@ */ package org.sonar.scanner.ci.vendors; +import java.nio.file.Path; import org.apache.commons.lang.StringUtils; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryBuilder; +import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.utils.System2; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; import org.sonar.scanner.ci.CiConfiguration; import org.sonar.scanner.ci.CiConfigurationImpl; import org.sonar.scanner.ci.CiVendor; @@ -28,10 +35,13 @@ import org.sonar.scanner.ci.CiVendor; import static org.apache.commons.lang.StringUtils.isNotBlank; public class Jenkins implements CiVendor { + private final static Logger log = Loggers.get(Jenkins.class); private final System2 system; + private final DefaultInputProject inputProject; - public Jenkins(System2 system) { + public Jenkins(System2 system, DefaultInputProject inputProject) { this.system = system; + this.inputProject = inputProject; } @Override @@ -51,12 +61,52 @@ public class Jenkins implements CiVendor { // https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-EnvironmentVariables // https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project String revision = system.envVariable("ghprbActualCommit"); - if (StringUtils.isBlank(revision)) { - revision = system.envVariable("GIT_COMMIT"); - if (StringUtils.isBlank(revision)) { - revision = system.envVariable("SVN_COMMIT"); + if (StringUtils.isNotBlank(revision)) { + return new CiConfigurationImpl(revision); + } + + revision = system.envVariable("GIT_COMMIT"); + + if (StringUtils.isNotBlank(revision)) { + if (StringUtils.isNotBlank(system.envVariable("CHANGE_ID"))) { + String jenkinsGitPrSha1 = getJenkinsGitPrSha1(); + if (StringUtils.isNotBlank(jenkinsGitPrSha1)) { + return new CiConfigurationImpl(jenkinsGitPrSha1); + } } + return new CiConfigurationImpl(revision); } + + revision = system.envVariable("SVN_COMMIT"); return new CiConfigurationImpl(revision); } + + private String getJenkinsGitPrSha1() { + String gitBranch = system.envVariable("GIT_BRANCH"); + if (StringUtils.isBlank(gitBranch)) { + return null; + } + + Path baseDir = inputProject.getBaseDir(); + + RepositoryBuilder builder = new RepositoryBuilder() + .findGitDir(baseDir.toFile()) + .setMustExist(true); + + if (builder.getGitDir() == null) { + return null; + } + + String refName = "refs/remotes/origin/" + gitBranch; + try (Repository repo = builder.build()) { + Ref ref = repo.exactRef(refName); + if (ref != null) { + return ref.getObjectId().getName(); + } + } catch (Exception e) { + log.debug("Couldn't find git sha1 in '{}': {}", refName, e.getMessage()); + } + return null; + } + } diff --git a/sonar-scanner-engine/src/main/resources/org/sonar/scanner/ci/vendors/gitrepo.zip b/sonar-scanner-engine/src/main/resources/org/sonar/scanner/ci/vendors/gitrepo.zip new file mode 100644 index 0000000000000000000000000000000000000000..847bba8bcd06254ac8d9c51d8f3222df0d277eb1 GIT binary patch literal 17779 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