Browse Source

SONAR-20699 Send DevOps platform information for GitHub from the scanner.

tags/10.3.0.82913
Wojtek Wajerowicz 8 months ago
parent
commit
4670e9985e
20 changed files with 299 additions and 83 deletions
  1. 4
    4
      server/sonar-ce/src/it/java/org/sonar/ce/queue/NextPendingTaskPickerIT.java
  2. 5
    5
      server/sonar-ce/src/main/java/org/sonar/ce/queue/NextPendingTaskPicker.java
  3. 7
    7
      server/sonar-db-dao/src/it/java/org/sonar/db/ce/CeQueueDaoIT.java
  4. 8
    4
      server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicDto.java
  5. 5
    5
      server/sonar-webserver-core/src/main/java/org/sonar/server/issue/index/AsyncIssueIndexingImpl.java
  6. 5
    5
      server/sonar-webserver-core/src/test/java/org/sonar/server/issue/index/AsyncIssueIndexingImplTest.java
  7. 9
    9
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/ActivityActionIT.java
  8. 13
    13
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/ComponentActionIT.java
  9. 7
    7
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/TaskActionIT.java
  10. 8
    5
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java
  11. 23
    2
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/SubmitActionTest.java
  12. 32
    0
      sonar-core/src/main/java/org/sonar/core/ce/CeTaskCharacteristics.java
  13. 5
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfiguration.java
  14. 16
    4
      sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationImpl.java
  15. 5
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationProvider.java
  16. 40
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/DevOpsPlatformInfo.java
  17. 17
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/GithubActions.java
  18. 22
    6
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java
  19. 26
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/GithubActionsTest.java
  20. 42
    3
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java

+ 4
- 4
server/sonar-ce/src/it/java/org/sonar/ce/queue/NextPendingTaskPickerIT.java View File

import org.junit.Test; import org.junit.Test;
import org.sonar.api.config.Configuration; import org.sonar.api.config.Configuration;
import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
import org.sonar.api.testfixtures.log.LogTester; import org.sonar.api.testfixtures.log.LogTester;
import org.sonar.api.utils.System2;
import org.sonar.core.config.ComputeEngineProperties; import org.sonar.core.config.ComputeEngineProperties;
import org.sonar.db.DbTester; import org.sonar.db.DbTester;
import org.sonar.db.ce.CeQueueDto; import org.sonar.db.ce.CeQueueDto;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH;
import static org.sonar.core.ce.CeTaskCharacteristics.PULL_REQUEST;
import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS; import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS;
import static org.sonar.db.ce.CeQueueDto.Status.PENDING; import static org.sonar.db.ce.CeQueueDto.Status.PENDING;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.PULL_REQUEST;


public class NextPendingTaskPickerIT { public class NextPendingTaskPickerIT {




private CeQueueDto insertPendingBranch(String uuid) { private CeQueueDto insertPendingBranch(String uuid) {
CeQueueDto queue = insertPending(uuid, null); CeQueueDto queue = insertPending(uuid, null);
insertCharacteristics(queue.getUuid(), BRANCH_KEY);
insertCharacteristics(queue.getUuid(), BRANCH);
return queue; return queue;
} }



+ 5
- 5
server/sonar-ce/src/main/java/org/sonar/ce/queue/NextPendingTaskPicker.java View File

import java.util.Set; import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.ObjectUtils;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.config.Configuration;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.config.Configuration;
import org.sonar.core.config.ComputeEngineProperties; import org.sonar.core.config.ComputeEngineProperties;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.ce.CeTaskDtoLight; import org.sonar.db.ce.CeTaskDtoLight;
import org.sonar.db.ce.PrOrBranchTask; import org.sonar.db.ce.PrOrBranchTask;


import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.PULL_REQUEST;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH;
import static org.sonar.core.ce.CeTaskCharacteristics.PULL_REQUEST;


@ComputeEngineSide @ComputeEngineSide
public class NextPendingTaskPicker { public class NextPendingTaskPicker {


for (PrOrBranchTask task : queuedPrOrBranches) { for (PrOrBranchTask task : queuedPrOrBranches) {
if ((Objects.equals(task.getBranchType(), PULL_REQUEST) && canRunPr(task, inProgressTasks)) if ((Objects.equals(task.getBranchType(), PULL_REQUEST) && canRunPr(task, inProgressTasks))
|| (Objects.equals(task.getBranchType(), BRANCH_KEY) && canRunBranch(task, inProgressTasks))) {
|| (Objects.equals(task.getBranchType(), BRANCH) && canRunBranch(task, inProgressTasks))) {
return Optional.of(task); return Optional.of(task);
} }
} }

+ 7
- 7
server/sonar-db-dao/src/it/java/org/sonar/db/ce/CeQueueDaoIT.java View File

import static org.assertj.core.groups.Tuple.tuple; import static org.assertj.core.groups.Tuple.tuple;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH;
import static org.sonar.core.ce.CeTaskCharacteristics.PULL_REQUEST;
import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS; import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS;
import static org.sonar.db.ce.CeQueueDto.Status.PENDING; import static org.sonar.db.ce.CeQueueDto.Status.PENDING;
import static org.sonar.db.ce.CeQueueTesting.newCeQueueDto; import static org.sonar.db.ce.CeQueueTesting.newCeQueueDto;
import static org.sonar.db.ce.CeQueueTesting.reset; import static org.sonar.db.ce.CeQueueTesting.reset;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.PULL_REQUEST;


public class CeQueueDaoIT { public class CeQueueDaoIT {
private static final long INIT_TIME = 1_450_000_000_000L; private static final long INIT_TIME = 1_450_000_000_000L;
List<CeQueueDto> notPendingForWorker = underTestAlwaysIncreasingSystem2.selectNotPendingForWorker(db.getSession(), WORKER_UUID_1); List<CeQueueDto> notPendingForWorker = underTestAlwaysIncreasingSystem2.selectNotPendingForWorker(db.getSession(), WORKER_UUID_1);


assertThat(notPendingForWorker).extracting(CeQueueDto::getUuid) assertThat(notPendingForWorker).extracting(CeQueueDto::getUuid)
.contains(inProgressTaskWorker1.getUuid());
.contains(inProgressTaskWorker1.getUuid());
} }


@Test @Test
assertThat(prOrBranchTasks).hasSize(1); assertThat(prOrBranchTasks).hasSize(1);
assertThat(prOrBranchTasks.get(0)) assertThat(prOrBranchTasks.get(0))
.extracting(PrOrBranchTask::getBranchType, PrOrBranchTask::getComponentUuid, PrOrBranchTask::getEntityUuid, PrOrBranchTask::getTaskType) .extracting(PrOrBranchTask::getBranchType, PrOrBranchTask::getComponentUuid, PrOrBranchTask::getEntityUuid, PrOrBranchTask::getTaskType)
.containsExactly(BRANCH_KEY, COMPONENT_UUID_1, ENTITY_UUID_1, CeTaskTypes.REPORT);
.containsExactly(BRANCH, COMPONENT_UUID_1, ENTITY_UUID_1, CeTaskTypes.REPORT);
} }


@Test @Test
.setTaskType(CeTaskTypes.REPORT) .setTaskType(CeTaskTypes.REPORT)
.setCreatedAt(123L)); .setCreatedAt(123L));
List<PrOrBranchTask> prOrBranchTasks = underTest.selectOldestPendingPrOrBranch(db.getSession()); List<PrOrBranchTask> prOrBranchTasks = underTest.selectOldestPendingPrOrBranch(db.getSession());
insertCharacteristic(BRANCH_KEY, "123", "c1", TASK_UUID_1);
insertCharacteristic(BRANCH, "123", "c1", TASK_UUID_1);


