*/
package org.sonar.db.component;
+import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
import org.sonar.api.utils.System2;
import org.sonar.db.Dao;
+import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbSession;
import static java.util.Objects.requireNonNull;
return getMapper(session).selectByAnalysisUuid(analysisUuid);
}
+ public List<AnalysisPropertyDto> selectByKeyAndAnalysisUuids(DbSession session, String key, Collection<String> snapshotUuids) {
+ requireNonNull(snapshotUuids);
+ var mapper = getMapper(session);
+ return DatabaseUtils.executeLargeInputs(snapshotUuids, input -> mapper.selectByKeyAnAnalysisUuids(input, key));
+ }
+
public void insert(DbSession session, List<AnalysisPropertyDto> analysisPropertyDto) {
analysisPropertyDto.forEach(a -> insert(session, a));
}
*/
package org.sonar.db.component;
+import java.util.Collection;
import java.util.List;
import org.apache.ibatis.annotations.Param;
void insertAsText(@Param("analysisPropertyDto") AnalysisPropertyDto analysisPropertyDto, @Param("createdAt") long createdAt);
List<ProjectCountPerAnalysisPropertyValue> selectProjectCountPerAnalysisPropertyValueInLastAnalysis(@Param("analysisPropertyKey") String analysisPropertyKey);
+
+ List<AnalysisPropertyDto> selectByKeyAnAnalysisUuids(@Param("analysisUuids") Collection<String> analysisUuids, @Param("analysisPropertyKey") String analysisPropertyKey);
+
}
@Override
public String toString() {
- return "BranchDto{" + "uuid='" + uuid + '\'' +
+ return "AnalysisPropertyDto{" + "uuid='" + uuid + '\'' +
", analysisUuid='" + analysisUuid + '\'' +
", key='" + key + '\'' +
", value='" + value + "'" +
analysis_uuid = #{analysisUuid}
</select>
+ <select id="selectByKeyAnAnalysisUuids" parameterType="string" resultType="ScrapAnalysisProperty">
+ SELECT
+ <include refid="columns"/>
+ FROM
+ analysis_properties
+ WHERE
+ kee = #{analysisPropertyKey,jdbcType=VARCHAR}
+ AND analysis_uuid in <foreach collection="analysisUuids" open="(" close=")" item="uuid" separator=",">#{uuid,jdbcType=VARCHAR}</foreach>
+ </select>
+
<select id="selectProjectCountPerAnalysisPropertyValueInLastAnalysis" parameterType="string" resultType="ProjectCountPerAnalysisPropertyValue">
select
ap.text_value as "propertyValue",
import java.util.Arrays;
import java.util.List;
import java.util.Random;
+import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
assertThat(result).containsExactlyInAnyOrder(propertyDtos.toArray(new AnalysisPropertyDto[0]));
}
+ @Test
+ public void selectByKeyAndAnalysisUuids_should_return_correct_values() {
+ String analysisUuid = randomAlphanumeric(40);
+
+ List<AnalysisPropertyDto> propertyDtos = Arrays.asList(
+ newAnalysisPropertyDto(random.nextInt(10), "key1",analysisUuid),
+ newAnalysisPropertyDto(random.nextInt(10), "key2", analysisUuid),
+ newAnalysisPropertyDto(random.nextInt(10), "key3", analysisUuid)
+ );
+
+ underTest.insert(dbSession, propertyDtos);
+ assertThat(dbTester.countRowsOfTable(dbSession, "ANALYSIS_PROPERTIES")).isEqualTo(propertyDtos.size());
+
+ List<AnalysisPropertyDto> result = underTest.selectByKeyAndAnalysisUuids(dbSession, "key1", Set.of(analysisUuid));
+ assertThat(result).contains(propertyDtos.get(0));
+ result = underTest.selectByKeyAndAnalysisUuids(dbSession, "key2", Set.of(analysisUuid));
+ assertThat(result).contains(propertyDtos.get(1));
+ result = underTest.selectByKeyAndAnalysisUuids(dbSession, "key3", Set.of(analysisUuid));
+ assertThat(result).contains(propertyDtos.get(2));
+ }
+
@Test
public void selectProjectCountPerAnalysisPropertyValueInLastAnalysis_should_return_correct_values() {
final String analysisPropertyKey = "key";
.containsExactlyInAnyOrder(
tuple("git", 3L),
tuple("svn", 1L),
- tuple("undetected", 2L)
- );
+ tuple("undetected", 2L));
}
private AnalysisPropertyDto insertAnalysisPropertyDto(int valueLength) {
return analysisPropertyDto;
}
- private AnalysisPropertyDto newAnalysisPropertyDto(int valueLength, String analysisUuid) {
+ private AnalysisPropertyDto newAnalysisPropertyDto(int valueLength, String key, String analysisUuid) {
return new AnalysisPropertyDto()
.setAnalysisUuid(analysisUuid)
- .setKey(randomAlphanumeric(512))
+ .setKey(key)
.setUuid(randomAlphanumeric(40))
.setValue(randomAlphanumeric(valueLength))
.setCreatedAt(1_000L);
}
+ private AnalysisPropertyDto newAnalysisPropertyDto(int valueLength, String analysisUuid) {
+ return newAnalysisPropertyDto(valueLength, randomAlphanumeric(512), analysisUuid);
+ }
+
private void compareFirstValueWith(AnalysisPropertyDto analysisPropertyDto) {
AnalysisPropertyDto dtoFromDatabase = underTest.selectByAnalysisUuid(dbSession, analysisPropertyDto.getAnalysisUuid()).get(0);
assertThat(dtoFromDatabase).isEqualTo(analysisPropertyDto);
*/
package org.sonar.server.projectanalysis.ws;
-import com.google.common.collect.ImmutableSet;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.web.UserRole;
+import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
public class SearchAction implements ProjectAnalysesWsAction {
- private static final Set<String> ALLOWED_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.APP, Qualifiers.VIEW);
+ private static final Set<String> ALLOWED_QUALIFIERS = Set.of(Qualifiers.PROJECT, Qualifiers.APP, Qualifiers.VIEW);
private final DbClient dbClient;
private final ComponentFinder componentFinder;
.setSince("6.3")
.setResponseExample(getClass().getResource("search-example.json"))
.setChangelog(
- new Change("7.5", "Add QualityGate information on Applications")
- )
+ new Change("9.0", "Add field response 'detectedCI'"),
+ new Change("7.5", "Add QualityGate information on Applications"))
.setHandler(this);
action.addPagingParams(DEFAULT_PAGE_SIZE, 500);
.setSort(BY_DATE, DESC);
ofNullable(data.getRequest().getFrom()).ifPresent(from -> dbQuery.setCreatedAfter(parseStartingDateOrDateTime(from).getTime()));
ofNullable(data.getRequest().getTo()).ifPresent(to -> dbQuery.setCreatedBefore(parseEndingDateOrDateTime(to).getTime() + 1_000L));
- data.setAnalyses(dbClient.snapshotDao().selectAnalysesByQuery(data.getDbSession(), dbQuery));
+ List<SnapshotDto> snapshotDtos = dbClient.snapshotDao().selectAnalysesByQuery(data.getDbSession(), dbQuery);
+ var detectedCIs = dbClient.analysisPropertiesDao().selectByKeyAndAnalysisUuids(data.getDbSession(),
+ CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDCI,
+ snapshotDtos.stream().map(SnapshotDto::getUuid).collect(Collectors.toList()));
+ data.setAnalyses(snapshotDtos);
+ data.setDetectedCIs(detectedCIs);
}
private void addEvents(SearchData.Builder data) {
import com.google.common.collect.ListMultimap;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.utils.Paging;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbSession;
+import org.sonar.db.component.AnalysisPropertyDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.event.EventComponentChangeDto;
class SearchData {
final List<SnapshotDto> analyses;
+ final Map<String, String> detectedCIs;
final ListMultimap<String, EventDto> eventsByAnalysis;
final ListMultimap<String, EventComponentChangeDto> componentChangesByEventUuid;
final Paging paging;
private SearchData(Builder builder) {
this.analyses = builder.analyses;
+ this.detectedCIs = builder.detectedCIs;
this.eventsByAnalysis = buildEvents(builder.events);
this.componentChangesByEventUuid = buildComponentChanges(builder.componentChanges);
this.paging = Paging
private final SearchRequest request;
private ComponentDto project;
private List<SnapshotDto> analyses;
+ private Map<String, String> detectedCIs;
private int countAnalyses;
private String manualBaseline;
private List<EventDto> events;
return this;
}
+ Builder setDetectedCIs(List<AnalysisPropertyDto> detectedCIs) {
+ this.detectedCIs = detectedCIs.stream().collect(Collectors.toMap(AnalysisPropertyDto::getAnalysisUuid,
+ AnalysisPropertyDto::getValue));
+ return this;
+ }
+
Builder setEvents(List<EventDto> events) {
this.events = events;
return this;
return analyses;
}
+ Map<String, String> getDetectedCIs() {
+ return detectedCIs;
+ }
+
public Builder setManualBaseline(@Nullable String manualBaseline) {
this.manualBaseline = manualBaseline;
return this;
}
private Analysis.Builder dbToWsAnalysis(SnapshotDto dbAnalysis) {
- Analysis.Builder builder = wsAnalysis.clear();
+ var builder = wsAnalysis.clear();
builder
.setKey(dbAnalysis.getUuid())
.setDate(formatDateTime(dbAnalysis.getCreatedAt()))
ofNullable(dbAnalysis.getProjectVersion()).ifPresent(builder::setProjectVersion);
ofNullable(dbAnalysis.getBuildString()).ifPresent(builder::setBuildString);
ofNullable(dbAnalysis.getRevision()).ifPresent(builder::setRevision);
+ ofNullable(searchData.detectedCIs.get(dbAnalysis.getUuid())).ifPresent(builder::setDetectedCI);
return builder;
}
"projectVersion": "1.2",
"buildString": "1.2.0.321",
"manualNewCodePeriodBaseline": false,
+ "detectedCI": "Jenkins",
"events": [
{
"key": "E31",
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.api.web.UserRole;
+import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
+import org.sonar.db.component.AnalysisPropertyDto;
import org.sonar.db.component.BranchDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import static java.lang.String.format;
import static java.util.Optional.ofNullable;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.api.utils.DateUtils.formatDate;
import static org.sonar.api.utils.DateUtils.formatDateTime;
@RunWith(DataProviderRunner.class)
public class SearchActionTest {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
.setCreatedAt(parseDateTime("2015-11-11T10:00:00+0100").getTime())
.setProjectVersion("1.2")
.setBuildString("1.2.0.321"));
+ db.getDbClient().analysisPropertiesDao().insert(db.getSession(), new AnalysisPropertyDto()
+ .setUuid("P1-prop-uuid")
+ .setAnalysisUuid(a3.getUuid())
+ .setKey(CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDCI)
+ .setValue("Jenkins")
+ .setCreatedAt(1L));
BranchDto branchDto = newBranchDto(project, BRANCH);
db.getDbClient().branchDao().insert(db.getSession(), branchDto);
db.newCodePeriods().insert(new NewCodePeriodDto()
userSession.anonymous();
ComponentDto project = db.components().insertPrivateProject();
- expectedException.expect(ForbiddenException.class);
-
- call(project.getDbKey());
+ var projectDbKey = project.getDbKey();
+ assertThatThrownBy(() -> call(projectDbKey))
+ .isInstanceOf(ForbiddenException.class);
}
@Test
public void fail_if_project_does_not_exist() {
- expectedException.expect(NotFoundException.class);
-
- call("P1");
+ assertThatThrownBy(() -> call("P1"))
+ .isInstanceOf(NotFoundException.class);
}
@Test
db.components().insertSnapshot(newAnalysis(project));
userSession.registerComponents(project, file);
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("A project, portfolio or application is required");
-
- call(file.getDbKey());
+ var fileDbKey = file.getDbKey();
+ assertThatThrownBy(() -> call(fileDbKey))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("A project, portfolio or application is required");
}
@Test
userSession.addProjectPermission(UserRole.USER, project);
db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
- expectedException.expect(NotFoundException.class);
- expectedException.expectMessage(format("Component '%s' on branch '%s' not found", project.getKey(), "another_branch"));
-
- call(SearchRequest.builder()
+ var searchRequest = SearchRequest.builder()
.setProject(project.getKey())
.setBranch("another_branch")
- .build());
+ .build();
+
+ assertThatThrownBy(() -> call(searchRequest))
+ .isInstanceOf(NotFoundException.class)
+ .hasMessage(format("Component '%s' on branch '%s' not found", project.getKey(), "another_branch"));
}
@Test
optional string buildString = 5;
optional bool manualNewCodePeriodBaseline = 6;
optional string revision = 7;
+ optional string detectedCI = 8;
}
message QualityGate {