diff options
author | Benjamin Campomenosi <benjamin.campomenosi@sonarsource.com> | 2022-12-20 17:33:54 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-12-28 20:02:48 +0000 |
commit | 1eb320deeb1981d572f50645163795f3786f2845 (patch) | |
tree | 5de723b74364a898100093d3d360e0004e6046f0 | |
parent | d023db004a914ab40a9d7caaaa40d901433a018b (diff) | |
download | sonarqube-1eb320deeb1981d572f50645163795f3786f2845.tar.gz sonarqube-1eb320deeb1981d572f50645163795f3786f2845.zip |
SONAR-17610 Backend documentation links targets https://docs.sonarqube.org/ instead of embedded doc
11 files changed, 217 insertions, 35 deletions
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index 847bc10c2dc..1dd7307f102 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -66,6 +66,7 @@ import org.sonar.ce.taskprocessor.CeProcessingScheduler; import org.sonar.ce.taskprocessor.CeTaskProcessorModule; import org.sonar.core.component.DefaultResourceTypes; import org.sonar.core.config.CorePropertyDefinitions; +import org.sonar.core.documentation.DefaultDocumentationLinkGenerator; import org.sonar.core.extension.CoreExtensionRepositoryImpl; import org.sonar.core.extension.CoreExtensionsLoader; import org.sonar.core.language.LanguagesProvider; @@ -451,7 +452,9 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { QualityGateFinder.class, QualityGateEvaluatorImpl.class, - new AnalysisCacheCleaningModule() + new AnalysisCacheCleaningModule(), + + DefaultDocumentationLinkGenerator.class ); diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index a57f28666b7..587d180255a 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -49,6 +49,7 @@ import org.sonar.ce.task.projectanalysis.taskprocessor.IssueSyncTaskProcessor; import org.sonar.ce.task.projectanalysis.taskprocessor.ReportTaskProcessor; import org.sonar.ce.task.projectexport.taskprocessor.ProjectExportTaskProcessor; import org.sonar.core.component.DefaultResourceTypes; +import org.sonar.core.documentation.DefaultDocumentationLinkGenerator; import org.sonar.core.extension.CoreExtensionsInstaller; import org.sonar.core.language.LanguagesProvider; import org.sonar.core.platform.PlatformEditionProvider; @@ -300,6 +301,7 @@ public class PlatformLevel4 extends PlatformLevel { WebAnalyticsLoaderImpl.class, new MonitoringWsModule(), DefaultBranchNameResolver.class, + DefaultDocumentationLinkGenerator.class, // batch new BatchWsModule(), diff --git a/sonar-core/src/main/java/org/sonar/core/documentation/DefaultDocumentationLinkGenerator.java b/sonar-core/src/main/java/org/sonar/core/documentation/DefaultDocumentationLinkGenerator.java new file mode 100644 index 00000000000..148ef8353d1 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/documentation/DefaultDocumentationLinkGenerator.java @@ -0,0 +1,41 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.core.documentation; + +import java.util.Optional; +import javax.annotation.Nullable; +import org.sonar.api.utils.Version; +import org.sonar.core.platform.SonarQubeVersion; + +public class DefaultDocumentationLinkGenerator implements DocumentationLinkGenerator { + private static final String DOCUMENTATION_PUBLIC_URL = "https://docs.sonarqube.org/"; + + private final String documentationBaseUrl; + + public DefaultDocumentationLinkGenerator(SonarQubeVersion sonarQubeVersion) { + Version version = sonarQubeVersion.get(); + this.documentationBaseUrl = DOCUMENTATION_PUBLIC_URL + version.major() + "." + version.minor(); + } + + @Override + public String getDocumentationLink(@Nullable String suffix) { + return documentationBaseUrl + Optional.ofNullable(suffix).orElse(""); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/documentation/DocumentationLinkGenerator.java b/sonar-core/src/main/java/org/sonar/core/documentation/DocumentationLinkGenerator.java new file mode 100644 index 00000000000..fb262e2404c --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/documentation/DocumentationLinkGenerator.java @@ -0,0 +1,34 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.core.documentation; + +import javax.annotation.Nullable; +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.api.scanner.ScannerSide; +import org.sonar.api.server.ServerSide; + +@ServerSide +@ComputeEngineSide +@ScannerSide +public interface DocumentationLinkGenerator { + + String getDocumentationLink(@Nullable String suffix); + +} diff --git a/sonar-core/src/test/java/org/sonar/core/documentation/DefaultDocumentationLinkGeneratorTest.java b/sonar-core/src/test/java/org/sonar/core/documentation/DefaultDocumentationLinkGeneratorTest.java new file mode 100644 index 00000000000..9926bb2abce --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/documentation/DefaultDocumentationLinkGeneratorTest.java @@ -0,0 +1,62 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.core.documentation; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.sonar.core.platform.SonarQubeVersion; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class DefaultDocumentationLinkGeneratorTest { + private static final String TEST_SUFFIX = "/documentation/analyzing-source-code/scm-integration/"; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private SonarQubeVersion sonarQubeVersion; + + private DefaultDocumentationLinkGenerator documentationLinkGenerator; + + @Before + public void setUp() { + when(sonarQubeVersion.get().major()).thenReturn(100); + when(sonarQubeVersion.get().minor()).thenReturn(1000); + documentationLinkGenerator = new DefaultDocumentationLinkGenerator(sonarQubeVersion); + } + + @Test + public void getDocumentationLink_whenSuffixProvided_concatenatesIt() { + String generatedLink = documentationLinkGenerator.getDocumentationLink(TEST_SUFFIX); + + assertThat(generatedLink).isEqualTo("https://docs.sonarqube.org/100.1000/documentation/analyzing-source-code/scm-integration/"); + } + + @Test + public void getDocumentationLink_whenSuffixNotProvided_returnsBaseUrl() { + String generatedLink = documentationLinkGenerator.getDocumentationLink(null); + + assertThat(generatedLink).isEqualTo("https://docs.sonarqube.org/100.1000"); + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java index 78be7024302..02ec64c891c 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java @@ -36,6 +36,7 @@ import org.sonar.api.utils.UriReader; import org.sonar.api.utils.Version; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; +import org.sonar.core.documentation.DefaultDocumentationLinkGenerator; import org.sonar.core.extension.CoreExtensionRepositoryImpl; import org.sonar.core.extension.CoreExtensionsLoader; import org.sonar.core.platform.PluginClassLoader; @@ -96,6 +97,7 @@ public class SpringGlobalContainer extends SpringComponentContainer { new GlobalConfigurationProvider(), new ScannerWsClientProvider(), DefaultServer.class, + DefaultDocumentationLinkGenerator.class, new GlobalTempFolderProvider(), analysisWarnings, UriReader.class, diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/DefaultBlameOutput.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/DefaultBlameOutput.java index d7d512da5b1..d821f809047 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/DefaultBlameOutput.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/DefaultBlameOutput.java @@ -19,6 +19,7 @@ */ package org.sonar.scanner.scm; +import com.google.common.annotations.VisibleForTesting; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; @@ -35,27 +36,34 @@ import org.sonar.api.batch.scm.BlameLine; import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; +import org.sonar.core.documentation.DocumentationLinkGenerator; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Builder; import org.sonar.scanner.protocol.output.ScannerReportWriter; import org.sonar.scanner.util.ProgressReport; +import static java.lang.String.format; import static org.sonar.api.utils.Preconditions.checkArgument; class DefaultBlameOutput implements BlameOutput { private static final Logger LOG = Loggers.get(DefaultBlameOutput.class); + @VisibleForTesting + static final String SCM_INTEGRATION_DOCUMENTATION_SUFFIX = "/analyzing-source-code/scm-integration/"; private final ScannerReportWriter writer; private AnalysisWarnings analysisWarnings; + private final DocumentationLinkGenerator documentationLinkGenerator; private final Set<InputFile> allFilesToBlame = new LinkedHashSet<>(); private ProgressReport progressReport; private int count; private int total; - DefaultBlameOutput(ScannerReportWriter writer, AnalysisWarnings analysisWarnings, List<InputFile> filesToBlame) { + DefaultBlameOutput(ScannerReportWriter writer, AnalysisWarnings analysisWarnings, List<InputFile> filesToBlame, + DocumentationLinkGenerator documentationLinkGenerator) { this.writer = writer; this.analysisWarnings = analysisWarnings; + this.documentationLinkGenerator = documentationLinkGenerator; this.allFilesToBlame.addAll(filesToBlame); count = 0; total = filesToBlame.size(); @@ -134,12 +142,12 @@ class DefaultBlameOutput implements BlameOutput { LOG.warn(" * " + f); } LOG.warn("This may lead to missing/broken features in SonarQube"); - String link = "/documentation/analyzing-source-code/scm-integration/"; - analysisWarnings.addUnique(String.format("Missing blame information for %d %s. This may lead to some features not working correctly. " + - "Please check the analysis logs and refer to <a href=\"%s\" target=\"_blank\">the documentation</a>.", + String docUrl = documentationLinkGenerator.getDocumentationLink(SCM_INTEGRATION_DOCUMENTATION_SUFFIX); + analysisWarnings.addUnique(format("Missing blame information for %d %s. This may lead to some features not working correctly. " + + "Please check the analysis logs and refer to <a href=\"%s\" rel=\"noopener noreferrer\" target=\"_blank\">the documentation</a>.", allFilesToBlame.size(), allFilesToBlame.size() > 1 ? "files" : "file", - link)); + docUrl)); } } @@ -147,3 +155,4 @@ class DefaultBlameOutput implements BlameOutput { return filesCount == 1 ? "source file" : "source files"; } } + diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java index e773c0d3bcf..fd24e4b4052 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java @@ -31,6 +31,7 @@ import org.sonar.api.batch.scm.ScmProvider; import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; +import org.sonar.core.documentation.DocumentationLinkGenerator; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Builder; import org.sonar.scanner.protocol.output.ScannerReportWriter; @@ -49,11 +50,12 @@ public final class ScmPublisher { private final InputComponentStore componentStore; private final FileSystem fs; private final ScannerReportWriter writer; - private AnalysisWarnings analysisWarnings; + private final AnalysisWarnings analysisWarnings; private final BranchConfiguration branchConfiguration; + private final DocumentationLinkGenerator documentationLinkGenerator; public ScmPublisher(ScmConfiguration configuration, ProjectRepositories projectRepositories, InputComponentStore componentStore, FileSystem fs, - ReportPublisher reportPublisher, BranchConfiguration branchConfiguration, AnalysisWarnings analysisWarnings) { + ReportPublisher reportPublisher, BranchConfiguration branchConfiguration, AnalysisWarnings analysisWarnings, DocumentationLinkGenerator documentationLinkGenerator) { this.configuration = configuration; this.projectRepositories = projectRepositories; this.componentStore = componentStore; @@ -61,6 +63,7 @@ public final class ScmPublisher { this.branchConfiguration = branchConfiguration; this.writer = reportPublisher.getWriter(); this.analysisWarnings = analysisWarnings; + this.documentationLinkGenerator = documentationLinkGenerator; } public void publish() { @@ -79,7 +82,7 @@ public final class ScmPublisher { if (!filesToBlame.isEmpty()) { String key = provider.key(); LOG.info("SCM Publisher SCM provider for this project is: " + key); - DefaultBlameOutput output = new DefaultBlameOutput(writer, analysisWarnings, filesToBlame); + DefaultBlameOutput output = new DefaultBlameOutput(writer, analysisWarnings, filesToBlame, documentationLinkGenerator); try { provider.blameCommand().blame(new DefaultBlameInput(fs, filesToBlame), output); } catch (Exception e) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scm/git/GitScmProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scm/git/GitScmProvider.java index aec033458e7..817f2370d04 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scm/git/GitScmProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scm/git/GitScmProvider.java @@ -19,6 +19,7 @@ */ package org.sonar.scm.git; +import com.google.common.annotations.VisibleForTesting; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; @@ -69,6 +70,7 @@ 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.documentation.DocumentationLinkGenerator; import static java.lang.String.format; import static java.util.function.Function.identity; @@ -84,18 +86,22 @@ public class GitScmProvider extends ScmProvider { private static final Logger LOG = Loggers.get(GitScmProvider.class); private static final String COULD_NOT_FIND_REF = "Could not find ref '%s' in refs/heads, refs/remotes, refs/remotes/upstream or refs/remotes/origin"; private static final String NO_MERGE_BASE_FOUND_MESSAGE = "No merge base found between HEAD and %s"; + @VisibleForTesting + static final String SCM_INTEGRATION_DOCUMENTATION_SUFFIX = "/analyzing-source-code/scm-integration/"; private final BlameCommand blameCommand; private final AnalysisWarnings analysisWarnings; private final GitIgnoreCommand gitIgnoreCommand; private final System2 system2; - private final String documentationLink; + private final DocumentationLinkGenerator documentationLinkGenerator; + + public GitScmProvider(CompositeBlameCommand blameCommand, AnalysisWarnings analysisWarnings, GitIgnoreCommand gitIgnoreCommand, System2 system2, + DocumentationLinkGenerator documentationLinkGenerator) { - public GitScmProvider(CompositeBlameCommand blameCommand, AnalysisWarnings analysisWarnings, GitIgnoreCommand gitIgnoreCommand, System2 system2) { this.blameCommand = blameCommand; this.analysisWarnings = analysisWarnings; this.gitIgnoreCommand = gitIgnoreCommand; this.system2 = system2; - this.documentationLink = "/documentation/analyzing-source-code/scm-integration/"; + this.documentationLinkGenerator = documentationLinkGenerator; } @Override @@ -257,10 +263,11 @@ public class GitScmProvider extends ScmProvider { } private void addWarningTargetNotFound(String targetBranchName) { + String url = documentationLinkGenerator.getDocumentationLink(SCM_INTEGRATION_DOCUMENTATION_SUFFIX); analysisWarnings.addUnique(format(COULD_NOT_FIND_REF + ". You may see unexpected issues and changes. " + "Please make sure to fetch this ref before pull request analysis and refer to" - + " <a href=\"%s\" target=\"_blank\">the documentation</a>.", targetBranchName, documentationLink)); + + " <a href=\"%s\" rel=\"noopener noreferrer\" target=\"_blank\">the documentation</a>.", targetBranchName, url)); } private void collectChangedLines(Repository repo, RevCommit mergeBaseCommit, Map<Path, Set<Integer>> changedLines, Path changedFilePath, ChangedFile changedFile) { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/DefaultBlameOutputTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/DefaultBlameOutputTest.java index 5e1972b4b80..9fc3d7104f5 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/DefaultBlameOutputTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/DefaultBlameOutputTest.java @@ -25,39 +25,58 @@ import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.batch.scm.BlameLine; import org.sonar.api.utils.System2; +import org.sonar.core.documentation.DocumentationLinkGenerator; import org.sonar.scanner.notifications.DefaultAnalysisWarnings; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.scanner.scm.DefaultBlameOutput.SCM_INTEGRATION_DOCUMENTATION_SUFFIX; public class DefaultBlameOutputTest { + private static final String DOC_LINK = "https://link.to.documentation/new/page"; private System2 system2 = mock(System2.class); private DefaultAnalysisWarnings analysisWarnings = new DefaultAnalysisWarnings(system2); + private DocumentationLinkGenerator documentationLinkGenerator = mock(DocumentationLinkGenerator.class); @Test public void shouldNotFailIfNotSameNumberOfLines() { InputFile file = new TestInputFileBuilder("foo", "src/main/java/Foo.java").setLines(10).build(); - new DefaultBlameOutput(null, analysisWarnings, singletonList(file)).blameResult(file, singletonList(new BlameLine().revision("1").author("guy"))); + new DefaultBlameOutput(null, analysisWarnings, singletonList(file), mock(DocumentationLinkGenerator.class)).blameResult(file, + singletonList(new BlameLine().revision("1").author("guy"))); } @Test public void addWarningIfFilesMissing() { + when(documentationLinkGenerator.getDocumentationLink(SCM_INTEGRATION_DOCUMENTATION_SUFFIX)).thenReturn(DOC_LINK); InputFile file = new TestInputFileBuilder("foo", "src/main/java/Foo.java").setLines(10).build(); - new DefaultBlameOutput(null, analysisWarnings, singletonList(file)).finish(true); + new DefaultBlameOutput(null, analysisWarnings, singletonList(file), documentationLinkGenerator).finish(true); assertThat(analysisWarnings.warnings()).extracting(DefaultAnalysisWarnings.Message::getText) .containsOnly("Missing blame information for 1 file. This may lead to some features not working correctly. " + - "Please check the analysis logs and refer to <a href=\"/documentation/analyzing-source-code/scm-integration/\" target=\"_blank\">the documentation</a>."); + "Please check the analysis logs and refer to <a href=\"" + DOC_LINK + "\" rel=\"noopener noreferrer\" target=\"_blank\">the documentation</a>."); + } + + @Test + public void addWarningWithContextIfFiles() { + when(documentationLinkGenerator.getDocumentationLink(SCM_INTEGRATION_DOCUMENTATION_SUFFIX)).thenReturn(DOC_LINK); + InputFile file = new TestInputFileBuilder("foo", "src/main/java/Foo.java").setLines(10).build(); + when(documentationLinkGenerator.getDocumentationLink("suffix")).thenReturn("blababl"); + new DefaultBlameOutput(null, analysisWarnings, singletonList(file), documentationLinkGenerator).finish(true); + assertThat(analysisWarnings.warnings()).extracting(DefaultAnalysisWarnings.Message::getText) + .containsOnly("Missing blame information for 1 file. This may lead to some features not working correctly. " + + "Please check the analysis logs and refer to <a href=\"" + DOC_LINK + "\" rel=\"noopener noreferrer\" target=\"_blank\">the documentation</a>."); } @Test public void shouldFailIfNotExpectedFile() { InputFile file = new TestInputFileBuilder("foo", "src/main/java/Foo.java").build(); var blameOutput = new DefaultBlameOutput(null, analysisWarnings, - singletonList(new TestInputFileBuilder("foo", "src/main/java/Foo2.java").build())); + singletonList(new TestInputFileBuilder("foo", "src/main/java/Foo2.java").build()), + mock(DocumentationLinkGenerator.class)); var lines = singletonList(new BlameLine().revision("1").author("guy")); assertThatThrownBy(() -> blameOutput.blameResult(file, lines)) @@ -68,7 +87,7 @@ public class DefaultBlameOutputTest { @Test public void shouldFailIfNullDate() { InputFile file = new TestInputFileBuilder("foo", "src/main/java/Foo.java").setLines(1).build(); - var blameOutput = new DefaultBlameOutput(null, analysisWarnings, singletonList(file)); + var blameOutput = new DefaultBlameOutput(null, analysisWarnings, singletonList(file), mock(DocumentationLinkGenerator.class)); var lines = singletonList(new BlameLine().revision("1").author("guy")); assertThatThrownBy(() -> blameOutput.blameResult(file, lines)) @@ -79,7 +98,7 @@ public class DefaultBlameOutputTest { @Test public void shouldFailIfNullRevision() { InputFile file = new TestInputFileBuilder("foo", "src/main/java/Foo.java").setLines(1).build(); - var blameOUtput = new DefaultBlameOutput(null, analysisWarnings, singletonList(file)); + var blameOUtput = new DefaultBlameOutput(null, analysisWarnings, singletonList(file), mock(DocumentationLinkGenerator.class)); var lines = singletonList(new BlameLine().date(new Date()).author("guy")); assertThatThrownBy(() -> blameOUtput.blameResult(file, lines)) diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scm/git/GitScmProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scm/git/GitScmProviderTest.java index e8e2d7bcebe..186677e7df4 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scm/git/GitScmProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scm/git/GitScmProviderTest.java @@ -60,6 +60,7 @@ import org.sonar.api.utils.MessageException; import org.sonar.api.utils.System2; import org.sonar.api.utils.log.LogAndArguments; import org.sonar.api.utils.log.LogTester; +import org.sonar.core.documentation.DocumentationLinkGenerator; import static java.lang.String.format; import static java.util.Collections.emptySet; @@ -74,6 +75,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import static org.sonar.api.utils.log.LoggerLevel.WARN; +import static org.sonar.scm.git.GitScmProvider.SCM_INTEGRATION_DOCUMENTATION_SUFFIX; import static org.sonar.scm.git.GitUtils.createFile; import static org.sonar.scm.git.GitUtils.createRepository; import static org.sonar.scm.git.Utils.javaUnzip; @@ -109,6 +111,7 @@ public class GitScmProviderTest { + "The door of all subtleties!"; private static final String BRANCH_NAME = "branch"; + private static final String TEST_DOC_LINK = "documentation link"; @Rule public TemporaryFolder temp = new TemporaryFolder(); @@ -123,11 +126,13 @@ public class GitScmProviderTest { private Path worktree; private Git git; private final AnalysisWarnings analysisWarnings = mock(AnalysisWarnings.class); + private final DocumentationLinkGenerator documentationLinkGenerator = mock(DocumentationLinkGenerator.class); @Before public void before() throws IOException, GitAPIException { worktree = temp.newFolder().toPath(); git = createRepository(worktree); + when(documentationLinkGenerator.getDocumentationLink(SCM_INTEGRATION_DOCUMENTATION_SUFFIX)).thenReturn(TEST_DOC_LINK); createAndCommitFile("file-in-first-commit.xoo"); } @@ -142,7 +147,7 @@ public class GitScmProviderTest { JGitBlameCommand jblameCommand = new JGitBlameCommand(); GitBlameCommand nativeBlameCommand = new GitBlameCommand(System2.INSTANCE, new ProcessWrapperFactory()); CompositeBlameCommand compositeBlameCommand = new CompositeBlameCommand(analysisWarnings, new PathResolver(), jblameCommand, nativeBlameCommand); - GitScmProvider gitScmProvider = new GitScmProvider(compositeBlameCommand, analysisWarnings, gitIgnoreCommand, system2); + GitScmProvider gitScmProvider = new GitScmProvider(compositeBlameCommand, analysisWarnings, gitIgnoreCommand, system2, documentationLinkGenerator); assertThat(gitScmProvider.blameCommand()).isEqualTo(compositeBlameCommand); } @@ -419,7 +424,8 @@ public class GitScmProviderTest { } @Test - public void branchChangedLinesWithFileMovementDetection_detects_modified_lines_on_renamed_pr_files_compared_to_original_files_on_target_branch() throws GitAPIException, IOException { + public void branchChangedLinesWithFileMovementDetection_detects_modified_lines_on_renamed_pr_files_compared_to_original_files_on_target_branch() + throws GitAPIException, IOException { String fileM1 = "file-m1.xoo"; String newFileM1 = "new-file-m1.xoo"; String fileM2 = "file-m2.xoo"; @@ -616,7 +622,7 @@ public class GitScmProviderTest { @Test public void branchChangedFiles_should_return_null_on_io_errors_of_repo_builder() { - GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2) { + GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2, documentationLinkGenerator) { @Override Repository buildRepo(Path basedir) throws IOException { throw new IOException(); @@ -633,7 +639,7 @@ public class GitScmProviderTest { when(repository.getRefDatabase()).thenReturn(refDatabase); when(refDatabase.findRef(BRANCH_NAME)).thenReturn(null); - GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2) { + GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2, documentationLinkGenerator) { @Override Repository buildRepo(Path basedir) { return repository; @@ -648,7 +654,7 @@ public class GitScmProviderTest { String warning = refNotFound + ". You may see unexpected issues and changes. Please make sure to fetch this ref before pull request analysis" - + " and refer to <a href=\"/documentation/analyzing-source-code/scm-integration/\" target=\"_blank\">the documentation</a>."; + + " and refer to <a href=\"" + TEST_DOC_LINK + "\" rel=\"noopener noreferrer\" target=\"_blank\">the documentation</a>."; verify(analysisWarnings).addUnique(warning); } @@ -663,7 +669,7 @@ public class GitScmProviderTest { Git git = mock(Git.class); when(git.diff()).thenReturn(diffCommand); - GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2) { + GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2, documentationLinkGenerator) { @Override Git newGit(Repository repo) { return git; @@ -700,7 +706,7 @@ public class GitScmProviderTest { commit(f3); AtomicInteger callCount = new AtomicInteger(0); - GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2) { + GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2, documentationLinkGenerator) { @Override AbstractTreeIterator prepareTreeParser(Repository repo, RevCommit commit) throws IOException { if (callCount.getAndIncrement() == 2) { @@ -721,7 +727,7 @@ public class GitScmProviderTest { @Test public void branchChangedLines_returns_null_on_io_errors_of_repo_builder() { - GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2) { + GitScmProvider provider = new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2, documentationLinkGenerator) { @Override Repository buildRepo(Path basedir) throws IOException { throw new IOException(); @@ -736,7 +742,7 @@ public class GitScmProviderTest { } private GitScmProvider newGitScmProvider() { - return new GitScmProvider(mock(CompositeBlameCommand.class), analysisWarnings, gitIgnoreCommand, system2); + return new GitScmProvider(mock(CompositeBlameCommand.class), analysisWarnings, gitIgnoreCommand, system2, documentationLinkGenerator); } @Test @@ -814,12 +820,6 @@ public class GitScmProviderTest { createAndCommitFile(relativePath, randomizedContent(relativePath, 3), git, this.worktree); } - private void createAndCommitFile(String relativePath, Instant commitDate) throws IOException, GitAPIException { - createFile(relativePath, randomizedContent(relativePath, 3), this.worktree); - commit(relativePath, commitDate); - } - - private void createAndCommitFile(String fileName, Git git, Path worktree) throws IOException, GitAPIException { createAndCommitFile(fileName, randomizedContent(fileName, 3), git, worktree); } @@ -896,6 +896,6 @@ public class GitScmProviderTest { } private GitScmProvider newScmProvider() { - return new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2); + return new GitScmProvider(mockCommand(), analysisWarnings, gitIgnoreCommand, system2, documentationLinkGenerator); } } |