assertThat(prOrBranchTasks).hasSize(1); assertThat(prOrBranchTasks).hasSize(1);
assertThat(prOrBranchTasks.get(0)) assertThat(prOrBranchTasks.get(0))
.extracting(PrOrBranchTask::getBranchType, PrOrBranchTask::getComponentUuid, PrOrBranchTask::getEntityUuid, PrOrBranchTask::getTaskType) .extracting(PrOrBranchTask::getBranchType, PrOrBranchTask::getComponentUuid, PrOrBranchTask::getEntityUuid, PrOrBranchTask::getTaskType)
.containsExactly(BRANCH_KEY, COMPONENT_UUID_1, ENTITY_UUID_1, CeTaskTypes.REPORT);
.containsExactly(BRANCH, COMPONENT_UUID_1, ENTITY_UUID_1, CeTaskTypes.REPORT);
} }


@Test @Test
assertThat(prOrBranchTasks).hasSize(1); assertThat(prOrBranchTasks).hasSize(1);
assertThat(prOrBranchTasks.get(0)) assertThat(prOrBranchTasks.get(0))
.extracting(PrOrBranchTask::getBranchType, PrOrBranchTask::getComponentUuid, PrOrBranchTask::getEntityUuid, PrOrBranchTask::getTaskType) .extracting(PrOrBranchTask::getBranchType, PrOrBranchTask::getComponentUuid, PrOrBranchTask::getEntityUuid, PrOrBranchTask::getTaskType)
.containsExactly(BRANCH_KEY, COMPONENT_UUID_1, ENTITY_UUID_1, CeTaskTypes.REPORT);
.containsExactly(BRANCH, COMPONENT_UUID_1, ENTITY_UUID_1, CeTaskTypes.REPORT);
} }


