diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2019-05-12 15:12:42 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-05-22 20:21:18 +0200 |
commit | f24fd0a266ca0dc30b99ab32defba039eb145df4 (patch) | |
tree | 0db916b74ae164994478ee41aca64ae8017f8765 /sonar-scanner-engine/src/main | |
parent | 09d6f7a1a956f9648916469be482a0fe5b5e33cb (diff) | |
download | sonarqube-f24fd0a266ca0dc30b99ab32defba039eb145df4.tar.gz sonarqube-f24fd0a266ca0dc30b99ab32defba039eb145df4.zip |
SONAR-11950 autoconfig of SCM revision on Cirrus and Bitbucket
Diffstat (limited to 'sonar-scanner-engine/src/main')
13 files changed, 495 insertions, 32 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfiguration.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfiguration.java new file mode 100644 index 00000000000..fc1d3c62677 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfiguration.java @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.ci; + +import java.util.Optional; + +/** + * Configuration provided by CI environments like TravisCI or Jenkins. + * + * @see CiVendor + */ +public interface CiConfiguration { + + /** + * The revision that triggered the analysis. It should + * be the revision as seen by end-user, but not the necessarily + * the effective revision of the clone on disk (merge commit with + * base branch for instance). + */ + Optional<String> getScmRevision(); + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationImpl.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationImpl.java new file mode 100644 index 00000000000..aabd92bc30a --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationImpl.java @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.ci; + +import java.util.Optional; +import javax.annotation.Nullable; + +import static org.apache.commons.lang.StringUtils.defaultIfBlank; + +public class CiConfigurationImpl implements CiConfiguration { + + @Nullable + private final String scmRevision; + + public CiConfigurationImpl(@Nullable String scmRevision) { + this.scmRevision = defaultIfBlank(scmRevision, null); + } + + @Override + public Optional<String> getScmRevision() { + return Optional.ofNullable(scmRevision); + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationProvider.java new file mode 100644 index 00000000000..38032976b05 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationProvider.java @@ -0,0 +1,66 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.ci; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.picocontainer.injectors.ProviderAdapter; +import org.sonar.api.config.Configuration; +import org.sonar.api.utils.MessageException; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; + +public class CiConfigurationProvider extends ProviderAdapter { + + private static final Logger LOG = Loggers.get(CiConfigurationProvider.class); + private static final String PROP_DISABLED = "sonar.ci.autoconfig.disabled"; + + public CiConfiguration provide(Configuration configuration, CiVendor[] ciVendors) { + boolean disabled = configuration.getBoolean(PROP_DISABLED).orElse(false); + if (disabled) { + return new EmptyCiConfiguration(); + } + + List<CiVendor> detectedVendors = Arrays.stream(ciVendors) + .filter(CiVendor::isDetected) + .collect(Collectors.toList()); + + if (detectedVendors.size() > 1) { + List<String> names = detectedVendors.stream().map(CiVendor::getName).collect(Collectors.toList()); + throw MessageException.of("Multiple CI environments are detected: " + names + ". Please check environment variables or set property " + PROP_DISABLED + " to true."); + } + + if (detectedVendors.size() == 1) { + CiVendor vendor = detectedVendors.get(0); + LOG.info("Detected {}", vendor.getName()); + return vendor.loadConfiguration(); + } + return new EmptyCiConfiguration(); + } + + private static class EmptyCiConfiguration implements CiConfiguration { + @Override + public Optional<String> getScmRevision() { + return Optional.empty(); + } + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiVendor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiVendor.java new file mode 100644 index 00000000000..30aefcd90a0 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiVendor.java @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.ci; + +import org.sonar.api.scanner.ScannerSide; + +@ScannerSide +public interface CiVendor { + + /** + * The display name, for example "Jenkins" + */ + String getName(); + + /** + * Whether the analyser runs in the CI vendor or not. + */ + boolean isDetected(); + + /** + * The configuration guessed by CI vendor. Called only + * if {@link #isDetected()} is true. + */ + CiConfiguration loadConfiguration(); + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/package-info.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/package-info.java new file mode 100644 index 00000000000..d7a896d0b70 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.scanner.ci; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/BitbucketPipelines.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/BitbucketPipelines.java new file mode 100644 index 00000000000..7e86de90b91 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/BitbucketPipelines.java @@ -0,0 +1,54 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.ci.vendors; + +import org.sonar.api.utils.System2; +import org.sonar.scanner.ci.CiConfiguration; +import org.sonar.scanner.ci.CiConfigurationImpl; +import org.sonar.scanner.ci.CiVendor; + +import static org.apache.commons.lang.StringUtils.isNotEmpty; + +public class BitbucketPipelines implements CiVendor { + + private final System2 system; + + public BitbucketPipelines(System2 system) { + this.system = system; + } + + @Override + public String getName() { + return "Bitbucket Pipelines"; + } + + @Override + public boolean isDetected() { + String ci = system.envVariable("CI"); + String revision = system.envVariable("BITBUCKET_COMMIT"); + return "true".equals(ci) && isNotEmpty(revision); + } + + @Override + public CiConfiguration loadConfiguration() { + String revision = system.envVariable("BITBUCKET_COMMIT"); + return new CiConfigurationImpl(revision); + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/CirrusCi.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/CirrusCi.java new file mode 100644 index 00000000000..9e2bc921b13 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/CirrusCi.java @@ -0,0 +1,62 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.ci.vendors; + +import org.sonar.api.utils.System2; +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; + +import static org.apache.commons.lang.StringUtils.isEmpty; + +/** + * Support https://cirrus-ci.org/ + * + * Environment variables are documented at https://cirrus-ci.org/guide/writing-tasks/#environment-variables + */ +public class CirrusCi implements CiVendor { + + private static final String PROPERTY_COMMIT = "CIRRUS_CHANGE_IN_REPO"; + private final System2 system; + + public CirrusCi(System2 system) { + this.system = system; + } + + @Override + public String getName() { + return "CirrusCI"; + } + + @Override + public boolean isDetected() { + return "true".equals(system.envVariable("CIRRUS_CI")); + } + + @Override + public CiConfiguration loadConfiguration() { + String revision = system.envVariable(PROPERTY_COMMIT); + if (isEmpty(revision)) { + Loggers.get(getClass()).warn("Missing environment variable " + PROPERTY_COMMIT); + } + return new CiConfigurationImpl(revision); + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/package-info.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/package-info.java new file mode 100644 index 00000000000..daae39d4d1b --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.scanner.ci.vendors; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java index dc79f7262f4..06f20e70e95 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java @@ -23,7 +23,6 @@ import java.io.File; import java.nio.file.Path; import java.util.LinkedList; import java.util.Map.Entry; -import java.util.Optional; import java.util.regex.Pattern; import javax.annotation.Nullable; import org.sonar.api.batch.fs.internal.AbstractProjectOrModule; @@ -44,6 +43,7 @@ import org.sonar.scanner.rule.QualityProfiles; import org.sonar.scanner.scan.ScanProperties; import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scm.ScmConfiguration; +import org.sonar.scanner.scm.ScmRevision; import static java.util.Optional.ofNullable; @@ -58,13 +58,14 @@ public class MetadataPublisher implements ReportPublisherStep { private final CpdSettings cpdSettings; private final ScannerPluginRepository pluginRepository; private final BranchConfiguration branchConfiguration; + private final ScmRevision scmRevision; @Nullable private final ScmConfiguration scmConfiguration; public MetadataPublisher(ProjectInfo projectInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties, QualityProfiles qProfiles, CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration, - @Nullable ScmConfiguration scmConfiguration) { + ScmRevision scmRevision, @Nullable ScmConfiguration scmConfiguration) { this.projectInfo = projectInfo; this.moduleHierarchy = moduleHierarchy; this.properties = properties; @@ -72,12 +73,13 @@ public class MetadataPublisher implements ReportPublisherStep { this.cpdSettings = cpdSettings; this.pluginRepository = pluginRepository; this.branchConfiguration = branchConfiguration; + this.scmRevision = scmRevision; this.scmConfiguration = scmConfiguration; } public MetadataPublisher(ProjectInfo projectInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties, - QualityProfiles qProfiles, CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration) { - this(projectInfo, moduleHierarchy, properties, qProfiles, cpdSettings, pluginRepository, branchConfiguration, null); + QualityProfiles qProfiles, CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration, ScmRevision scmRevision) { + this(projectInfo, moduleHierarchy, properties, qProfiles, cpdSettings, pluginRepository, branchConfiguration, scmRevision, null); } @Override @@ -100,9 +102,7 @@ public class MetadataPublisher implements ReportPublisherStep { ofNullable(rootProject.getBranch()).ifPresent(builder::setDeprecatedBranch); - if (scmConfiguration != null) { - addScmInformation(builder); - } + addScmInformation(builder); for (QProfile qp : qProfiles.findAll()) { builder.putQprofilesPerLanguage(qp.getLanguage(), ScannerReport.Metadata.QProfile.newBuilder() @@ -134,33 +134,26 @@ public class MetadataPublisher implements ReportPublisherStep { builder.putModulesProjectRelativePathByKey(module.key(), relativePath); } } - } - private void addScmInformation(ScannerReport.Metadata.Builder builder) { - ScmProvider scmProvider = scmConfiguration.provider(); - if (scmProvider != null) { - Path projectBasedir = moduleHierarchy.root().getBaseDir(); - try { - builder.setRelativePathFromScmRoot(toSonarQubePath(scmProvider.relativePathFromScmRoot(projectBasedir))); - } catch (UnsupportedOperationException e) { - LOG.debug(e.getMessage()); - } - try { - computeScmRevision().ifPresent(builder::setScmRevisionId); - } catch (UnsupportedOperationException e) { - LOG.debug(e.getMessage()); + if (scmConfiguration != null) { + ScmProvider scmProvider = scmConfiguration.provider(); + if (scmProvider != null) { + Path projectBasedir = moduleHierarchy.root().getBaseDir(); + try { + builder.setRelativePathFromScmRoot(toSonarQubePath(scmProvider.relativePathFromScmRoot(projectBasedir))); + } catch (UnsupportedOperationException e) { + LOG.debug(e.getMessage()); + } } } } - private Optional<String> computeScmRevision() { - Optional<String> scmRevision = properties.getScmRevision(); - ScmProvider scmProvider = scmConfiguration.provider(); - if (!scmRevision.isPresent() && scmProvider != null) { - scmRevision = Optional.ofNullable(scmProvider.revisionId(moduleHierarchy.root().getBaseDir())); + private void addScmInformation(ScannerReport.Metadata.Builder builder) { + try { + scmRevision.get().ifPresent(builder::setScmRevisionId); + } catch (UnsupportedOperationException e) { + LOG.debug(e.getMessage()); } - - return scmRevision; } private void addBranchInformation(ScannerReport.Metadata.Builder builder) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java index d31dfe56c1b..edb43371cd2 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java @@ -46,6 +46,9 @@ import org.sonar.scanner.bootstrap.GlobalAnalysisMode; import org.sonar.scanner.bootstrap.MetricProvider; import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary; import org.sonar.scanner.bootstrap.ProcessedScannerProperties; +import org.sonar.scanner.ci.CiConfigurationProvider; +import org.sonar.scanner.ci.vendors.BitbucketPipelines; +import org.sonar.scanner.ci.vendors.CirrusCi; import org.sonar.scanner.cpd.CpdExecutor; import org.sonar.scanner.cpd.CpdSettings; import org.sonar.scanner.cpd.index.SonarCpdBlockIndex; @@ -109,6 +112,7 @@ import org.sonar.scanner.scan.measure.DefaultMetricFinder; import org.sonar.scanner.scm.ScmChangedFilesProvider; import org.sonar.scanner.scm.ScmConfiguration; import org.sonar.scanner.scm.ScmPublisher; +import org.sonar.scanner.scm.ScmRevisionImpl; import org.sonar.scanner.sensor.DefaultSensorStorage; import org.sonar.scanner.sensor.ProjectSensorContext; import org.sonar.scanner.sensor.ProjectSensorExtensionDictionnary; @@ -248,6 +252,7 @@ public class ProjectScanContainer extends ComponentContainer { // SCM ScmConfiguration.class, ScmPublisher.class, + ScmRevisionImpl.class, // Sensors DefaultSensorStorage.class, @@ -260,6 +265,11 @@ public class ProjectScanContainer extends ComponentContainer { // Filesystem DefaultProjectFileSystem.class, + // CI + new CiConfigurationProvider(), + BitbucketPipelines.class, + CirrusCi.class, + AnalysisObservers.class); addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ScanProperties.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ScanProperties.java index 36fd9b5d41e..1033292a4b8 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ScanProperties.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ScanProperties.java @@ -79,10 +79,6 @@ public class ScanProperties { } } - public Optional<String> getScmRevision() { - return configuration.get(SCM_REVISION); - } - /** * This should be called in the beginning of the analysis to fail fast */ diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmRevision.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmRevision.java new file mode 100644 index 00000000000..28af0127b6f --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmRevision.java @@ -0,0 +1,37 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.scm; + +import java.util.Optional; +import org.sonar.api.scanner.ScannerSide; + +/** + * The SCM revision that triggered the analysis. It may be different than + * the effective revision checked-out on disk, as provided by {@link org.sonar.api.batch.scm.ScmProvider}. + * + * For instance on pull requests it's not the merge-commit that some CI services check out. It is + * the commit that was pushed by user to the branch. + */ +@ScannerSide +public interface ScmRevision { + + Optional<String> get(); + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmRevisionImpl.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmRevisionImpl.java new file mode 100644 index 00000000000..6eb15be6e81 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmRevisionImpl.java @@ -0,0 +1,77 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.scm; + +import java.util.Optional; +import org.sonar.api.batch.fs.internal.InputModuleHierarchy; +import org.sonar.api.batch.scm.ScmProvider; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.scanner.bootstrap.RawScannerProperties; +import org.sonar.scanner.ci.CiConfiguration; + +import static org.apache.commons.lang.StringUtils.isBlank; +import static org.sonar.scanner.scan.ScanProperties.SCM_REVISION; + +public class ScmRevisionImpl implements ScmRevision { + + private static final Logger LOG = Loggers.get(ScmRevisionImpl.class); + + private final CiConfiguration ciConfiguration; + private final RawScannerProperties scannerConfiguration; + private final ScmConfiguration scmConfiguration; + private final InputModuleHierarchy moduleHierarchy; + + public ScmRevisionImpl(CiConfiguration ciConfiguration, RawScannerProperties scannerConfiguration, ScmConfiguration scmConfiguration, InputModuleHierarchy moduleHierarchy) { + this.ciConfiguration = ciConfiguration; + this.scannerConfiguration = scannerConfiguration; + this.scmConfiguration = scmConfiguration; + this.moduleHierarchy = moduleHierarchy; + } + + @Override + public Optional<String> get() { + Optional<String> revision = Optional.ofNullable(scannerConfiguration.property(SCM_REVISION)); + if (isSet(revision)) { + return revision; + } + revision = ciConfiguration.getScmRevision(); + if (isSet(revision)) { + return revision; + } + ScmProvider scmProvider = scmConfiguration.provider(); + if (scmProvider != null) { + try { + revision = Optional.ofNullable(scmProvider.revisionId(moduleHierarchy.root().getBaseDir())); + } catch (UnsupportedOperationException e) { + LOG.debug(e.getMessage()); + revision = Optional.empty(); + } + } + if (isSet(revision)) { + return revision; + } + return Optional.empty(); + } + + private static boolean isSet(Optional<String> opt) { + return opt.isPresent() && !isBlank(opt.get()); + } +} |