1
0
mirror of https://github.com/mc1arke/sonarqube-community-branch-plugin.git synced 2025-10-08 22:52:13 +02:00

#1115: Differentiate Gitlab pipelines on monorepos

The Gitlab decorator used a constant name for the pipeline which meant
the last executed pipeline in a monorepo may allow a Merge Request to be
marked as successful even if other projects in the repository had failed
their pipelines. To overcome this the decorator has been altered to
include the project key in the pipeline name if the project is a
monorepo to ensure that the pipeline is unique across all projects in
the monorepo.
This commit is contained in:
Michael Clarke
2025-09-18 17:08:25 +01:00
committed by Michael Clarke
parent 7085d58013
commit 9e5caf732b
4 changed files with 31 additions and 14 deletions

View File

@@ -111,7 +111,7 @@ public abstract class DiscussionAwarePullRequestDecorator<C, P, U, D, N> impleme
AnalysisSummary analysisSummary = reportGenerator.createAnalysisSummary(analysis);
submitSummaryNote(client, pullRequest, analysis, analysisSummary);
submitPipelineStatus(client, pullRequest, analysis, analysisSummary);
submitPipelineStatus(client, pullRequest, analysis, analysisSummary, projectAlmSettingDto);
DecorationResult.Builder builder = DecorationResult.builder();
createFrontEndUrl(pullRequest, analysis).ifPresent(builder::withPullRequestUrl);
@@ -130,7 +130,7 @@ public abstract class DiscussionAwarePullRequestDecorator<C, P, U, D, N> impleme
protected abstract List<String> getCommitIdsForPullRequest(C client, P pullRequest);
protected abstract void submitPipelineStatus(C client, P pullRequest, AnalysisDetails analysis, AnalysisSummary analysisSummary);
protected abstract void submitPipelineStatus(C client, P pullRequest, AnalysisDetails analysis, AnalysisSummary analysisSummary, ProjectAlmSettingDto projectAlmSettingDto);
protected abstract void submitCommitNoteForIssue(C client, P pullRequest, PostAnalysisIssueVisitor.ComponentIssue issue, String filePath,
AnalysisDetails analysis, AnalysisIssueSummary analysisIssueSummary);

View File