private void insertPending(CeQueueDto dto) { private void insertPending(CeQueueDto dto) {

+ 8
- 4
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicDto.java View File



import java.util.Set; import java.util.Set;


import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH_TYPE;
import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_PROJECT_IDENTIFIER;
import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_URL;
import static org.sonar.core.ce.CeTaskCharacteristics.PULL_REQUEST;

public class CeTaskCharacteristicDto { public class CeTaskCharacteristicDto {


public static final String BRANCH_KEY = "branch";
public static final String BRANCH_TYPE_KEY = "branchType";
public static final String PULL_REQUEST = "pullRequest";
public static final Set<String> SUPPORTED_KEYS = Set.of(BRANCH_KEY, BRANCH_TYPE_KEY, PULL_REQUEST);

public static final Set<String> SUPPORTED_KEYS = Set.of(BRANCH, BRANCH_TYPE, PULL_REQUEST, DEVOPS_PLATFORM_URL, DEVOPS_PLATFORM_PROJECT_IDENTIFIER);


private String uuid; private String uuid;
private String taskUuid; private String taskUuid;

+ 5
- 5
server/sonar-webserver-core/src/main/java/org/sonar/server/issue/index/AsyncIssueIndexingImpl.java View File

import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.sonar.ce.queue.CeQueue; import org.sonar.ce.queue.CeQueue;
import org.sonar.ce.queue.CeTaskSubmit; import org.sonar.ce.queue.CeTaskSubmit;
import org.sonar.core.ce.CeTaskCharacteristics;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.ce.CeActivityDto; import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.component.SnapshotDto; import org.sonar.db.component.SnapshotDto;


import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.toCollection;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.PULL_REQUEST;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH_TYPE;
import static org.sonar.core.ce.CeTaskCharacteristics.PULL_REQUEST;
import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC; import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC;


public class AsyncIssueIndexingImpl implements AsyncIssueIndexing { public class AsyncIssueIndexingImpl implements AsyncIssueIndexing {


private CeTaskSubmit buildTaskSubmit(BranchDto branch) { private CeTaskSubmit buildTaskSubmit(BranchDto branch) {
Map<String, String> characteristics = new HashMap<>(); Map<String, String> characteristics = new HashMap<>();
characteristics.put(branch.getBranchType() == BranchType.BRANCH ? BRANCH_KEY : PULL_REQUEST, branch.getKey());
characteristics.put(BRANCH_TYPE_KEY, branch.getBranchType().name());
characteristics.put(branch.getBranchType() == BranchType.BRANCH ? CeTaskCharacteristics.BRANCH : PULL_REQUEST, branch.getKey());
characteristics.put(BRANCH_TYPE, branch.getBranchType().name());


return ceQueue.prepareSubmit() return ceQueue.prepareSubmit()
.setType(BRANCH_ISSUE_SYNC) .setType(BRANCH_ISSUE_SYNC)

+ 5
- 5
server/sonar-webserver-core/src/test/java/org/sonar/server/issue/index/AsyncIssueIndexingImplTest.java View File

import org.sonar.api.utils.System2; import org.sonar.api.utils.System2;
import org.sonar.ce.queue.CeQueue; import org.sonar.ce.queue.CeQueue;
import org.sonar.ce.queue.CeTaskSubmit; import org.sonar.ce.queue.CeTaskSubmit;
import org.sonar.core.ce.CeTaskCharacteristics;
import org.sonar.core.util.SequenceUuidFactory; import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.UuidFactory; import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.ce.CeActivityDto; import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.ce.CeActivityDto.Status; import org.sonar.db.ce.CeActivityDto.Status;
import org.sonar.db.ce.CeQueueDto; import org.sonar.db.ce.CeQueueDto;
import org.sonar.db.ce.CeTaskCharacteristicDto;
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;
import org.sonar.db.component.SnapshotDto; import org.sonar.db.component.SnapshotDto;
import org.sonar.db.project.ProjectDto; import org.sonar.db.project.ProjectDto;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH_TYPE;
import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC; import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC;
import static org.sonar.db.ce.CeTaskTypes.REPORT; import static org.sonar.db.ce.CeTaskTypes.REPORT;
import static org.sonar.db.component.BranchType.BRANCH; import static org.sonar.db.component.BranchType.BRANCH;
assertThat(tasks).hasSize(2); assertThat(tasks).hasSize(2);


assertThat(tasks) assertThat(tasks)
.extracting(p -> p.getCharacteristics().get(BRANCH_TYPE_KEY),
p -> p.getCharacteristics().get(CeTaskCharacteristicDto.BRANCH_KEY),
p -> p.getCharacteristics().get(CeTaskCharacteristicDto.PULL_REQUEST))
.extracting(p -> p.getCharacteristics().get(BRANCH_TYPE),
p -> p.getCharacteristics().get(CeTaskCharacteristics.BRANCH),
p -> p.getCharacteristics().get(CeTaskCharacteristics.PULL_REQUEST))
.containsExactlyInAnyOrder( .containsExactlyInAnyOrder(
tuple("BRANCH", "branch_1", null), tuple("BRANCH", "branch_1", null),
tuple("PULL_REQUEST", null, "pr_1")); tuple("PULL_REQUEST", null, "pr_1"));

+ 9
- 9
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/ActivityActionIT.java View File

import org.sonar.api.utils.System2; import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole; import org.sonar.api.web.UserRole;
import org.sonar.ce.task.taskprocessor.CeTaskProcessor; import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
import org.sonar.core.ce.CeTaskCharacteristics;
import org.sonar.core.util.Uuids; import org.sonar.core.util.Uuids;
import org.sonar.db.DbTester; import org.sonar.db.DbTester;
import org.sonar.db.ce.CeActivityDto; import org.sonar.db.ce.CeActivityDto;
import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY; import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
import static org.sonar.api.utils.DateUtils.formatDate; import static org.sonar.api.utils.DateUtils.formatDate;
import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH_TYPE;
import static org.sonar.core.ce.CeTaskCharacteristics.PULL_REQUEST;
import static org.sonar.db.ce.CeActivityDto.Status.FAILED; import static org.sonar.db.ce.CeActivityDto.Status.FAILED;
import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS; import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS; import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS;
import static org.sonar.db.ce.CeQueueDto.Status.PENDING; import static org.sonar.db.ce.CeQueueDto.Status.PENDING;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.PULL_REQUEST;
import static org.sonar.db.component.BranchType.BRANCH; import static org.sonar.db.component.BranchType.BRANCH;
import static org.sonar.server.ce.ws.CeWsParameters.PARAM_COMPONENT; import static org.sonar.server.ce.ws.CeWsParameters.PARAM_COMPONENT;
import static org.sonar.server.ce.ws.CeWsParameters.PARAM_MAX_EXECUTED_AT; import static org.sonar.server.ce.ws.CeWsParameters.PARAM_MAX_EXECUTED_AT;
ComponentDto branch = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey(branchName)); ComponentDto branch = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey(branchName));
SnapshotDto analysis = db.components().insertSnapshot(branch); SnapshotDto analysis = db.components().insertSnapshot(branch);
CeActivityDto activity = insertActivity("T1", project.projectUuid(), project.mainBranchUuid(), SUCCESS, analysis); CeActivityDto activity = insertActivity("T1", project.projectUuid(), project.mainBranchUuid(), SUCCESS, analysis);
insertCharacteristic(activity, BRANCH_KEY, branchName);
insertCharacteristic(activity, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(activity, CeTaskCharacteristics.BRANCH, branchName);
insertCharacteristic(activity, BRANCH_TYPE, BRANCH.name());


ActivityResponse response = ws.newRequest().executeProtobuf(ActivityResponse.class); ActivityResponse response = ws.newRequest().executeProtobuf(ActivityResponse.class);


logInAsSystemAdministrator(); logInAsSystemAdministrator();
String branch = "ny_branch"; String branch = "ny_branch";
CeQueueDto queue1 = insertQueue("T1", null, IN_PROGRESS); CeQueueDto queue1 = insertQueue("T1", null, IN_PROGRESS);
insertCharacteristic(queue1, BRANCH_KEY, branch);
insertCharacteristic(queue1, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(queue1, CeTaskCharacteristics.BRANCH, branch);
insertCharacteristic(queue1, BRANCH_TYPE, BRANCH.name());
CeQueueDto queue2 = insertQueue("T2", null, PENDING); CeQueueDto queue2 = insertQueue("T2", null, PENDING);
insertCharacteristic(queue2, BRANCH_KEY, branch);
insertCharacteristic(queue2, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(queue2, CeTaskCharacteristics.BRANCH, branch);
insertCharacteristic(queue2, BRANCH_TYPE, BRANCH.name());


ActivityResponse response = ws.newRequest() ActivityResponse response = ws.newRequest()
.setParam("status", "FAILED,IN_PROGRESS,PENDING") .setParam("status", "FAILED,IN_PROGRESS,PENDING")

+ 13
- 13
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/ComponentActionIT.java View File

import org.junit.Test; import org.junit.Test;
import org.sonar.api.utils.System2; import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole; import org.sonar.api.web.UserRole;
import org.sonar.core.ce.CeTaskCharacteristics;
import org.sonar.core.util.Uuids; import org.sonar.core.util.Uuids;
import org.sonar.db.DbTester; import org.sonar.db.DbTester;
import org.sonar.db.ce.CeActivityDto; import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.ce.CeQueueDto; import org.sonar.db.ce.CeQueueDto;
import org.sonar.db.ce.CeTaskCharacteristicDto; import org.sonar.db.ce.CeTaskCharacteristicDto;
import org.sonar.db.ce.CeTaskMessageDto; import org.sonar.db.ce.CeTaskMessageDto;
import org.sonar.db.dismissmessage.MessageType;
import org.sonar.db.ce.CeTaskTypes; import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ProjectData; import org.sonar.db.component.ProjectData;
import org.sonar.db.component.SnapshotDto; import org.sonar.db.component.SnapshotDto;
import org.sonar.db.dismissmessage.MessageType;
import org.sonar.db.entity.EntityDto; import org.sonar.db.entity.EntityDto;
import org.sonar.db.project.ProjectDto; import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.TestComponentFinder; import org.sonar.server.component.TestComponentFinder;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple; import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH_TYPE;
import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS; import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS; import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS;
import static org.sonar.db.ce.CeQueueDto.Status.PENDING; import static org.sonar.db.ce.CeQueueDto.Status.PENDING;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY;
import static org.sonar.db.component.BranchType.BRANCH; import static org.sonar.db.component.BranchType.BRANCH;
import static org.sonar.server.ce.ws.CeWsParameters.PARAM_COMPONENT; import static org.sonar.server.ce.ws.CeWsParameters.PARAM_COMPONENT;


ComponentDto branch = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey(branchName)); ComponentDto branch = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey(branchName));
SnapshotDto analysis = db.components().insertSnapshot(branch); SnapshotDto analysis = db.components().insertSnapshot(branch);
CeActivityDto activity = insertActivity("T1", project.getMainBranchComponent(), project.getProjectDto(), SUCCESS, analysis); CeActivityDto activity = insertActivity("T1", project.getMainBranchComponent(), project.getProjectDto(), SUCCESS, analysis);
insertCharacteristic(activity, BRANCH_KEY, branchName);
insertCharacteristic(activity, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(activity, CeTaskCharacteristics.BRANCH, branchName);
insertCharacteristic(activity, BRANCH_TYPE, BRANCH.name());


Ce.ComponentResponse response = ws.newRequest() Ce.ComponentResponse response = ws.newRequest()
.setParam(PARAM_COMPONENT, project.projectKey()) .setParam(PARAM_COMPONENT, project.projectKey())
String branchName = randomAlphanumeric(248); String branchName = randomAlphanumeric(248);
ComponentDto branch = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey(branchName)); ComponentDto branch = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey(branchName));
CeQueueDto queue1 = insertQueue("T1", project.getMainBranchComponent(), project.getProjectDto(), IN_PROGRESS); CeQueueDto queue1 = insertQueue("T1", project.getMainBranchComponent(), project.getProjectDto(), IN_PROGRESS);
insertCharacteristic(queue1, BRANCH_KEY, branchName);
insertCharacteristic(queue1, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(queue1, CeTaskCharacteristics.BRANCH, branchName);
insertCharacteristic(queue1, BRANCH_TYPE, BRANCH.name());
CeQueueDto queue2 = insertQueue("T2", project.getMainBranchComponent(), project.getProjectDto(), PENDING); CeQueueDto queue2 = insertQueue("T2", project.getMainBranchComponent(), project.getProjectDto(), PENDING);
insertCharacteristic(queue2, BRANCH_KEY, branchName);
insertCharacteristic(queue2, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(queue2, CeTaskCharacteristics.BRANCH, branchName);
insertCharacteristic(queue2, BRANCH_TYPE, BRANCH.name());


Ce.ComponentResponse response = ws.newRequest() Ce.ComponentResponse response = ws.newRequest()
.setParam(PARAM_COMPONENT, branch.getKey()) .setParam(PARAM_COMPONENT, branch.getKey())
String branchName1 = "Branch1"; String branchName1 = "Branch1";
ComponentDto branch1 = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey("branch1")); ComponentDto branch1 = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey("branch1"));
CeQueueDto branchQueue1 = insertQueue("Branch1", project.getMainBranchComponent(), project.getProjectDto(), IN_PROGRESS); CeQueueDto branchQueue1 = insertQueue("Branch1", project.getMainBranchComponent(), project.getProjectDto(), IN_PROGRESS);
insertCharacteristic(branchQueue1, BRANCH_KEY, branchName1);
insertCharacteristic(branchQueue1, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(branchQueue1, CeTaskCharacteristics.BRANCH, branchName1);
insertCharacteristic(branchQueue1, BRANCH_TYPE, BRANCH.name());


ComponentDto branch2 = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey("branch2")); ComponentDto branch2 = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setBranchType(BRANCH).setKey("branch2"));
String branchName2 = "Branch2"; String branchName2 = "Branch2";
CeQueueDto branchQueue2 = insertQueue("Branch2", project.getMainBranchComponent(), project.getProjectDto(), PENDING); CeQueueDto branchQueue2 = insertQueue("Branch2", project.getMainBranchComponent(), project.getProjectDto(), PENDING);
insertCharacteristic(branchQueue2, BRANCH_KEY, branchName2);
insertCharacteristic(branchQueue2, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(branchQueue2, CeTaskCharacteristics.BRANCH, branchName2);
insertCharacteristic(branchQueue2, BRANCH_TYPE, BRANCH.name());


Ce.ComponentResponse response = ws.newRequest() Ce.ComponentResponse response = ws.newRequest()
.setParam(PARAM_COMPONENT, project.projectKey()) .setParam(PARAM_COMPONENT, project.projectKey())

+ 7
- 7
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/TaskActionIT.java View File

import org.junit.Test; import org.junit.Test;
import org.sonar.api.utils.System2; import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole; import org.sonar.api.web.UserRole;
import org.sonar.core.ce.CeTaskCharacteristics;
import org.sonar.core.util.CloseableIterator; import org.sonar.core.util.CloseableIterator;
import org.sonar.core.util.UuidFactoryFast; import org.sonar.core.util.UuidFactoryFast;
import org.sonar.core.util.Uuids; import org.sonar.core.util.Uuids;
import org.sonar.db.ce.CeQueueDto; import org.sonar.db.ce.CeQueueDto;
import org.sonar.db.ce.CeTaskCharacteristicDto; import org.sonar.db.ce.CeTaskCharacteristicDto;
import org.sonar.db.ce.CeTaskMessageDto; import org.sonar.db.ce.CeTaskMessageDto;
import org.sonar.db.dismissmessage.MessageType;
import org.sonar.db.ce.CeTaskTypes; import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ProjectData; import org.sonar.db.component.ProjectData;
import org.sonar.db.dismissmessage.MessageType;
import org.sonar.db.permission.GlobalPermission; import org.sonar.db.permission.GlobalPermission;
import org.sonar.db.project.ProjectDto; import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.UserDto; import org.sonar.db.user.UserDto;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.sonar.api.web.UserRole.ADMIN; import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.api.web.UserRole.SCAN; import static org.sonar.api.web.UserRole.SCAN;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH_TYPE;
import static org.sonar.db.component.BranchType.BRANCH; import static org.sonar.db.component.BranchType.BRANCH;


public class TaskActionIT { public class TaskActionIT {
ComponentDto branch = db.components().insertProjectBranch(mainBranch, b -> b.setBranchType(BRANCH).setKey(branchName)); ComponentDto branch = db.components().insertProjectBranch(mainBranch, b -> b.setBranchType(BRANCH).setKey(branchName));
db.components().insertSnapshot(branch); db.components().insertSnapshot(branch);
CeActivityDto activity = createAndPersistArchivedTask(mainBranch); CeActivityDto activity = createAndPersistArchivedTask(mainBranch);
insertCharacteristic(activity, BRANCH_KEY, branchName);
insertCharacteristic(activity, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(activity, CeTaskCharacteristics.BRANCH, branchName);
insertCharacteristic(activity, BRANCH_TYPE, BRANCH.name());


Ce.TaskResponse taskResponse = ws.newRequest() Ce.TaskResponse taskResponse = ws.newRequest()
.setParam("id", SOME_TASK_UUID) .setParam("id", SOME_TASK_UUID)


String branch = "my_branch"; String branch = "my_branch";
CeQueueDto queueDto = createAndPersistQueueTask(null, user); CeQueueDto queueDto = createAndPersistQueueTask(null, user);
insertCharacteristic(queueDto, BRANCH_KEY, branch);
insertCharacteristic(queueDto, BRANCH_TYPE_KEY, BRANCH.name());
insertCharacteristic(queueDto, CeTaskCharacteristics.BRANCH, branch);
insertCharacteristic(queueDto, BRANCH_TYPE, BRANCH.name());


Ce.TaskResponse taskResponse = ws.newRequest() Ce.TaskResponse taskResponse = ws.newRequest()
.setParam("id", SOME_TASK_UUID) .setParam("id", SOME_TASK_UUID)

+ 8
- 5
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java View File

import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH_TYPE;
import static org.sonar.core.ce.CeTaskCharacteristics.PULL_REQUEST;


/** /**
* Converts {@link CeActivityDto} and {@link CeQueueDto} to the protobuf objects * Converts {@link CeActivityDto} and {@link CeQueueDto} to the protobuf objects


static DtoCache forActivityDtos(DbClient dbClient, DbSession dbSession, Collection<CeActivityDto> ceActivityDtos) { static DtoCache forActivityDtos(DbClient dbClient, DbSession dbSession, Collection<CeActivityDto> ceActivityDtos) {
Map<String, ComponentDto> componentsByUuid = dbClient.componentDao().selectByUuids( Map<String, ComponentDto> componentsByUuid = dbClient.componentDao().selectByUuids(
dbSession,
getComponentUuidsOfCeActivities(ceActivityDtos))
dbSession,
getComponentUuidsOfCeActivities(ceActivityDtos))
.stream() .stream()
.collect(Collectors.toMap(ComponentDto::uuid, Function.identity())); .collect(Collectors.toMap(ComponentDto::uuid, Function.identity()));
Multimap<String, CeTaskCharacteristicDto> characteristicsByTaskUuid = dbClient.ceTaskCharacteristicsDao() Multimap<String, CeTaskCharacteristicDto> characteristicsByTaskUuid = dbClient.ceTaskCharacteristicsDao()


Optional<String> getBranchKey(String taskUuid) { Optional<String> getBranchKey(String taskUuid) {
return characteristicsByTaskUuid.get(taskUuid).stream() return characteristicsByTaskUuid.get(taskUuid).stream()
.filter(c -> c.getKey().equals(CeTaskCharacteristicDto.BRANCH_KEY))
.filter(c -> c.getKey().equals(BRANCH))
.map(CeTaskCharacteristicDto::getValue) .map(CeTaskCharacteristicDto::getValue)
.findAny(); .findAny();
} }


Optional<Common.BranchType> getBranchType(String taskUuid) { Optional<Common.BranchType> getBranchType(String taskUuid) {
return characteristicsByTaskUuid.get(taskUuid).stream() return characteristicsByTaskUuid.get(taskUuid).stream()
.filter(c -> c.getKey().equals(CeTaskCharacteristicDto.BRANCH_TYPE_KEY))
.filter(c -> c.getKey().equals(BRANCH_TYPE))
.map(c -> Common.BranchType.valueOf(c.getValue())) .map(c -> Common.BranchType.valueOf(c.getValue()))
.findAny(); .findAny();
} }


Optional<String> getPullRequest(String taskUuid) { Optional<String> getPullRequest(String taskUuid) {
return characteristicsByTaskUuid.get(taskUuid).stream() return characteristicsByTaskUuid.get(taskUuid).stream()
.filter(c -> c.getKey().equals(CeTaskCharacteristicDto.PULL_REQUEST))
.filter(c -> c.getKey().equals(PULL_REQUEST))
.map(CeTaskCharacteristicDto::getValue) .map(CeTaskCharacteristicDto::getValue)
.findAny(); .findAny();
} }

+ 23
- 2
server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/SubmitActionTest.java View File

import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH;
import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_PROJECT_IDENTIFIER;
import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_URL;
import static org.sonar.core.ce.CeTaskCharacteristics.PULL_REQUEST;


public class SubmitActionTest { public class SubmitActionTest {


public void submit_task_with_characteristics() { public void submit_task_with_characteristics() {
when(reportSubmitter.submit(eq("my_project"), eq("My Project"), anyMap(), any())).thenReturn(A_CE_TASK); when(reportSubmitter.submit(eq("my_project"), eq("My Project"), anyMap(), any())).thenReturn(A_CE_TASK);


String[] characteristics = {"branch=foo", "pullRequest=123", "unsupported=bar"};
String devOpsPlatformUrl = "https://github.com";
String devOpsPlatformProjectIdentifier = "foo/bar";
String[] characteristics = {
buildCharacteristicParam(BRANCH, "foo"),
buildCharacteristicParam(PULL_REQUEST, "123"),
buildCharacteristicParam("unsupported", "bar"),
buildCharacteristicParam(DEVOPS_PLATFORM_URL, devOpsPlatformUrl),
buildCharacteristicParam(DEVOPS_PLATFORM_PROJECT_IDENTIFIER, devOpsPlatformProjectIdentifier) };
Ce.SubmitResponse submitResponse = tester.newRequest() Ce.SubmitResponse submitResponse = tester.newRequest()
.setParam("projectKey", "my_project") .setParam("projectKey", "my_project")
.setParam("projectName", "My Project") .setParam("projectName", "My Project")
verify(reportSubmitter).submit(eq("my_project"), eq("My Project"), map.capture(), any()); verify(reportSubmitter).submit(eq("my_project"), eq("My Project"), map.capture(), any());


// unsupported characteristics are ignored // unsupported characteristics are ignored
assertThat(map.getValue()).containsExactly(entry("branch", "foo"), entry("pullRequest", "123"));

assertThat(map.getValue()).containsExactly(
entry(BRANCH, "foo"),
entry(PULL_REQUEST, "123"),
entry(DEVOPS_PLATFORM_URL, devOpsPlatformUrl),
entry(DEVOPS_PLATFORM_PROJECT_IDENTIFIER, devOpsPlatformProjectIdentifier));
}

private static String buildCharacteristicParam(String characteristic, String value) {
return characteristic + "=" + value;
} }


@Test @Test

+ 32
- 0
sonar-core/src/main/java/org/sonar/core/ce/CeTaskCharacteristics.java View File

/*
* 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.core.ce;

public class CeTaskCharacteristics {

public static final String BRANCH = "branch";
public static final String BRANCH_TYPE = "branchType";
public static final String PULL_REQUEST = "pullRequest";
public static final String DEVOPS_PLATFORM_URL = "devOpsPlatformUrl";
public static final String DEVOPS_PLATFORM_PROJECT_IDENTIFIER = "devOpsPlatformProjectIdentifier";

private CeTaskCharacteristics() {
}
}

+ 5
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfiguration.java View File

*/ */
Optional<String> getScmRevision(); Optional<String> getScmRevision();


/**
* The information about DevOpsPlatform that was detected.
*/
Optional<DevOpsPlatformInfo> getDevOpsPlatformInfo();

} }

+ 16
- 4
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationImpl.java View File

public class CiConfigurationImpl implements CiConfiguration { public class CiConfigurationImpl implements CiConfiguration {
private final String ciName; private final String ciName;


@Nullable
private final String scmRevision;
private final Optional<String> scmRevision;
private final Optional<DevOpsPlatformInfo> devOpsPlatformInfo;


public CiConfigurationImpl(@Nullable String scmRevision, String ciName) { public CiConfigurationImpl(@Nullable String scmRevision, String ciName) {
this.scmRevision = defaultIfBlank(scmRevision, null);
this.scmRevision = Optional.ofNullable(defaultIfBlank(scmRevision, null));
this.ciName = ciName; this.ciName = ciName;
this.devOpsPlatformInfo = Optional.empty();
}

public CiConfigurationImpl(@Nullable String scmRevision, String ciName, DevOpsPlatformInfo devOpsPlatformInfo) {
this.scmRevision = Optional.ofNullable(defaultIfBlank(scmRevision, null));
this.ciName = ciName;
this.devOpsPlatformInfo = Optional.of(devOpsPlatformInfo);
} }


@Override @Override
public Optional<String> getScmRevision() { public Optional<String> getScmRevision() {
return Optional.ofNullable(scmRevision);
return scmRevision;
} }


@Override @Override
public String getCiName() { public String getCiName() {
return ciName; return ciName;
} }

@Override
public Optional<DevOpsPlatformInfo> getDevOpsPlatformInfo() {
return devOpsPlatformInfo;
}
} }

+ 5
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationProvider.java View File

return Optional.empty(); return Optional.empty();
} }


@Override
public Optional<DevOpsPlatformInfo> getDevOpsPlatformInfo() {
return Optional.empty();
}

@Override @Override
public String getCiName() { public String getCiName() {
return "undetected"; return "undetected";

+ 40
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/DevOpsPlatformInfo.java View File

/*
* 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.scanner.ci;

public class DevOpsPlatformInfo {

private final String url;
private final String projectIdentifier;

public DevOpsPlatformInfo(String url, String projectIdentifier) {
this.url = url;
this.projectIdentifier = projectIdentifier;
}

public String getUrl() {
return url;
}

public String getProjectIdentifier() {
return projectIdentifier;
}

}

+ 17
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/GithubActions.java View File

package org.sonar.scanner.ci.vendors; package org.sonar.scanner.ci.vendors;


import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.System2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.sonar.api.utils.System2;
import org.sonar.scanner.ci.CiConfiguration; import org.sonar.scanner.ci.CiConfiguration;
import org.sonar.scanner.ci.CiConfigurationImpl; import org.sonar.scanner.ci.CiConfigurationImpl;
import org.sonar.scanner.ci.CiVendor; import org.sonar.scanner.ci.CiVendor;
import org.sonar.scanner.ci.DevOpsPlatformInfo;


import static org.apache.commons.lang.StringUtils.isEmpty; import static org.apache.commons.lang.StringUtils.isEmpty;


*/ */
public class GithubActions implements CiVendor { public class GithubActions implements CiVendor {


private static final Logger LOG = LoggerFactory.getLogger(GithubActions.class);

private static final String PROPERTY_COMMIT = "GITHUB_SHA"; private static final String PROPERTY_COMMIT = "GITHUB_SHA";
public static final String GITHUB_REPOSITORY_ENV_VAR = "GITHUB_REPOSITORY";
public static final String GITHUB_API_URL_ENV_VAR = "GITHUB_API_URL";


private final System2 system; private final System2 system;


public CiConfiguration loadConfiguration() { public CiConfiguration loadConfiguration() {
String revision = system.envVariable(PROPERTY_COMMIT); String revision = system.envVariable(PROPERTY_COMMIT);
if (isEmpty(revision)) { if (isEmpty(revision)) {
LoggerFactory.getLogger(getClass()).warn("Missing environment variable " + PROPERTY_COMMIT);
LOG.warn("Missing environment variable " + PROPERTY_COMMIT);
} }
return new CiConfigurationImpl(revision, getName());

String githubRepository = system.envVariable(GITHUB_REPOSITORY_ENV_VAR);
String githubApiUrl = system.envVariable(GITHUB_API_URL_ENV_VAR);
if (isEmpty(githubRepository) || isEmpty(githubApiUrl)) {
LOG.warn("Missing or empty environment variables: {}, and/or {}", GITHUB_API_URL_ENV_VAR, GITHUB_REPOSITORY_ENV_VAR);
return new CiConfigurationImpl(revision, getName());
}
return new CiConfigurationImpl(revision, getName(), new DevOpsPlatformInfo(githubApiUrl, githubRepository));

} }
} }

+ 22
- 6
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java View File

import javax.annotation.Nullable; import javax.annotation.Nullable;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.Startable; import org.sonar.api.Startable;
import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.platform.Server; import org.sonar.api.platform.Server;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.TempFolder; import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.ZipUtils; import org.sonar.api.utils.ZipUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.core.ce.CeTaskCharacteristics;
import org.sonar.scanner.bootstrap.DefaultScannerWsClient; import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode; import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
import org.sonar.scanner.ci.CiConfiguration;
import org.sonar.scanner.fs.InputModuleHierarchy; import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.protocol.output.FileStructure; import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReportReader; import org.sonar.scanner.protocol.output.ScannerReportReader;
import static java.net.URLEncoder.encode; import static java.net.URLEncoder.encode;
import static org.apache.commons.lang.StringUtils.EMPTY; import static org.apache.commons.lang.StringUtils.EMPTY;
import static org.apache.commons.lang.StringUtils.isBlank; import static org.apache.commons.lang.StringUtils.isBlank;
import static org.sonar.core.ce.CeTaskCharacteristics.BRANCH_TYPE;
import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_PROJECT_IDENTIFIER;
import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_URL;
import static org.sonar.core.util.FileUtils.deleteQuietly; import static org.sonar.core.util.FileUtils.deleteQuietly;
import static org.sonar.core.util.FileUtils.humanReadableByteCountSI; import static org.sonar.core.util.FileUtils.humanReadableByteCountSI;
import static org.sonar.scanner.scan.branch.BranchType.PULL_REQUEST; import static org.sonar.scanner.scan.branch.BranchType.PULL_REQUEST;
private final AnalysisWarnings analysisWarnings; private final AnalysisWarnings analysisWarnings;
private final JavaArchitectureInformationProvider javaArchitectureInformationProvider; private final JavaArchitectureInformationProvider javaArchitectureInformationProvider;


private final CiConfiguration ciConfiguration;

public ReportPublisher(ScanProperties properties, DefaultScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher, public ReportPublisher(ScanProperties properties, DefaultScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher,
InputModuleHierarchy moduleHierarchy, GlobalAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers, BranchConfiguration branchConfiguration, InputModuleHierarchy moduleHierarchy, GlobalAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers, BranchConfiguration branchConfiguration,
CeTaskReportDataHolder ceTaskReportDataHolder, AnalysisWarnings analysisWarnings, CeTaskReportDataHolder ceTaskReportDataHolder, AnalysisWarnings analysisWarnings,
JavaArchitectureInformationProvider javaArchitectureInformationProvider, FileStructure fileStructure) {
JavaArchitectureInformationProvider javaArchitectureInformationProvider, FileStructure fileStructure, CiConfiguration ciConfiguration) {
this.wsClient = wsClient; this.wsClient = wsClient;
this.server = server; this.server = server;
this.contextPublisher = contextPublisher; this.contextPublisher = contextPublisher;
this.javaArchitectureInformationProvider = javaArchitectureInformationProvider; this.javaArchitectureInformationProvider = javaArchitectureInformationProvider;
this.writer = new ScannerReportWriter(fileStructure); this.writer = new ScannerReportWriter(fileStructure);
this.reader = new ScannerReportReader(fileStructure); this.reader = new ScannerReportReader(fileStructure);
this.ciConfiguration = ciConfiguration;
} }


@Override @Override


String branchName = branchConfiguration.branchName(); String branchName = branchConfiguration.branchName();
if (branchName != null) { if (branchName != null) {
ciConfiguration.getDevOpsPlatformInfo().ifPresent(devOpsPlatformInfo -> {
post.setParam(CHARACTERISTIC, buildCharacteristicParam(DEVOPS_PLATFORM_URL ,devOpsPlatformInfo.getUrl()));
post.setParam(CHARACTERISTIC, buildCharacteristicParam(DEVOPS_PLATFORM_PROJECT_IDENTIFIER, devOpsPlatformInfo.getProjectIdentifier()));
});
if (branchConfiguration.branchType() != PULL_REQUEST) { if (branchConfiguration.branchType() != PULL_REQUEST) {
post.setParam(CHARACTERISTIC, "branch=" + branchName);
post.setParam(CHARACTERISTIC, "branchType=" + branchConfiguration.branchType().name());
post.setParam(CHARACTERISTIC, buildCharacteristicParam(CeTaskCharacteristics.BRANCH, branchName));
post.setParam(CHARACTERISTIC, buildCharacteristicParam(BRANCH_TYPE, branchConfiguration.branchType().name()));
} else { } else {
post.setParam(CHARACTERISTIC, "pullRequest=" + branchConfiguration.pullRequestKey());
post.setParam(CHARACTERISTIC, buildCharacteristicParam(CeTaskCharacteristics.PULL_REQUEST, branchConfiguration.pullRequestKey()));
} }
} }


} }
} }


private static String buildCharacteristicParam(String characteristic, String value) {
return characteristic + "=" + value;
}

void prepareAndDumpMetadata(String taskId) { void prepareAndDumpMetadata(String taskId) {
Map<String, String> metadata = new LinkedHashMap<>(); Map<String, String> metadata = new LinkedHashMap<>();



+ 26
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/GithubActionsTest.java View File

import org.slf4j.event.Level; import org.slf4j.event.Level;
import org.sonar.api.testfixtures.log.LogTester; import org.sonar.api.testfixtures.log.LogTester;
import org.sonar.api.utils.System2; import org.sonar.api.utils.System2;
import org.sonar.scanner.ci.CiConfiguration;
import org.sonar.scanner.ci.CiVendor; import org.sonar.scanner.ci.CiVendor;
import org.sonar.scanner.ci.DevOpsPlatformInfo;


import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;


public class GithubActionsTest { public class GithubActionsTest {


private static final String GITHUB_API_URL = "https://api.github.com/";
private static final String REPOSITORY = "foo/bar";

@Rule @Rule
public LogTester logs = new LogTester(); public LogTester logs = new LogTester();


public void loadConfiguration() { public void loadConfiguration() {
setEnvVariable("GITHUB_ACTION", "build"); setEnvVariable("GITHUB_ACTION", "build");
setEnvVariable("GITHUB_SHA", "abd12fc"); setEnvVariable("GITHUB_SHA", "abd12fc");
setEnvVariable("GITHUB_API_URL", GITHUB_API_URL);
setEnvVariable("GITHUB_REPOSITORY", REPOSITORY);


assertThat(underTest.loadConfiguration().getScmRevision()).hasValue("abd12fc");
CiConfiguration configuration = underTest.loadConfiguration();
assertThat(configuration.getScmRevision()).hasValue("abd12fc");
checkDevOpsPlatformInfo(configuration);
} }


@Test @Test
assertThat(logs.logs(Level.WARN)).contains("Missing environment variable GITHUB_SHA"); assertThat(logs.logs(Level.WARN)).contains("Missing environment variable GITHUB_SHA");
} }


@Test
public void loadConfiguration_whenMissingGitHubEnvironmentVariables_shouldLogWarn() {
setEnvVariable("GITHUB_ACTION", "build");

assertThat(underTest.loadConfiguration().getDevOpsPlatformInfo()).isEmpty();
assertThat(logs.logs(Level.WARN)).contains("Missing or empty environment variables: GITHUB_API_URL, and/or GITHUB_REPOSITORY");
}

private void setEnvVariable(String key, @Nullable String value) { private void setEnvVariable(String key, @Nullable String value) {
when(system.envVariable(key)).thenReturn(value); when(system.envVariable(key)).thenReturn(value);
} }

private void checkDevOpsPlatformInfo(CiConfiguration configuration) {
assertThat(configuration.getDevOpsPlatformInfo()).isNotEmpty();
DevOpsPlatformInfo devOpsPlatformInfo = configuration.getDevOpsPlatformInfo().get();
assertThat(devOpsPlatformInfo.getProjectIdentifier()).isEqualTo(REPOSITORY);
assertThat(devOpsPlatformInfo.getUrl()).isEqualTo(GITHUB_API_URL);

}
} }

+ 42
- 3
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java View File

import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Optional;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.sonar.api.utils.TempFolder; import org.sonar.api.utils.TempFolder;
import org.sonar.scanner.bootstrap.DefaultScannerWsClient; import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode; import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
import org.sonar.scanner.ci.CiConfiguration;
import org.sonar.scanner.ci.DevOpsPlatformInfo;
import org.sonar.scanner.fs.InputModuleHierarchy; import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.protocol.output.FileStructure; import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport;
private AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class); private AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class);
private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
private CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.class); private CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.class);
private CiConfiguration ciConfiguration = mock(CiConfiguration.class);
private ReportPublisher underTest; private ReportPublisher underTest;
private AnalysisWarnings analysisWarnings = mock(AnalysisWarnings.class); private AnalysisWarnings analysisWarnings = mock(AnalysisWarnings.class);
private FileStructure fileStructure; private FileStructure fileStructure;
.resolve("folder") .resolve("folder")
.resolve("report-task.txt")); .resolve("report-task.txt"));
underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder, underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder,
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder, analysisWarnings, javaArchitectureInformationProvider, fileStructure);
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder, analysisWarnings, javaArchitectureInformationProvider, fileStructure, ciConfiguration);
} }


