diff options
author | Matteo Mara <matteo.mara@sonarsource.com> | 2023-09-12 11:30:54 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-09-27 20:02:58 +0000 |
commit | 360a4b93d39f94b9fc8aea2aff7dfd37203b5a1b (patch) | |
tree | 97677ee6120b8d31b1694e5e63e467956c59f6d4 /server | |
parent | 319abd794487e6e17eb2b08ca9ac266cbb16c66a (diff) | |
download | sonarqube-360a4b93d39f94b9fc8aea2aff7dfd37203b5a1b.tar.gz sonarqube-360a4b93d39f94b9fc8aea2aff7dfd37203b5a1b.zip |
SONAR-20442 Add new extension point before measure calculation
Diffstat (limited to 'server')
4 files changed, 242 insertions, 0 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/PreMeasuresComputationCheck.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/PreMeasuresComputationCheck.java new file mode 100644 index 00000000000..909514b9d3f --- /dev/null +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/PreMeasuresComputationCheck.java @@ -0,0 +1,50 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.ce.task.projectanalysis.measure; + +import org.sonar.api.ExtensionPoint; +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.ce.task.projectanalysis.analysis.Branch; + +/** + * Extension point that is called during processing of a task + * by {@link PreMeasuresComputationChecksStep}. + * + * It is stateless, the same instance is reused for all tasks. + * As a consequence Compute Engine task components can't be injected + * as dependencies. + */ +@ComputeEngineSide +@ExtensionPoint +public interface PreMeasuresComputationCheck { + + /** + * This method can make the task fail by throwing a {@link RuntimeException} + */ + void onCheck(Context context); + + interface Context { + + String getProjectUuid(); + + Branch getBranch(); + + } +} diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/PreMeasuresComputationChecksStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/PreMeasuresComputationChecksStep.java new file mode 100644 index 00000000000..79257403306 --- /dev/null +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/PreMeasuresComputationChecksStep.java @@ -0,0 +1,69 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.ce.task.projectanalysis.measure; + +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder; +import org.sonar.ce.task.projectanalysis.analysis.Branch; +import org.sonar.ce.task.step.ComputationStep; + +/** + * Execute {@link PreMeasuresComputationCheck} instances in no specific order. + * If an extension fails (throws an exception), consecutive extensions + * won't be called. + */ +@ComputeEngineSide +public class PreMeasuresComputationChecksStep implements ComputationStep { + + private final AnalysisMetadataHolder analysisMetadataHolder; + private final PreMeasuresComputationCheck[] extensions; + + public PreMeasuresComputationChecksStep(AnalysisMetadataHolder analysisMetadataHolder, PreMeasuresComputationCheck... extensions) { + this.analysisMetadataHolder = analysisMetadataHolder; + this.extensions = extensions; + } + + @Override + public void execute(Context context) { + PreMeasuresComputationCheck.Context extensionContext = new ContextImpl(); + for (PreMeasuresComputationCheck extension : extensions) { + extension.onCheck(extensionContext); + } + } + + @Override + public String getDescription() { + return "Checks executed before computation of measures"; + } + + private class ContextImpl implements PreMeasuresComputationCheck.Context { + + @Override + public String getProjectUuid() { + return analysisMetadataHolder.getProject().getUuid(); + } + + @Override + public Branch getBranch() { + return analysisMetadataHolder.getBranch(); + } + + } +} diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java index 6432f2a3aef..731935a5425 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java @@ -26,6 +26,7 @@ import org.sonar.ce.task.projectanalysis.filemove.FileMoveDetectionStep; import org.sonar.ce.task.projectanalysis.filemove.PullRequestFileMoveDetectionStep; import org.sonar.ce.task.projectanalysis.language.HandleUnanalyzedLanguagesStep; import org.sonar.ce.task.projectanalysis.measure.PostMeasuresComputationChecksStep; +import org.sonar.ce.task.projectanalysis.measure.PreMeasuresComputationChecksStep; import org.sonar.ce.task.projectanalysis.purge.PurgeDatastoresStep; import org.sonar.ce.task.projectanalysis.qualityprofile.RegisterQualityProfileStatusStep; import org.sonar.ce.task.projectanalysis.source.PersistFileSourcesStep; @@ -50,6 +51,9 @@ public class ReportComputationSteps extends AbstractComputationSteps { ValidateProjectStep.class, LoadQualityProfilesStep.class, + // Pre analysis operations + PreMeasuresComputationChecksStep.class, + // load project related stuffs LoadFileHashesAndStatusStep.class, LoadQualityGateStep.class, diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/PreMeasuresComputationChecksStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/PreMeasuresComputationChecksStepTest.java new file mode 100644 index 00000000000..5f2481025f0 --- /dev/null +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/PreMeasuresComputationChecksStepTest.java @@ -0,0 +1,119 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.ce.task.projectanalysis.measure; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule; +import org.sonar.ce.task.projectanalysis.analysis.Branch; +import org.sonar.ce.task.projectanalysis.measure.PreMeasuresComputationCheck.Context; +import org.sonar.ce.task.step.TestComputationStepContext; +import org.sonar.db.component.BranchType; +import org.sonar.server.project.Project; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; + +public class PreMeasuresComputationChecksStepTest { + + public AnalysisMetadataHolderRule analysisMetadataHolder = mock(AnalysisMetadataHolderRule.class); + + @Test + public void execute_extensions() { + PreMeasuresComputationCheck check1 = mock(PreMeasuresComputationCheck.class); + PreMeasuresComputationCheck check2 = mock(PreMeasuresComputationCheck.class); + + newStep(check1, check2).execute(new TestComputationStepContext()); + + InOrder inOrder = inOrder(check1, check2); + inOrder.verify(check1).onCheck(any(Context.class)); + inOrder.verify(check2).onCheck(any(Context.class)); + } + + @Test + public void context_contains_project_uuid_from_analysis_metadata_holder() { + Project project = Project.from(newPrivateProjectDto()); + when(analysisMetadataHolder.getProject()).thenReturn(project); + PreMeasuresComputationCheck check = mock(PreMeasuresComputationCheck.class); + + newStep(check).execute(new TestComputationStepContext()); + + ArgumentCaptor<Context> contextArgumentCaptor = ArgumentCaptor.forClass(Context.class); + verify(check).onCheck(contextArgumentCaptor.capture()); + assertThat(contextArgumentCaptor.getValue().getProjectUuid()).isEqualTo(project.getUuid()); + } + + @Test + public void context_contains_pullRequest_key_from_analysis_metadata_holder() { + mockPr("pr1"); + PreMeasuresComputationCheck check = mock(PreMeasuresComputationCheck.class); + + newStep(check).execute(new TestComputationStepContext()); + + ArgumentCaptor<Context> contextArgumentCaptor = ArgumentCaptor.forClass(Context.class); + verify(check).onCheck(contextArgumentCaptor.capture()); + assertThat(contextArgumentCaptor.getValue().getBranch().getPullRequestKey()).isEqualTo("pr1"); + } + + @Test + public void context_contains_branch_from_analysis_metadata_holder() { + mockBranch("branchName"); + PreMeasuresComputationCheck check = mock(PreMeasuresComputationCheck.class); + + newStep(check).execute(new TestComputationStepContext()); + + ArgumentCaptor<Context> contextArgumentCaptor = ArgumentCaptor.forClass(Context.class); + verify(check).onCheck(contextArgumentCaptor.capture()); + assertThat(contextArgumentCaptor.getValue().getBranch().getName()).isEqualTo("branchName"); + } + + @Test + public void test_getDescription() { + assertThat(newStep().getDescription()).isNotEmpty(); + } + + private PreMeasuresComputationChecksStep newStep(PreMeasuresComputationCheck... preMeasuresComputationChecks) { + if (preMeasuresComputationChecks.length == 0) { + return new PreMeasuresComputationChecksStep(analysisMetadataHolder); + } + return new PreMeasuresComputationChecksStep(analysisMetadataHolder, preMeasuresComputationChecks); + } + + private void mockBranch(String branchName) { + Branch branch = mock(Branch.class); + when(branch.getName()).thenReturn(branchName); + when(branch.getType()).thenReturn(BranchType.BRANCH); + when(analysisMetadataHolder.getBranch()).thenReturn(branch); + } + + private void mockPr(String pullRequestKey) { + Branch branch = mock(Branch.class); + when(branch.getType()).thenReturn(BranchType.PULL_REQUEST); + when(branch.getPullRequestKey()).thenReturn(pullRequestKey); + when(analysisMetadataHolder.getBranch()).thenReturn(branch); + } + +} |