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; | ||||
} | } | ||||
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); | ||||
} | } | ||||
} | } |
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) { |
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; |
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) |
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")); |
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") |
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()) |
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) |
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(); | ||||
} | } |
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 |
/* | |||||
* 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() { | |||||
} | |||||
} |
*/ | */ | ||||
Optional<String> getScmRevision(); | Optional<String> getScmRevision(); | ||||
/** | |||||
* The information about DevOpsPlatform that was detected. | |||||
*/ | |||||
Optional<DevOpsPlatformInfo> getDevOpsPlatformInfo(); | |||||
} | } |
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; | |||||
} | |||||
} | } |
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"; |
/* | |||||
* 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; | |||||
} | |||||
} |
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)); | |||||
} | } | ||||
} | } |
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<>(); | ||||
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); | |||||
} | |||||
} | } |
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); |