@Test @Test
when(branchConfiguration.branchType()).thenReturn(BRANCH); when(branchConfiguration.branchType()).thenReturn(BRANCH);
when(branchConfiguration.branchName()).thenReturn("branch-6.7"); when(branchConfiguration.branchName()).thenReturn("branch-6.7");
ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class), ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder, analysisWarnings, javaArchitectureInformationProvider, fileStructure);
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder, analysisWarnings, javaArchitectureInformationProvider, fileStructure, ciConfiguration);


underTest.prepareAndDumpMetadata("TASK-123"); underTest.prepareAndDumpMetadata("TASK-123");


when(branchConfiguration.pullRequestKey()).thenReturn("105"); when(branchConfiguration.pullRequestKey()).thenReturn("105");


ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class), ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder, analysisWarnings, javaArchitectureInformationProvider, fileStructure);
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder, analysisWarnings, javaArchitectureInformationProvider, fileStructure, ciConfiguration);


underTest.prepareAndDumpMetadata("TASK-123"); underTest.prepareAndDumpMetadata("TASK-123");


WsRequest wsRequest = capture.getValue(); WsRequest wsRequest = capture.getValue();
assertThat(wsRequest.getParameters().getKeys()).containsOnly("projectKey"); assertThat(wsRequest.getParameters().getKeys()).containsOnly("projectKey");
assertThat(wsRequest.getParameters().getValue("projectKey")).isEqualTo("org.sonarsource.sonarqube:sonarqube"); assertThat(wsRequest.getParameters().getValue("projectKey")).isEqualTo("org.sonarsource.sonarqube:sonarqube");
assertThat(wsRequest.getParameters().getValues("characteristic")).isEmpty();
} }