@@ -144,7 +144,7 @@ public class AzureDevOpsPullRequestDecorator extends DiscussionAwarePullRequestD
}
@Override
protected void submitPipelineStatus(AzureDevopsClient client, PullRequest pullRequest, AnalysisDetails analysis, AnalysisSummary analysisSummary) {
protected void submitPipelineStatus(AzureDevopsClient client, PullRequest pullRequest, AnalysisDetails analysis, AnalysisSummary analysisSummary, ProjectAlmSettingDto projectAlmSettingDto) {
try {
GitPullRequestStatus gitPullRequestStatus = new GitPullRequestStatus(
GitStatusStateMapper.toGitStatusState(analysis.getQualityGateStatus()),

View File

@@ -122,14 +122,15 @@ public class GitlabMergeRequestDecorator extends DiscussionAwarePullRequestDecor
@Override
protected void submitPipelineStatus(GitlabClient gitlabClient, MergeRequest mergeRequest, AnalysisDetails analysis,
AnalysisSummary analysisSummary) {
AnalysisSummary analysisSummary, ProjectAlmSettingDto projectAlmSettingDto) {
Long pipelineId = analysis.getScannerProperty(PULLREQUEST_GITLAB_PIPELINE_ID)
.map(Long::parseLong)
.orElse(null);
try {
PipelineStatus pipelineStatus = new PipelineStatus("SonarQube",
"SonarQube Status",
boolean isMonorepo = Boolean.TRUE.equals(projectAlmSettingDto.getMonorepo());
PipelineStatus pipelineStatus = new PipelineStatus("SonarQube" + (isMonorepo ? " - " + analysis.getAnalysisProjectKey() : ""),
"SonarQube Status" + (isMonorepo ? " - " + analysis.getAnalysisProjectName() : ""),
analysis.getQualityGateStatus() == QualityGate.Status.OK ? PipelineStatus.State.SUCCESS : PipelineStatus.State.FAILED,
analysisSummary.getDashboardUrl(),
analysisSummary.getNewCoverage(),

View File

@@ -73,20 +73,21 @@ class GitlabMergeRequestDecoratorIntegrationTest {
@Test
void decorateQualityGateStatusOk() {
decorateQualityGateStatus(QualityGate.Status.OK);
decorateQualityGateStatus(QualityGate.Status.OK, false);
}
@Test
void decorateQualityGateStatusError() {
decorateQualityGateStatus(QualityGate.Status.ERROR);
decorateQualityGateStatus(QualityGate.Status.ERROR, true);
}
private void decorateQualityGateStatus(QualityGate.Status status) {
private void decorateQualityGateStatus(QualityGate.Status status, boolean isMonorepo) {
String user = "sonar_user";
String repositorySlug = "repo/slug";
String commitSha = "commitSha";
long mergeRequestIid = 6;
String projectKey = "projectKey";
String projectName = "project name";
String sonarRootUrl = "http://sonar:9000/sonar";
String discussionId = "6a9c1750b37d513a43987b574953fceb50b03ce7";
String noteId = "1126";
@@ -95,16 +96,18 @@ class GitlabMergeRequestDecoratorIntegrationTest {
int lineNumber = 5;
ProjectAlmSettingDto projectAlmSettingDto = mock();
when(projectAlmSettingDto.getAlmRepo()).thenReturn(repositorySlug);
when(projectAlmSettingDto.getMonorepo()).thenReturn(isMonorepo);
AlmSettingDto almSettingDto = mock();
when(almSettingDto.getDecryptedPersonalAccessToken(any())).thenReturn("token");
when(almSettingDto.getUrl()).thenReturn(wireMockExtension.baseUrl() + "/api/v4");
AnalysisDetails analysisDetails = mock();
when(almSettingDto.getUrl()).thenReturn(wireMockExtension.baseUrl() + "/api/v4");
when(projectAlmSettingDto.getAlmRepo()).thenReturn(repositorySlug);
when(projectAlmSettingDto.getMonorepo()).thenReturn(true);
when(analysisDetails.getQualityGateStatus()).thenReturn(status);
when(analysisDetails.getAnalysisProjectKey()).thenReturn(projectKey);
when(analysisDetails.getAnalysisProjectName()).thenReturn(projectName);
when(analysisDetails.getPullRequestId()).thenReturn(Long.toString(mergeRequestIid));
when(analysisDetails.getCommitSha()).thenReturn(commitSha);
@@ -215,9 +218,15 @@ class GitlabMergeRequestDecoratorIntegrationTest {
.withRequestBody(equalTo("body=" + urlEncode("This issue no longer exists in SonarQube, but due to other comments being present in this discussion, the discussion is not being being closed automatically. Please manually resolve this discussion once the other comments have been reviewed.")))
.willReturn(created()));
wireMockExtension.stubFor(post(urlEqualTo("/api/v4/projects/" + sourceProjectId + "/statuses/" + commitSha + "?state=" + (status == QualityGate.Status.OK ? "success" : "failed")))
.withRequestBody(equalTo("name=SonarQube&target_url=" + urlEncode(sonarRootUrl + "/dashboard?id=" + projectKey + "&pullRequest=" + mergeRequestIid) + "&description=SonarQube+Status&coverage=10"))
.willReturn(created()));
if (isMonorepo) {
wireMockExtension.stubFor(post(urlEqualTo("/api/v4/projects/" + sourceProjectId + "/statuses/" + commitSha + "?state=" + (status == QualityGate.Status.OK ? "success" : "failed")))
.withRequestBody(equalTo("name=SonarQube+-+projectKey&target_url=" + urlEncode(sonarRootUrl + "/dashboard?id=" + projectKey + "&pullRequest=" + mergeRequestIid) + "&description=SonarQube+Status+-+project+name&coverage=10"))
.willReturn(created()));
} else {
wireMockExtension.stubFor(post(urlEqualTo("/api/v4/projects/" + sourceProjectId + "/statuses/" + commitSha + "?state=" + (status == QualityGate.Status.OK ? "success" : "failed")))
.withRequestBody(equalTo("name=SonarQube&target_url=" + urlEncode(sonarRootUrl + "/dashboard?id=" + projectKey + "&pullRequest=" + mergeRequestIid) + "&description=SonarQube+Status&coverage=10"))
.willReturn(created()));
}
wireMockExtension.stubFor(post(urlPathEqualTo("/api/v4/projects/" + sourceProjectId + "/merge_requests/" + mergeRequestIid + "/discussions"))
.withRequestBody(equalTo("body=summary+comm%C3%A9nt%0A%0A%5Blink+text%5D"))
@@ -244,6 +253,13 @@ class GitlabMergeRequestDecoratorIntegrationTest {
.willReturn(ok())
);
if (!isMonorepo) {
wireMockExtension.stubFor(put(urlPathEqualTo("/api/v4/projects/" + sourceProjectId + "/merge_requests/" + mergeRequestIid + "/discussions/" + discussionId + 7))
.withQueryParam("resolved", equalTo("true"))
.willReturn(ok())
);
}
LinkHeaderReader linkHeaderReader = mock();
Settings settings = mock();
Encryption encryption = mock();