From 04f7bd9982ab7f2e5f2312421a41335924f3aede Mon Sep 17 00:00:00 2001 From: Michael Clarke Date: Wed, 29 Dec 2021 22:19:52 +0000 Subject: [PATCH] #523: Add auto-detection for all CIs in Sonarqube commercial editions The plugin previously only provided support for auto-detecting and configuring the scanner properties for a Pull Request in Azure Devops and a Merge Request or Branch in Gitlab CI. The Sonarqube documentation also stated that Bitbucket Pipelines, Github Actions, CodeMagic, Jenkins Branch API, and Cirrus CI could also be used to auto-discover Pull Request or Branch information although the plugin did not provide these. This change adds support for detecting these additional CIs based on the various environment variables they provide, and to auto-configure Pull Request or Branch parameters in the scanner when a suitable build job is detected. Includes the general clean-up of the creation of Branch and Pull Request configuration to force fail-fast behaviour where target branches are not provided or can't be matched against known branches, to ensure the correct reference branch is selected for Pull Request analysis, and to force an error to be displayed if a user mixes Pull Rrequest and Branch parameters in their launch properties. --- .../plugin/CommunityBranchPlugin.java | 16 +- .../plugin/scanner/BranchAutoConfigurer.java | 33 ++ .../scanner/BranchConfigurationFactory.java | 67 ++++ .../CommunityBranchConfigurationLoader.java | 113 +++---- .../AzureDevopsAutoConfigurer.java | 53 +++ .../BitbucketPipelinesAutoConfigurer.java | 57 ++++ .../CirrusCiAutoConfigurer.java | 57 ++++ .../CodeMagicAutoConfigurer.java | 57 ++++ .../GithubActionsAutoConfigurer.java | 62 ++++ .../GitlabCiAutoConfigurer.java | 51 +++ .../JenkinsAutoConfigurer.java | 53 +++ .../BranchConfigurationFactoryTest.java | 109 ++++++ ...ommunityBranchConfigurationLoaderTest.java | 316 +++--------------- .../AzureDevopsAutoConfigurerTest.java | 72 ++++ .../BitbucketPipelinesAutoConfigurerTest.java | 87 +++++ .../CirrusCiAutoConfigurerTest.java | 87 +++++ .../CodeMagicAutoConfigurerTest.java | 88 +++++ .../GithubActionsAutoConfigurerTest.java | 88 +++++ .../GitlabCiAutoConfigurerTest.java | 76 +++++ .../JenkinsAutoConfigurerTest.java | 76 +++++ 20 files changed, 1280 insertions(+), 338 deletions(-) create mode 100644 src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchAutoConfigurer.java create mode 100644 src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchConfigurationFactory.java create mode 100644 src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/AzureDevopsAutoConfigurer.java create mode 100644 src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/BitbucketPipelinesAutoConfigurer.java create mode 100644 src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CirrusCiAutoConfigurer.java create mode 100644 src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CodeMagicAutoConfigurer.java create mode 100644 src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GithubActionsAutoConfigurer.java create mode 100644 src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GitlabCiAutoConfigurer.java create mode 100644 src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/JenkinsAutoConfigurer.java create mode 100644 src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchConfigurationFactoryTest.java create mode 100644 src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/AzureDevopsAutoConfigurerTest.java create mode 100644 src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/BitbucketPipelinesAutoConfigurerTest.java create mode 100644 src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CirrusCiAutoConfigurerTest.java create mode 100644 src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CodeMagicAutoConfigurerTest.java create mode 100644 src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GithubActionsAutoConfigurerTest.java create mode 100644 src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GitlabCiAutoConfigurerTest.java create mode 100644 src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/JenkinsAutoConfigurerTest.java diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/CommunityBranchPlugin.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/CommunityBranchPlugin.java index 12e3a1a0a..642b83e1c 100644 --- a/src/main/java/com/github/mc1arke/sonarqube/plugin/CommunityBranchPlugin.java +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/CommunityBranchPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 Michael Clarke + * Copyright (C) 2020-2022 Michael Clarke * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,11 +25,19 @@ import com.github.mc1arke.sonarqube.plugin.almclient.github.v3.RestApplicationAuthenticationProvider; import com.github.mc1arke.sonarqube.plugin.almclient.gitlab.DefaultGitlabClientFactory; import com.github.mc1arke.sonarqube.plugin.ce.CommunityReportAnalysisComponentProvider; +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; import com.github.mc1arke.sonarqube.plugin.scanner.CommunityBranchConfigurationLoader; import com.github.mc1arke.sonarqube.plugin.scanner.CommunityBranchParamsValidator; import com.github.mc1arke.sonarqube.plugin.scanner.CommunityProjectBranchesLoader; import com.github.mc1arke.sonarqube.plugin.scanner.CommunityProjectPullRequestsLoader; import com.github.mc1arke.sonarqube.plugin.scanner.ScannerPullRequestPropertySensor; +import com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration.AzureDevopsAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration.BitbucketPipelinesAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration.CirrusCiAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration.CodeMagicAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration.GithubActionsAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration.GitlabCiAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration.JenkinsAutoConfigurer; import com.github.mc1arke.sonarqube.plugin.server.CommunityBranchFeatureExtension; import com.github.mc1arke.sonarqube.plugin.server.CommunityBranchSupportDelegate; import com.github.mc1arke.sonarqube.plugin.server.pullrequest.validator.AzureDevopsValidator; @@ -143,7 +151,11 @@ public void define(Plugin.Context context) { if (SonarQubeSide.SCANNER == context.getRuntime().getSonarQubeSide()) { context.addExtensions(CommunityProjectBranchesLoader.class, CommunityProjectPullRequestsLoader.class, CommunityBranchConfigurationLoader.class, CommunityBranchParamsValidator.class, - ScannerPullRequestPropertySensor.class); + ScannerPullRequestPropertySensor.class, BranchConfigurationFactory.class, + AzureDevopsAutoConfigurer.class, BitbucketPipelinesAutoConfigurer.class, + CirrusCiAutoConfigurer.class, CodeMagicAutoConfigurer.class, + GithubActionsAutoConfigurer.class, GitlabCiAutoConfigurer.class, + JenkinsAutoConfigurer.class); } } } diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchAutoConfigurer.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchAutoConfigurer.java new file mode 100644 index 000000000..9f3f92d7d --- /dev/null +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchAutoConfigurer.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner; + +import org.sonar.api.scanner.ScannerSide; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import java.util.Optional; + +@ScannerSide +public interface BranchAutoConfigurer { + + Optional detectConfiguration(System2 system, ProjectBranches projectBranches); + +} diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchConfigurationFactory.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchConfigurationFactory.java new file mode 100644 index 000000000..96c87afd8 --- /dev/null +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchConfigurationFactory.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner; + +import org.sonar.api.scanner.ScannerSide; +import org.sonar.api.utils.MessageException; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.BranchInfo; +import org.sonar.scanner.scan.branch.BranchType; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import java.util.Optional; + +@ScannerSide +public class BranchConfigurationFactory { + + public BranchConfiguration createBranchConfiguration(String branchName, ProjectBranches branches) { + if (branches.isEmpty()) { + return new CommunityBranchConfiguration(branchName, BranchType.BRANCH, null, null, null); + } + + String targetBranchName = branches.get(branchName) == null ? branches.defaultBranchName() : branchName; + return new CommunityBranchConfiguration(branchName, BranchType.BRANCH, targetBranchName, null, null); + } + + public BranchConfiguration createPullRequestConfiguration(String pullRequestKey, String pullRequestBranch, String pullRequestBase, ProjectBranches branches) { + if (branches.isEmpty()) { + return new CommunityBranchConfiguration(pullRequestBranch, BranchType.PULL_REQUEST, null, pullRequestBase, pullRequestKey); + } + + String referenceBranch = branches.get(pullRequestBase) == null ? branches.defaultBranchName() : findReferenceBranch(pullRequestBase, branches); + return new CommunityBranchConfiguration(pullRequestBranch, BranchType.PULL_REQUEST, referenceBranch, pullRequestBase, pullRequestKey); + + } + + private static String findReferenceBranch(String targetBranch, ProjectBranches branches) { + BranchInfo target = Optional.ofNullable(branches.get(targetBranch)) + .orElseThrow(() -> MessageException.of("No branch exists in Sonarqube with the name " + targetBranch)); + + if (target.type() == BranchType.BRANCH) { + return targetBranch; + } + + String targetBranchTarget = target.branchTargetName(); + if (targetBranchTarget == null) { + throw MessageException.of(String.format("The branch '%s' of type %s does not have a target", target.name(), target.type())); + } + + return findReferenceBranch(targetBranchTarget, branches); + } +} diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/CommunityBranchConfigurationLoader.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/CommunityBranchConfigurationLoader.java index 8258e3223..5acbab8c0 100644 --- a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/CommunityBranchConfigurationLoader.java +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/CommunityBranchConfigurationLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Michael Clarke + * Copyright (C) 2020-2022 Michael Clarke * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,26 +18,27 @@ */ package com.github.mc1arke.sonarqube.plugin.scanner; +import org.apache.commons.lang.StringUtils; import org.sonar.api.notifications.AnalysisWarnings; +import org.sonar.api.utils.MessageException; import org.sonar.api.utils.System2; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.core.config.ScannerProperties; import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.branch.BranchConfigurationLoader; -import org.sonar.scanner.scan.branch.BranchInfo; -import org.sonar.scanner.scan.branch.BranchType; import org.sonar.scanner.scan.branch.DefaultBranchConfiguration; import org.sonar.scanner.scan.branch.ProjectBranches; import org.sonar.scanner.scan.branch.ProjectPullRequests; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; /** * @author Michael Clarke @@ -55,89 +56,67 @@ public class CommunityBranchConfigurationLoader implements BranchConfigurationLo private final System2 system2; private final AnalysisWarnings analysisWarnings; + private final BranchConfigurationFactory branchConfigurationFactory; + private final List autoConfigurers; - public CommunityBranchConfigurationLoader(System2 system2, AnalysisWarnings analysisWarnings) { + public CommunityBranchConfigurationLoader(System2 system2, AnalysisWarnings analysisWarnings, + BranchConfigurationFactory branchConfigurationFactory, + List autoConfigurers) { super(); this.system2 = system2; this.analysisWarnings = analysisWarnings; + this.branchConfigurationFactory = branchConfigurationFactory; + this.autoConfigurers = autoConfigurers; } @Override public BranchConfiguration load(Map localSettings, ProjectBranches projectBranches, ProjectPullRequests pullRequests) { - localSettings = autoConfigure(localSettings); + List nonEmptyParameters = localSettings.entrySet().stream() + .filter(e -> StringUtils.isNotEmpty(e.getValue())) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + boolean hasBranchParameters = BRANCH_ANALYSIS_PARAMETERS.stream() + .anyMatch(nonEmptyParameters::contains); + boolean hasPullRequestParameters = PULL_REQUEST_ANALYSIS_PARAMETERS.stream() + .anyMatch(nonEmptyParameters::contains); + + if (hasPullRequestParameters && hasBranchParameters) { + throw MessageException.of("sonar.pullrequest and sonar.branch parameters should not be specified in the same scan"); + } + + if (!hasBranchParameters && !hasPullRequestParameters) { + for (BranchAutoConfigurer branchAutoConfigurer : autoConfigurers) { + Optional optionalBranchConfiguration = branchAutoConfigurer.detectConfiguration(system2, projectBranches); + if (optionalBranchConfiguration.isPresent()) { + BranchConfiguration branchConfiguration = optionalBranchConfiguration.get(); + LOGGER.info("Auto detected {} configuration with source {} using {}", branchConfiguration.branchType(), branchConfiguration.branchName(), branchAutoConfigurer.getClass().getName()); + return branchConfiguration; + } + } + } if (null != localSettings.get(ScannerProperties.BRANCH_TARGET)) { //NOSONAR - purposefully checking for a deprecated parameter String warning = String.format("Property '%s' is no longer supported", ScannerProperties.BRANCH_TARGET); //NOSONAR - reporting use of deprecated parameter analysisWarnings.addUnique(warning); LOGGER.warn(warning); } - if (BRANCH_ANALYSIS_PARAMETERS.stream().anyMatch(localSettings::containsKey)) { - return createBranchConfiguration(localSettings.get(ScannerProperties.BRANCH_NAME), - projectBranches); - } else if (PULL_REQUEST_ANALYSIS_PARAMETERS.stream().anyMatch(localSettings::containsKey)) { - return createPullRequestConfiguration(localSettings.get(ScannerProperties.PULL_REQUEST_KEY), - localSettings.get(ScannerProperties.PULL_REQUEST_BRANCH), - localSettings.get(ScannerProperties.PULL_REQUEST_BASE), - projectBranches); - } - return new DefaultBranchConfiguration(); - } - - private Map autoConfigure(Map localSettings) { - Map mutableLocalSettings = new HashMap<>(localSettings); - if (Boolean.parseBoolean(system2.envVariable("GITLAB_CI"))) { - //GitLab CI auto configuration - if (system2.envVariable("CI_MERGE_REQUEST_IID") != null) { - // we are inside a merge request - Optional.ofNullable(system2.envVariable("CI_MERGE_REQUEST_IID")).ifPresent( - v -> mutableLocalSettings.putIfAbsent(ScannerProperties.PULL_REQUEST_KEY, v)); - Optional.ofNullable(system2.envVariable("CI_MERGE_REQUEST_SOURCE_BRANCH_NAME")).ifPresent( - v -> mutableLocalSettings.putIfAbsent(ScannerProperties.PULL_REQUEST_BRANCH, v)); - Optional.ofNullable(system2.envVariable("CI_MERGE_REQUEST_TARGET_BRANCH_NAME")).ifPresent( - v -> mutableLocalSettings.putIfAbsent(ScannerProperties.PULL_REQUEST_BASE, v)); - } else { - // branch or tag - Optional.ofNullable(system2.envVariable("CI_COMMIT_REF_NAME")).ifPresent( - v -> mutableLocalSettings.putIfAbsent(ScannerProperties.BRANCH_NAME, v)); - } + if (hasBranchParameters) { + String branch = StringUtils.trimToNull(localSettings.get(ScannerProperties.BRANCH_NAME)); + return branchConfigurationFactory.createBranchConfiguration(branch, projectBranches); } - if (Boolean.parseBoolean(system2.envVariable("TF_BUILD"))) { - Optional.ofNullable(system2.envVariable("SYSTEM_PULLREQUEST_PULLREQUESTID")).ifPresent( - v -> mutableLocalSettings.putIfAbsent(ScannerProperties.PULL_REQUEST_KEY, v)); - Optional.ofNullable(system2.envVariable("SYSTEM_PULLREQUEST_SOURCEBRANCH")).ifPresent( - v -> mutableLocalSettings.putIfAbsent(ScannerProperties.PULL_REQUEST_BRANCH, v)); - Optional.ofNullable(system2.envVariable("SYSTEM_PULLREQUEST_TARGETBRANCH")).ifPresent( - v -> mutableLocalSettings.putIfAbsent(ScannerProperties.PULL_REQUEST_BASE, v)); - } - return Collections.unmodifiableMap(mutableLocalSettings); - } - - private static BranchConfiguration createBranchConfiguration(String branchName, ProjectBranches branches) { - BranchInfo existingBranch = branches.get(branchName); - - if (null == existingBranch) { - return new CommunityBranchConfiguration(branchName, BranchType.BRANCH, branches.defaultBranchName(), null, null); + if (hasPullRequestParameters) { + String key = Optional.ofNullable(StringUtils.trimToNull(localSettings.get(ScannerProperties.PULL_REQUEST_KEY))) + .orElseThrow(() -> MessageException.of(ScannerProperties.PULL_REQUEST_KEY + " is required for a pull request analysis")); + String branch = Optional.ofNullable(StringUtils.trimToNull(localSettings.get(ScannerProperties.PULL_REQUEST_BRANCH))) + .orElseThrow(() -> MessageException.of(ScannerProperties.PULL_REQUEST_BRANCH + " is required for a pull request analysis")); + String target = StringUtils.trimToNull(localSettings.get(ScannerProperties.PULL_REQUEST_BASE)); + return branchConfigurationFactory.createPullRequestConfiguration(key, branch, target, projectBranches); } - return new CommunityBranchConfiguration(branchName, existingBranch.type(), existingBranch.name(), null, null); - } - - private static BranchConfiguration createPullRequestConfiguration(String pullRequestKey, String pullRequestBranch, - String pullRequestBase, - ProjectBranches branches) { - if (null == pullRequestBase || pullRequestBase.isEmpty()) { - return new CommunityBranchConfiguration(pullRequestBranch, BranchType.PULL_REQUEST, branches.defaultBranchName(), - branches.defaultBranchName(), pullRequestKey); - } else { - return new CommunityBranchConfiguration(pullRequestBranch, BranchType.PULL_REQUEST, - Optional.ofNullable(branches.get(pullRequestBase)) - .map(b -> pullRequestBase) - .orElse(null), - pullRequestBase, pullRequestKey); - } + return new DefaultBranchConfiguration(); } } diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/AzureDevopsAutoConfigurer.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/AzureDevopsAutoConfigurer.java new file mode 100644 index 000000000..c3c3c35cb --- /dev/null +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/AzureDevopsAutoConfigurer.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import java.util.Optional; + +public class AzureDevopsAutoConfigurer implements BranchAutoConfigurer { + + private final BranchConfigurationFactory branchConfigurationFactory; + + public AzureDevopsAutoConfigurer(BranchConfigurationFactory branchConfigurationFactory) { + this.branchConfigurationFactory = branchConfigurationFactory; + } + + @Override + public Optional detectConfiguration(System2 system2, ProjectBranches projectBranches) { + if (!Boolean.parseBoolean(system2.envVariable("TF_BUILD"))) { + return Optional.empty(); + } + + String key = system2.envVariable("SYSTEM_PULLREQUEST_PULLREQUESTID"); + if (key != null) { + String sourceBranch = system2.envVariable("SYSTEM_PULLREQUEST_SOURCEBRANCH"); + String targetBranch = system2.envVariable("SYSTEM_PULLREQUEST_TARGETBRANCH"); + + return Optional.of(branchConfigurationFactory.createPullRequestConfiguration(key, sourceBranch, targetBranch, projectBranches)); + } + + return Optional.empty(); + } +} diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/BitbucketPipelinesAutoConfigurer.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/BitbucketPipelinesAutoConfigurer.java new file mode 100644 index 000000000..678997a7e --- /dev/null +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/BitbucketPipelinesAutoConfigurer.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import java.util.Optional; + +public class BitbucketPipelinesAutoConfigurer implements BranchAutoConfigurer { + + private final BranchConfigurationFactory branchConfigurationFactory; + + public BitbucketPipelinesAutoConfigurer(BranchConfigurationFactory branchConfigurationFactory) { + this.branchConfigurationFactory = branchConfigurationFactory; + } + + @Override + public Optional detectConfiguration(System2 system2, ProjectBranches projectBranches) { + if (!Boolean.parseBoolean(system2.envVariable("CI"))) { + return Optional.empty(); + } + + String branch = system2.envVariable("BITBUCKET_BRANCH"); + if (StringUtils.isEmpty(branch)) { + return Optional.empty(); + } + + String prId = system2.envVariable("BITBUCKET_PR_ID"); + String targetBranch = system2.envVariable("BITBUCKET_PR_DESTINATION_BRANCH"); + if (StringUtils.isEmpty(prId)) { + return Optional.of(branchConfigurationFactory.createBranchConfiguration(branch, projectBranches)); + } else { + return Optional.of(branchConfigurationFactory.createPullRequestConfiguration(prId, branch, targetBranch, projectBranches)); + } + } +} diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CirrusCiAutoConfigurer.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CirrusCiAutoConfigurer.java new file mode 100644 index 000000000..da420da95 --- /dev/null +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CirrusCiAutoConfigurer.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import java.util.Optional; + +public class CirrusCiAutoConfigurer implements BranchAutoConfigurer { + + private final BranchConfigurationFactory branchConfigurationFactory; + + public CirrusCiAutoConfigurer(BranchConfigurationFactory branchConfigurationFactory) { + this.branchConfigurationFactory = branchConfigurationFactory; + } + + @Override + public Optional detectConfiguration(System2 system2, ProjectBranches projectBranches) { + if (!Boolean.parseBoolean(system2.envVariable("CIRRUS_CI"))) { + return Optional.empty(); + } + + String branch = system2.envVariable("CIRRUS_BRANCH"); + if (StringUtils.isEmpty(branch)) { + return Optional.empty(); + } + + String pullRequestId = system2.envVariable("CIRRUS_PR"); + if (StringUtils.isEmpty(pullRequestId)) { + return Optional.of(branchConfigurationFactory.createBranchConfiguration(branch, projectBranches)); + } else { + String targetBranch = system2.envVariable("CIRRUS_BASE_BRANCH"); + return Optional.of(branchConfigurationFactory.createPullRequestConfiguration(pullRequestId, branch, targetBranch, projectBranches)); + } + } +} diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CodeMagicAutoConfigurer.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CodeMagicAutoConfigurer.java new file mode 100644 index 000000000..56f8a86b9 --- /dev/null +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CodeMagicAutoConfigurer.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import java.util.Optional; + +public class CodeMagicAutoConfigurer implements BranchAutoConfigurer { + + private final BranchConfigurationFactory branchConfigurationFactory; + + public CodeMagicAutoConfigurer(BranchConfigurationFactory branchConfigurationFactory) { + this.branchConfigurationFactory = branchConfigurationFactory; + } + + @Override + public Optional detectConfiguration(System2 system2, ProjectBranches projectBranches) { + if (!Boolean.parseBoolean(system2.envVariable("CI"))) { + return Optional.empty(); + } + + String sourceBranch = system2.envVariable("FCI_BRANCH"); + if (StringUtils.isEmpty(sourceBranch)) { + return Optional.empty(); + } + + if (Boolean.parseBoolean(system2.envVariable("FCI_PULL_REQUEST"))) { + String pullRequestId = system2.envVariable("FCI_PULL_REQUEST_NUMBER"); + String targetBranch = system2.envVariable("FCI_PULL_REQUEST_DEST"); + return Optional.of(branchConfigurationFactory.createPullRequestConfiguration(pullRequestId, sourceBranch, targetBranch, projectBranches)); + } else { + return Optional.of(branchConfigurationFactory.createBranchConfiguration(sourceBranch, projectBranches)); + } + } +} diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GithubActionsAutoConfigurer.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GithubActionsAutoConfigurer.java new file mode 100644 index 000000000..d18a8e0a5 --- /dev/null +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GithubActionsAutoConfigurer.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import java.util.Optional; + +public class GithubActionsAutoConfigurer implements BranchAutoConfigurer { + + private static final String PULL_REQUEST_REF_PREFIX = "refs/pull/"; + private static final String PULL_REQUEST_REF_POSTFIX = "/merge"; + + private final BranchConfigurationFactory branchConfigurationFactory; + + public GithubActionsAutoConfigurer(BranchConfigurationFactory branchConfigurationFactory) { + this.branchConfigurationFactory = branchConfigurationFactory; + } + + @Override + public Optional detectConfiguration(System2 system, ProjectBranches projectBranches) { + if (!Boolean.parseBoolean(system.envVariable("GITHUB_ACTIONS"))) { + return Optional.empty(); + } + + String ref = system.envVariable("GITHUB_REF"); + if (StringUtils.isEmpty(ref)) { + return Optional.empty(); + } + + String sourceBranch = system.envVariable("GITHUB_HEAD_REF"); + if (ref.startsWith(PULL_REQUEST_REF_PREFIX) && ref.endsWith(PULL_REQUEST_REF_POSTFIX) && StringUtils.isNotEmpty(sourceBranch)) { + String key = ref.substring(PULL_REQUEST_REF_PREFIX.length(), ref.length() - PULL_REQUEST_REF_POSTFIX.length()); + String targetBranch = system.envVariable("GITHUB_BASE_REF"); + return Optional.of(branchConfigurationFactory.createPullRequestConfiguration(key, sourceBranch, targetBranch, projectBranches)); + } else { + String branch = system.envVariable("GITHUB_REF_NAME"); + return Optional.of(branchConfigurationFactory.createBranchConfiguration(branch, projectBranches)); + } + } +} diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GitlabCiAutoConfigurer.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GitlabCiAutoConfigurer.java new file mode 100644 index 000000000..92dc904b0 --- /dev/null +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GitlabCiAutoConfigurer.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import java.util.Optional; + +public class GitlabCiAutoConfigurer implements BranchAutoConfigurer { + + private final BranchConfigurationFactory branchConfigurationFactory; + + public GitlabCiAutoConfigurer(BranchConfigurationFactory branchConfigurationFactory) { + this.branchConfigurationFactory = branchConfigurationFactory; + } + + @Override + public Optional detectConfiguration(System2 system2, ProjectBranches projectBranches) { + if (!Boolean.parseBoolean(system2.envVariable("GITLAB_CI"))) { + return Optional.empty(); + } + + String mergeRequestId = system2.envVariable("CI_MERGE_REQUEST_IID"); + if (StringUtils.isEmpty(mergeRequestId)) { + return Optional.of(branchConfigurationFactory.createBranchConfiguration(system2.envVariable("CI_COMMIT_REF_NAME"), projectBranches)); + } else { + return Optional.of(branchConfigurationFactory.createPullRequestConfiguration(mergeRequestId, system2.envVariable("CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"), system2.envVariable("CI_MERGE_REQUEST_TARGET_BRANCH_NAME"), projectBranches)); + } + } +} diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/JenkinsAutoConfigurer.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/JenkinsAutoConfigurer.java new file mode 100644 index 000000000..3e5c29b0f --- /dev/null +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/JenkinsAutoConfigurer.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchAutoConfigurer; +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import java.util.Optional; + +public class JenkinsAutoConfigurer implements BranchAutoConfigurer { + + private final BranchConfigurationFactory branchConfigurationFactory; + + public JenkinsAutoConfigurer(BranchConfigurationFactory branchConfigurationFactory) { + this.branchConfigurationFactory = branchConfigurationFactory; + } + + @Override + public Optional detectConfiguration(System2 system2, ProjectBranches projectBranches) { + if (StringUtils.isEmpty(system2.envVariable("JENKINS_HOME"))) { + return Optional.empty(); + } + + String pullRequestId = system2.envVariable("CHANGE_ID"); + if (StringUtils.isEmpty(pullRequestId)) { + return Optional.of(branchConfigurationFactory.createBranchConfiguration(system2.envVariable("BRANCH_NAME"), projectBranches)); + } else { + String changeBranch = system2.envVariable("CHANGE_BRANCH"); + String changeTarget = system2.envVariable("CHANGE_TARGET"); + return Optional.of(branchConfigurationFactory.createPullRequestConfiguration(pullRequestId, changeBranch, changeTarget, projectBranches)); + } + } +} diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchConfigurationFactoryTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchConfigurationFactoryTest.java new file mode 100644 index 000000000..5d4ebc490 --- /dev/null +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/BranchConfigurationFactoryTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner; + +import org.junit.jupiter.api.Test; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.BranchInfo; +import org.sonar.scanner.scan.branch.BranchType; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class BranchConfigurationFactoryTest { + + @Test + void shouldReturnBranchWithNoTargetIfNoProjectBranchesExist() { + ProjectBranches projectBranches = mock(ProjectBranches.class); + when(projectBranches.isEmpty()).thenReturn(true); + + BranchConfigurationFactory underTest = new BranchConfigurationFactory(); + BranchConfiguration actual = underTest.createBranchConfiguration("branch", projectBranches); + + assertThat(actual).usingRecursiveComparison().isEqualTo(new CommunityBranchConfiguration("branch", BranchType.BRANCH, null, null, null)); + } + + @Test + void shouldReturnBranchWithDefaultReferenceIfSpecifiedBranchDoesNotExist() { + ProjectBranches projectBranches = mock(ProjectBranches.class); + when(projectBranches.isEmpty()).thenReturn(false); + when(projectBranches.defaultBranchName()).thenReturn("default"); + when(projectBranches.get(any())).thenReturn(null); + + BranchConfigurationFactory underTest = new BranchConfigurationFactory(); + BranchConfiguration actual = underTest.createBranchConfiguration("branch", projectBranches); + + assertThat(actual).usingRecursiveComparison().isEqualTo(new CommunityBranchConfiguration("branch", BranchType.BRANCH, "default", null, null)); + } + + @Test + void shouldReturnBranchWithSelfReferenceIfSpecifiedBranchDoesExist() { + ProjectBranches projectBranches = mock(ProjectBranches.class); + when(projectBranches.isEmpty()).thenReturn(false); + when(projectBranches.defaultBranchName()).thenReturn("default"); + when(projectBranches.get(any())).thenReturn(mock(BranchInfo.class)); + + BranchConfigurationFactory underTest = new BranchConfigurationFactory(); + BranchConfiguration actual = underTest.createBranchConfiguration("branch", projectBranches); + + assertThat(actual).usingRecursiveComparison().isEqualTo(new CommunityBranchConfiguration("branch", BranchType.BRANCH, "branch", null, null)); + } + + @Test + void shouldReturnPullRequestWithNoTargetIfNoProjectBranchesExist() { + ProjectBranches projectBranches = mock(ProjectBranches.class); + when(projectBranches.isEmpty()).thenReturn(true); + + BranchConfigurationFactory underTest = new BranchConfigurationFactory(); + BranchConfiguration actual = underTest.createPullRequestConfiguration("key", "source", "target", projectBranches); + + assertThat(actual).usingRecursiveComparison().isEqualTo(new CommunityBranchConfiguration("source", BranchType.PULL_REQUEST, null, "target", "key")); + } + + @Test + void shouldReturnPullRequestWithTargetOfTargetAsReferenceIfTargetBranchExists() { + ProjectBranches projectBranches = mock(ProjectBranches.class); + when(projectBranches.isEmpty()).thenReturn(false); + BranchInfo branchInfo = new BranchInfo("target", BranchType.PULL_REQUEST, false, "target2"); + when(projectBranches.get("target")).thenReturn(branchInfo); + BranchInfo branchInfo2 = new BranchInfo("target2", BranchType.BRANCH, false, "target3"); + when(projectBranches.get("target2")).thenReturn(branchInfo2); + + BranchConfigurationFactory underTest = new BranchConfigurationFactory(); + BranchConfiguration actual = underTest.createPullRequestConfiguration("key", "source", "target", projectBranches); + + assertThat(actual).usingRecursiveComparison().isEqualTo(new CommunityBranchConfiguration("source", BranchType.PULL_REQUEST, "target2", "target", "key")); + } + + @Test + void shouldThrowExceptionIfPullRequestTargetsOtherPullRequestWithoutATarget() { + ProjectBranches projectBranches = mock(ProjectBranches.class); + when(projectBranches.isEmpty()).thenReturn(false); + BranchInfo branchInfo = new BranchInfo("target", BranchType.PULL_REQUEST, false, null); + when(projectBranches.get("target")).thenReturn(branchInfo); + + BranchConfigurationFactory underTest = new BranchConfigurationFactory(); + assertThatThrownBy(() -> underTest.createPullRequestConfiguration("key", "source", "target", projectBranches)).hasMessage("The branch 'target' of type PULL_REQUEST does not have a target"); + } + +} \ No newline at end of file diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/CommunityBranchConfigurationLoaderTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/CommunityBranchConfigurationLoaderTest.java index b3927217f..7312eb828 100644 --- a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/CommunityBranchConfigurationLoaderTest.java +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/CommunityBranchConfigurationLoaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Michael Clarke + * Copyright (C) 2020-2022 Michael Clarke * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,328 +18,106 @@ */ package com.github.mc1arke.sonarqube.plugin.scanner; -import org.hamcrest.core.IsEqual; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.utils.System2; import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.branch.BranchConfigurationLoader; -import org.sonar.scanner.scan.branch.BranchInfo; -import org.sonar.scanner.scan.branch.BranchType; import org.sonar.scanner.scan.branch.DefaultBranchConfiguration; import org.sonar.scanner.scan.branch.ProjectBranches; import org.sonar.scanner.scan.branch.ProjectPullRequests; -import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Optional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; /** * @author Michael Clarke */ -public class CommunityBranchConfigurationLoaderTest { - - private final ExpectedException expectedException = ExpectedException.none(); +class CommunityBranchConfigurationLoaderTest { private final AnalysisWarnings analysisWarnings = mock(AnalysisWarnings.class); private final System2 system2 = mock(System2.class); - private final BranchConfigurationLoader testCase = new CommunityBranchConfigurationLoader(system2, analysisWarnings); - - @Rule - public ExpectedException expectedException() { - return expectedException; - } - - @Test - public void testExceptionWhenNoExistingBranchAndBranchParamsPresent() { - ProjectBranches branchInfo = mock(ProjectBranches.class); - when(branchInfo.isEmpty()).thenReturn(true); - - Map parameters = new HashMap<>(); - parameters.put("sonar.branch.name", "dummy"); - - BranchConfiguration branchConfiguration = testCase.load(parameters, branchInfo, mock(ProjectPullRequests.class)); - - assertEquals("dummy", branchConfiguration.branchName()); - assertNull(branchConfiguration.referenceBranchName()); - assertEquals(BranchType.BRANCH, branchConfiguration.branchType()); - } - - @Test - public void testDefaultConfigWhenNoExistingBranchAndBranchNameParamMaster() { - ProjectBranches branchInfo = mock(ProjectBranches.class); - when(branchInfo.isEmpty()).thenReturn(true); - - Map parameters = new HashMap<>(); - parameters.put("sonar.branch.name", "master"); - - BranchConfiguration branchConfiguration = testCase.load(parameters, mock(ProjectBranches.class), mock(ProjectPullRequests.class)); - assertEquals("master", branchConfiguration.branchName()); - assertNull(branchConfiguration.targetBranchName()); - assertNull(branchConfiguration.referenceBranchName()); - assertEquals(BranchType.BRANCH, branchConfiguration.branchType()); } - - @Test - public void testErrorWhenNoExistingBranchAndBranchTargetMasterButNoSourceBranch() { - ProjectBranches branchInfo = mock(ProjectBranches.class); - when(branchInfo.isEmpty()).thenReturn(true); - - Map parameters = new HashMap<>(); - parameters.put("sonar.branch.name", "dummy"); - - BranchConfiguration branchConfiguration = testCase.load(parameters, branchInfo, mock(ProjectPullRequests.class)); - - assertEquals("dummy", branchConfiguration.branchName()); - assertNull(branchConfiguration.referenceBranchName()); - assertNull(branchConfiguration.targetBranchName()); - assertEquals(BranchType.BRANCH, branchConfiguration.branchType()); - } + private final BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + private final BranchAutoConfigurer branchAutoConfigurer = mock(BranchAutoConfigurer.class); + private final BranchConfigurationLoader testCase = new CommunityBranchConfigurationLoader(system2, analysisWarnings, branchConfigurationFactory, List.of(branchAutoConfigurer)); @Test - public void testWarningWhenTargetBranchParameterSpecified() { - Map parameters = new HashMap<>(); - parameters.put("sonar.branch.name", "feature/shortLivedBranch"); - parameters.put("sonar.branch.target", "dummy"); - - BranchInfo mockTargetBranchInfo = mock(BranchInfo.class); - when(mockTargetBranchInfo.name()).thenReturn("defaultBranchInfo"); - when(mockTargetBranchInfo.type()).thenReturn(BranchType.BRANCH); + void shouldReturnResultFromAutoConfigurerIfPresentAndNoParametersSpecified() { + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchAutoConfigurer.detectConfiguration(any(), any())).thenReturn(Optional.of(branchConfiguration)); ProjectBranches projectBranches = mock(ProjectBranches.class); - when(projectBranches.get("masterxxx")).thenReturn(mockTargetBranchInfo); - when(projectBranches.defaultBranchName()).thenReturn("masterxxx"); - BranchConfiguration result = testCase.load(parameters, projectBranches, mock(ProjectPullRequests.class)); + BranchConfiguration actual = testCase.load(Map.of(), projectBranches, mock(ProjectPullRequests.class)); - assertNull(result.targetBranchName()); - assertEquals("feature/shortLivedBranch", result.branchName()); - assertEquals("masterxxx", result.referenceBranchName()); - assertFalse(result.isPullRequest()); - - verify(analysisWarnings).addUnique(eq("Property 'sonar.branch.target' is no longer supported")); - } - - - @Test - public void testDefaultConfigWhenNoExistingBranchAndBranchParamsAllMaster() { - ProjectBranches branchInfo = mock(ProjectBranches.class); - when(branchInfo.isEmpty()).thenReturn(true); - - Map parameters = new HashMap<>(); - parameters.put("sonar.branch.name", "master"); - - BranchConfiguration branchConfiguration = testCase.load(parameters, branchInfo, mock(ProjectPullRequests.class)); - - assertEquals("master", branchConfiguration.branchName()); - assertEquals(BranchType.BRANCH, branchConfiguration.branchType()); - assertNull(branchConfiguration.referenceBranchName()); - assertNull(branchConfiguration.targetBranchName()); - } - - @Test - public void testDefaultBranchInfoWhenNoBranchParametersSpecifiedAndNoBranchesExist() { - ProjectBranches branchInfo = mock(ProjectBranches.class); - when(branchInfo.isEmpty()).thenReturn(true); - - Map parameters = new HashMap<>(); - parameters.put("dummy", "dummy"); - - - assertEquals(DefaultBranchConfiguration.class, - testCase.load(parameters, branchInfo, mock(ProjectPullRequests.class)).getClass()); - } - - @Test - public void testDefaultBranchInfoWhenNoParametersSpecified() { - assertEquals(DefaultBranchConfiguration.class, testCase.load(new HashMap<>(), mock(ProjectBranches.class), - mock(ProjectPullRequests.class)).getClass()); + assertThat(actual).isSameAs(branchConfiguration); + verify(branchAutoConfigurer).detectConfiguration(system2, projectBranches); + verifyNoInteractions(branchConfigurationFactory); } @Test - public void testValidBranchInfoWhenAllBranchParametersSpecified() { - Map parameters = new HashMap<>(); - parameters.put("sonar.branch.name", "feature/shortLivedFeatureBranch"); - - BranchInfo mockTargetBranchInfo = mock(BranchInfo.class); - when(mockTargetBranchInfo.name()).thenReturn("masterBranchInfo"); - when(mockTargetBranchInfo.type()).thenReturn(BranchType.BRANCH); + void shouldReturnDefaultBranchIfAutoConfigurerNoResultAndNoParametersSpecified() { + when(branchAutoConfigurer.detectConfiguration(any(), any())).thenReturn(Optional.empty()); ProjectBranches projectBranches = mock(ProjectBranches.class); - when(projectBranches.get("master")).thenReturn(mockTargetBranchInfo); - when(projectBranches.defaultBranchName()).thenReturn("master"); - - BranchConfiguration result = testCase.load(parameters, projectBranches, mock(ProjectPullRequests.class)); - - assertNull(result.targetBranchName()); - assertEquals("feature/shortLivedFeatureBranch", result.branchName()); - assertEquals("master", result.referenceBranchName()); - assertFalse(result.isPullRequest()); - expectedException - .expectMessage(IsEqual.equalTo("Only a branch of type PULL_REQUEST can have a Pull Request key")); - expectedException.expect(IllegalStateException.class); + BranchConfiguration actual = testCase.load(Map.of(), projectBranches, mock(ProjectPullRequests.class)); - result.pullRequestKey(); + assertThat(actual).usingRecursiveComparison().isEqualTo(new DefaultBranchConfiguration()); + verify(branchAutoConfigurer).detectConfiguration(system2, projectBranches); + verifyNoInteractions(branchConfigurationFactory); } @Test - public void testValidBranchInfoWhenOnlySourceBranchSpecifiedAndMasterExists() { - Map parameters = new HashMap<>(); - parameters.put("sonar.branch.name", "feature/shortLivedBranch"); - - BranchInfo mockTargetBranchInfo = mock(BranchInfo.class); - when(mockTargetBranchInfo.name()).thenReturn("defaultBranchInfo"); - when(mockTargetBranchInfo.type()).thenReturn(BranchType.BRANCH); - + void shouldCreateBranchConfigurationIfAnyBranchPropertiesSet() { ProjectBranches projectBranches = mock(ProjectBranches.class); - when(projectBranches.get("masterxxx")).thenReturn(mockTargetBranchInfo); - when(projectBranches.defaultBranchName()).thenReturn("masterxxx"); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createBranchConfiguration(any(), any())).thenReturn(branchConfiguration); - BranchConfiguration result = testCase.load(parameters, projectBranches, mock(ProjectPullRequests.class)); + BranchConfiguration actual = testCase.load(Map.of("sonar.branch.name", "branch", "sonar.branch.target", "target"), projectBranches, mock(ProjectPullRequests.class)); - assertNull(result.targetBranchName()); - assertEquals("feature/shortLivedBranch", result.branchName()); - assertEquals("masterxxx", result.referenceBranchName()); - assertFalse(result.isPullRequest()); + assertThat(actual).isSameAs(branchConfiguration); + verify(branchConfigurationFactory).createBranchConfiguration("branch", projectBranches); + verifyNoInteractions(branchAutoConfigurer); + verify(analysisWarnings).addUnique("Property 'sonar.branch.target' is no longer supported"); } @Test - public void testExceptionWhenOnlySourceBranchSpecifiedAndNoMasterExists() { - Map parameters = new HashMap<>(); - parameters.put("sonar.branch.name", "feature/shortLivedBranch"); - - BranchInfo mockTargetBranchInfo = mock(BranchInfo.class); - when(mockTargetBranchInfo.name()).thenReturn("defaultBranchInfo"); - when(mockTargetBranchInfo.type()).thenReturn(BranchType.BRANCH); - + void shouldCreatePullConfigurationIfAnyPullRequestPropertiesSet() { ProjectBranches projectBranches = mock(ProjectBranches.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createPullRequestConfiguration(any(), any(), any(), any())).thenReturn(branchConfiguration); - BranchConfiguration branchConfiguration = testCase.load(parameters, projectBranches, mock(ProjectPullRequests.class)); + BranchConfiguration actual = testCase.load(Map.of("sonar.pullrequest.key", "key", "sonar.pullrequest.branch", "source", "sonar.pullrequest.base", "target"), projectBranches, mock(ProjectPullRequests.class)); - assertEquals("feature/shortLivedBranch", branchConfiguration.branchName()); - assertNull(branchConfiguration.referenceBranchName()); - assertNull(branchConfiguration.targetBranchName()); - assertEquals(BranchType.BRANCH, branchConfiguration.branchType()); + assertThat(actual).isSameAs(branchConfiguration); + verify(branchConfigurationFactory).createPullRequestConfiguration("key", "source", "target", projectBranches); + verifyNoInteractions(branchAutoConfigurer); + verifyNoInteractions(analysisWarnings); } @Test - public void testExistingBranchOnlySourceParameters() { - Map parameters = new HashMap<>(); - parameters.put("sonar.branch.name", "longLivedBranch"); - - BranchInfo mockTargetBranchInfo = mock(BranchInfo.class); - when(mockTargetBranchInfo.name()).thenReturn("longLivedBranch"); - when(mockTargetBranchInfo.type()).thenReturn(BranchType.BRANCH); - - - ProjectBranches projectBranches = mock(ProjectBranches.class); - when(projectBranches.get("longLivedBranch")).thenReturn(mockTargetBranchInfo); - - BranchConfiguration result = testCase.load(parameters, projectBranches, mock(ProjectPullRequests.class)); - - assertNull(result.targetBranchName()); - assertEquals("longLivedBranch", result.branchName()); - assertEquals("longLivedBranch", result.referenceBranchName()); - assertFalse(result.isPullRequest()); + void shouldThrowErrorIfBothBranchAndPullRequestParametersPresent() { + assertThatThrownBy(() -> testCase.load(Map.of("sonar.pullrequest.key", "key", "sonar.pullrequest.branch", "source", "sonar.branch.name", "branch"), mock(ProjectBranches.class), mock(ProjectPullRequests.class))).hasMessage("sonar.pullrequest and sonar.branch parameters should not be specified in the same scan"); } @Test - public void testPullRequestAllParameters() { - Map parameters = new HashMap<>(); - parameters.put("sonar.pullrequest.branch", "feature/sourceBranch"); - parameters.put("sonar.pullrequest.base", "target"); - parameters.put("sonar.pullrequest.key", "pr-key"); - - BranchInfo mockTargetBranchInfo = mock(BranchInfo.class); - when(mockTargetBranchInfo.name()).thenReturn("targetInfo"); - when(mockTargetBranchInfo.type()).thenReturn(BranchType.BRANCH); - - ProjectBranches projectBranches = mock(ProjectBranches.class); - when(projectBranches.get("target")).thenReturn(mockTargetBranchInfo); - - BranchConfiguration result = testCase.load(parameters, projectBranches, mock(ProjectPullRequests.class)); - - assertEquals("target", result.targetBranchName()); - assertEquals("feature/sourceBranch", result.branchName()); - assertEquals("target", result.referenceBranchName()); - assertTrue(result.isPullRequest()); - assertEquals("pr-key", result.pullRequestKey()); + void shouldThrowErrorIfPullRequestAnlysisWithoutPullRequestKey() { + assertThatThrownBy(() -> testCase.load(Map.of("sonar.pullrequest.base", "target"), mock(ProjectBranches.class), mock(ProjectPullRequests.class))).hasMessage("sonar.pullrequest.key is required for a pull request analysis"); } - @Test - public void testPullRequestMandatoryParameters() { - Map parameters = new HashMap<>(); - parameters.put("sonar.pullrequest.branch", "feature/sourceBranch"); - parameters.put("sonar.pullrequest.key", "pr-key"); - - BranchInfo mockTargetBranchInfo = mock(BranchInfo.class); - when(mockTargetBranchInfo.name()).thenReturn("masterInfo"); - when(mockTargetBranchInfo.type()).thenReturn(BranchType.BRANCH); - - - ProjectBranches projectBranches = mock(ProjectBranches.class); - when(projectBranches.get("master")).thenReturn(mockTargetBranchInfo); - when(projectBranches.defaultBranchName()).thenReturn("master"); - - BranchConfiguration result = testCase.load(parameters, projectBranches, mock(ProjectPullRequests.class)); - - assertEquals("master", result.targetBranchName()); - assertEquals("feature/sourceBranch", result.branchName()); - assertEquals("master", result.referenceBranchName()); - assertTrue(result.isPullRequest()); - } - - @Test - public void testPullRequestMandatoryParameters2() { - Map parameters = new HashMap<>(); - parameters.put("sonar.pullrequest.branch", "feature/sourceBranch"); - parameters.put("sonar.pullrequest.key", "pr-key"); - parameters.put("sonar.pullrequest.base", ""); - - BranchInfo mockTargetBranchInfo = mock(BranchInfo.class); - when(mockTargetBranchInfo.name()).thenReturn("masterInfo"); - when(mockTargetBranchInfo.type()).thenReturn(BranchType.BRANCH); - - - ProjectBranches projectBranches = mock(ProjectBranches.class); - when(projectBranches.get("master")).thenReturn(mockTargetBranchInfo); - when(projectBranches.defaultBranchName()).thenReturn("master"); - - BranchConfiguration result = testCase.load(parameters, projectBranches, mock(ProjectPullRequests.class)); - - assertEquals("master", result.targetBranchName()); - assertEquals("feature/sourceBranch", result.branchName()); - assertEquals("master", result.referenceBranchName()); - assertTrue(result.isPullRequest()); - } - - - @Test - public void testPullRequestNoSuchTarget() { - Map parameters = new HashMap<>(); - parameters.put("sonar.pullrequest.branch", "feature/sourceBranch"); - parameters.put("sonar.pullrequest.base", "missingTarget"); - parameters.put("sonar.pullrequest.key", "pr-key"); - - - ProjectBranches projectBranches = mock(ProjectBranches.class); - - BranchConfiguration branchConfiguration = testCase.load(parameters, projectBranches, mock(ProjectPullRequests.class)); - assertEquals("feature/sourceBranch", branchConfiguration.branchName()); - assertEquals("missingTarget", branchConfiguration.targetBranchName()); - assertNull(branchConfiguration.referenceBranchName()); - assertEquals(BranchType.PULL_REQUEST, branchConfiguration.branchType()); + void shouldThrowErrorIfPullRequestAnalysisWithoutPullRequestBranch() { + assertThatThrownBy(() -> testCase.load(Map.of("sonar.pullrequest.key", "key"), mock(ProjectBranches.class), mock(ProjectPullRequests.class))).hasMessage("sonar.pullrequest.branch is required for a pull request analysis"); } } diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/AzureDevopsAutoConfigurerTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/AzureDevopsAutoConfigurerTest.java new file mode 100644 index 000000000..9a7577aeb --- /dev/null +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/AzureDevopsAutoConfigurerTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.junit.jupiter.api.Test; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class AzureDevopsAutoConfigurerTest { + + @Test + void shouldReturnOptionalEmptyIfNotTfBuild() { + System2 system2 = mock(System2.class); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + AzureDevopsAutoConfigurer underTest = new AzureDevopsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnOptionalEmptyIfTfBuildWithNoPullRequestId() { + System2 system2 = mock(System2.class); + when(system2.envVariable("TF_BUILD")).thenReturn("true"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + AzureDevopsAutoConfigurer underTest = new AzureDevopsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnConfigurationBasedOnAllEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("TF_BUILD")).thenReturn("true"); + when(system2.envVariable("SYSTEM_PULLREQUEST_PULLREQUESTID")).thenReturn("id"); + when(system2.envVariable("SYSTEM_PULLREQUEST_SOURCEBRANCH")).thenReturn("source"); + when(system2.envVariable("SYSTEM_PULLREQUEST_TARGETBRANCH")).thenReturn("target"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createPullRequestConfiguration(any(), any(), any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + AzureDevopsAutoConfigurer underTest = new AzureDevopsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createPullRequestConfiguration("id", "source", "target", projectBranches); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/BitbucketPipelinesAutoConfigurerTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/BitbucketPipelinesAutoConfigurerTest.java new file mode 100644 index 000000000..ee0710762 --- /dev/null +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/BitbucketPipelinesAutoConfigurerTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.junit.jupiter.api.Test; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class BitbucketPipelinesAutoConfigurerTest { + + @Test + void shouldReturnOptionalEmptyIfNotCi() { + System2 system2 = mock(System2.class); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + BitbucketPipelinesAutoConfigurer underTest = new BitbucketPipelinesAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnOptionalEmptyIfCiWithNoBranchProperty() { + System2 system2 = mock(System2.class); + when(system2.envVariable("CI")).thenReturn("true"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + BitbucketPipelinesAutoConfigurer underTest = new BitbucketPipelinesAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnBranchConfigurationBasedOnNoPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("CI")).thenReturn("true"); + when(system2.envVariable("BITBUCKET_BRANCH")).thenReturn("branch"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createBranchConfiguration(any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + BitbucketPipelinesAutoConfigurer underTest = new BitbucketPipelinesAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createBranchConfiguration("branch", projectBranches); + } + + @Test + void shouldReturnPullRequestConfigurationBasedOnPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("CI")).thenReturn("true"); + when(system2.envVariable("BITBUCKET_BRANCH")).thenReturn("source"); + when(system2.envVariable("BITBUCKET_PR_ID")).thenReturn("id"); + when(system2.envVariable("BITBUCKET_PR_DESTINATION_BRANCH")).thenReturn("target"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createPullRequestConfiguration(any(), any(), any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + BitbucketPipelinesAutoConfigurer underTest = new BitbucketPipelinesAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createPullRequestConfiguration("id", "source", "target", projectBranches); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CirrusCiAutoConfigurerTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CirrusCiAutoConfigurerTest.java new file mode 100644 index 000000000..38f326ce4 --- /dev/null +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CirrusCiAutoConfigurerTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.junit.jupiter.api.Test; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class CirrusCiAutoConfigurerTest { + + @Test + void shouldReturnOptionalEmptyIfNotCirrusCi() { + System2 system2 = mock(System2.class); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + CirrusCiAutoConfigurer underTest = new CirrusCiAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnOptionalEmptyIfCirrusCiWithNoBranchProperty() { + System2 system2 = mock(System2.class); + when(system2.envVariable("CIRRUS_CI")).thenReturn("true"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + CirrusCiAutoConfigurer underTest = new CirrusCiAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnBranchConfigurationBasedOnNoPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("CIRRUS_CI")).thenReturn("true"); + when(system2.envVariable("CIRRUS_BRANCH")).thenReturn("branch"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createBranchConfiguration(any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + CirrusCiAutoConfigurer underTest = new CirrusCiAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createBranchConfiguration("branch", projectBranches); + } + + @Test + void shouldReturnPullRequestConfigurationBasedOnPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("CIRRUS_CI")).thenReturn("true"); + when(system2.envVariable("CIRRUS_BRANCH")).thenReturn("source"); + when(system2.envVariable("CIRRUS_PR")).thenReturn("id"); + when(system2.envVariable("CIRRUS_BASE_BRANCH")).thenReturn("target"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createPullRequestConfiguration(any(), any(), any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + CirrusCiAutoConfigurer underTest = new CirrusCiAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createPullRequestConfiguration("id", "source", "target", projectBranches); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CodeMagicAutoConfigurerTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CodeMagicAutoConfigurerTest.java new file mode 100644 index 000000000..8a99fcc23 --- /dev/null +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/CodeMagicAutoConfigurerTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.junit.jupiter.api.Test; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class CodeMagicAutoConfigurerTest { + + @Test + void shouldReturnOptionalEmptyIfNotCi() { + System2 system2 = mock(System2.class); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + CodeMagicAutoConfigurer underTest = new CodeMagicAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnOptionalEmptyIfCiWithNoFciBranchProperty() { + System2 system2 = mock(System2.class); + when(system2.envVariable("CI")).thenReturn("true"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + CodeMagicAutoConfigurer underTest = new CodeMagicAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnBranchConfigurationBasedOnNoPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("CI")).thenReturn("true"); + when(system2.envVariable("FCI_BRANCH")).thenReturn("branch"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createBranchConfiguration(any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + CodeMagicAutoConfigurer underTest = new CodeMagicAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createBranchConfiguration("branch", projectBranches); + } + + @Test + void shouldReturnPullRequestConfigurationBasedOnPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("CI")).thenReturn("true"); + when(system2.envVariable("FCI_BRANCH")).thenReturn("source"); + when(system2.envVariable("FCI_PULL_REQUEST")).thenReturn("true"); + when(system2.envVariable("FCI_PULL_REQUEST_NUMBER")).thenReturn("id"); + when(system2.envVariable("FCI_PULL_REQUEST_DEST")).thenReturn("target"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createPullRequestConfiguration(any(), any(), any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + CodeMagicAutoConfigurer underTest = new CodeMagicAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createPullRequestConfiguration("id", "source", "target", projectBranches); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GithubActionsAutoConfigurerTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GithubActionsAutoConfigurerTest.java new file mode 100644 index 000000000..54b04d6e1 --- /dev/null +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GithubActionsAutoConfigurerTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.junit.jupiter.api.Test; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class GithubActionsAutoConfigurerTest { + + @Test + void shouldReturnOptionalEmptyIfNotGithubActions() { + System2 system2 = mock(System2.class); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + GithubActionsAutoConfigurer underTest = new GithubActionsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnOptionalEmptyIfGithubActionsWithNoGithubRefProperty() { + System2 system2 = mock(System2.class); + when(system2.envVariable("GITHUB_ACTIONS")).thenReturn("true"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + GithubActionsAutoConfigurer underTest = new GithubActionsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnBranchConfigurationBasedOnNoPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("GITHUB_ACTIONS")).thenReturn("true"); + when(system2.envVariable("GITHUB_REF")).thenReturn("refs/heads/branch"); + when(system2.envVariable("GITHUB_REF_NAME")).thenReturn("branch"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createBranchConfiguration(any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + GithubActionsAutoConfigurer underTest = new GithubActionsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createBranchConfiguration("branch", projectBranches); + } + + @Test + void shouldReturnPullRequestConfigurationBasedOnPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("GITHUB_ACTIONS")).thenReturn("true"); + when(system2.envVariable("GITHUB_HEAD_REF")).thenReturn("source"); + when(system2.envVariable("GITHUB_REF")).thenReturn("refs/pull/id/merge"); + when(system2.envVariable("GITHUB_BASE_REF")).thenReturn("target"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createPullRequestConfiguration(any(), any(), any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + GithubActionsAutoConfigurer underTest = new GithubActionsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createPullRequestConfiguration("id", "source", "target", projectBranches); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GitlabCiAutoConfigurerTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GitlabCiAutoConfigurerTest.java new file mode 100644 index 000000000..4fa565255 --- /dev/null +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/GitlabCiAutoConfigurerTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.junit.jupiter.api.Test; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class GitlabCiAutoConfigurerTest { + + @Test + void shouldReturnOptionalEmptyIfNotGitlabCi() { + System2 system2 = mock(System2.class); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + GitlabCiAutoConfigurer underTest = new GitlabCiAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnBranchConfigurationBasedOnNoPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("GITLAB_CI")).thenReturn("true"); + when(system2.envVariable("CI_COMMIT_REF_NAME")).thenReturn("branch"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createBranchConfiguration(any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + GitlabCiAutoConfigurer underTest = new GitlabCiAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createBranchConfiguration("branch", projectBranches); + } + + @Test + void shouldReturnPullRequestConfigurationBasedOnPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("GITLAB_CI")).thenReturn("true"); + when(system2.envVariable("CI_MERGE_REQUEST_SOURCE_BRANCH_NAME")).thenReturn("source"); + when(system2.envVariable("CI_MERGE_REQUEST_IID")).thenReturn("id"); + when(system2.envVariable("CI_MERGE_REQUEST_TARGET_BRANCH_NAME")).thenReturn("target"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createPullRequestConfiguration(any(), any(), any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + GitlabCiAutoConfigurer underTest = new GitlabCiAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createPullRequestConfiguration("id", "source", "target", projectBranches); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/JenkinsAutoConfigurerTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/JenkinsAutoConfigurerTest.java new file mode 100644 index 000000000..b30a70244 --- /dev/null +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/scanner/autoconfiguration/JenkinsAutoConfigurerTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 Michael Clarke + * + * 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 com.github.mc1arke.sonarqube.plugin.scanner.autoconfiguration; + +import com.github.mc1arke.sonarqube.plugin.scanner.BranchConfigurationFactory; +import org.junit.jupiter.api.Test; +import org.sonar.api.utils.System2; +import org.sonar.scanner.scan.branch.BranchConfiguration; +import org.sonar.scanner.scan.branch.ProjectBranches; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class JenkinsAutoConfigurerTest { + + @Test + void shouldReturnOptionalEmptyIfNotJenkins() { + System2 system2 = mock(System2.class); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + JenkinsAutoConfigurer underTest = new JenkinsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).isEmpty(); + } + + @Test + void shouldReturnBranchConfigurationBasedOnNoPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("JENKINS_HOME")).thenReturn("/path/to/home"); + when(system2.envVariable("BRANCH_NAME")).thenReturn("branch"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createBranchConfiguration(any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + JenkinsAutoConfigurer underTest = new JenkinsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createBranchConfiguration("branch", projectBranches); + } + + @Test + void shouldReturnPullRequestConfigurationBasedOnPrIdInEnvironmentParameters() { + System2 system2 = mock(System2.class); + when(system2.envVariable("JENKINS_HOME")).thenReturn("/path/to/home"); + when(system2.envVariable("CHANGE_BRANCH")).thenReturn("source"); + when(system2.envVariable("CHANGE_ID")).thenReturn("id"); + when(system2.envVariable("CHANGE_TARGET")).thenReturn("target"); + BranchConfigurationFactory branchConfigurationFactory = mock(BranchConfigurationFactory.class); + BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); + when(branchConfigurationFactory.createPullRequestConfiguration(any(), any(), any(), any())).thenReturn(branchConfiguration); + ProjectBranches projectBranches = mock(ProjectBranches.class); + + JenkinsAutoConfigurer underTest = new JenkinsAutoConfigurer(branchConfigurationFactory); + assertThat(underTest.detectConfiguration(system2, projectBranches)).contains(branchConfiguration); + verify(branchConfigurationFactory).createPullRequestConfiguration("id", "source", "target", projectBranches); + } +} \ No newline at end of file