@Test @Test
.containsExactlyInAnyOrder("pullRequest=" + pullRequestId); .containsExactlyInAnyOrder("pullRequest=" + pullRequestId);
} }


@Test
public void upload_whenDevOpsPlatformInformationPresentInCiConfiguration_shouldUploadDevOpsPlatformInfoAsCharacteristic() throws Exception {
String branchName = "feature";
String pullRequestId = "pr-123";
DevOpsPlatformInfo devOpsPlatformInfo = new DevOpsPlatformInfo("https://devops.example.com", "projectId");

when(branchConfiguration.branchName()).thenReturn(branchName);
when(branchConfiguration.branchType()).thenReturn(PULL_REQUEST);
when(branchConfiguration.pullRequestKey()).thenReturn(pullRequestId);
when(ciConfiguration.getDevOpsPlatformInfo()).thenReturn(Optional.of(devOpsPlatformInfo));

WsResponse response = mock(WsResponse.class);

PipedOutputStream out = new PipedOutputStream();
PipedInputStream in = new PipedInputStream(out);
Ce.SubmitResponse.newBuilder().build().writeTo(out);
out.close();

when(response.failIfNotSuccessful()).thenReturn(response);
when(response.contentStream()).thenReturn(in);

when(wsClient.call(any(WsRequest.class))).thenReturn(response);
underTest.upload(reportTempFolder.newFile());

ArgumentCaptor<WsRequest> capture = ArgumentCaptor.forClass(WsRequest.class);
verify(wsClient).call(capture.capture());

WsRequest wsRequest = capture.getValue();
assertThat(wsRequest.getParameters().getValues("characteristic"))
.contains(
"devOpsPlatformUrl=" + devOpsPlatformInfo.getUrl(),
"devOpsPlatformProjectIdentifier=" + devOpsPlatformInfo.getProjectIdentifier());
}

@Test @Test
public void test_do_not_log_or_add_warning_if_using_64bit_jre() { public void test_do_not_log_or_add_warning_if_using_64bit_jre() {
when(javaArchitectureInformationProvider.is64bitJavaVersion()).thenReturn(true); when(javaArchitectureInformationProvider.is64bitJavaVersion()).thenReturn(true);

Loading…
Cancel
Save