private final Boolean isPrivate;
private final Set<Long> componentIds;
private final Long analyzedBefore;
+ private final boolean onProvisionedOnly;
private ComponentQuery(Builder builder) {
this.nameOrKeyQuery = builder.nameOrKeyQuery;
this.componentIds = builder.componentIds;
this.isPrivate = builder.isPrivate;
this.analyzedBefore = builder.analyzedBefore;
+ this.onProvisionedOnly = builder.onProvisionedOnly;
}
public String[] getQualifiers() {
return analyzedBefore;
}
+ public boolean isOnProvisionedOnly() {
+ return onProvisionedOnly;
+ }
+
public static Builder builder() {
return new Builder();
}
private Boolean isPrivate;
private Set<Long> componentIds;
private Long analyzedBefore;
+ private boolean onProvisionedOnly = false;
public Builder setNameOrKeyQuery(@Nullable String nameOrKeyQuery) {
this.nameOrKeyQuery = nameOrKeyQuery;
return this;
}
+ public Builder setOnProvisionedOnly(boolean onProvisionedOnly) {
+ this.onProvisionedOnly = onProvisionedOnly;
+ return this;
+ }
+
public ComponentQuery build() {
checkArgument(qualifiers != null && qualifiers.length > 0, "At least one qualifier must be provided");
checkArgument(nameOrKeyQuery != null || partialMatchOnKey == null, "A query must be provided if a partial match on key is specified.");
<sql id="sqlSelectByQuery">
from projects p
<if test="query.analyzedBefore!=null">
- inner join snapshots s on s.component_uuid=p.uuid and s.status='P' and s.islast=${_true}
- and s.created_at < #{query.analyzedBefore,jdbcType=BIGINT}
+ inner join snapshots sa on sa.component_uuid=p.uuid
+ and sa.status='P' and sa.islast=${_true} and sa.created_at < #{query.analyzedBefore,jdbcType=BIGINT}
</if>
where
p.enabled=${_true}
and p.private=${_false}
</if>
</if>
+ <if test="query.isOnProvisionedOnly()">
+ and not exists(select 1 from snapshots sp where sp.component_uuid=p.uuid)
+ </if>
</sql>
<select id="selectDescendants" resultType="Component">
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Supplier;
import javax.annotation.Nullable;
import org.apache.ibatis.session.RowBounds;
import org.assertj.core.api.ListAssert;
String viewUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newView(organization)).getComponentUuid();
Set<String> projectQualifiers = newHashSet(Qualifiers.PROJECT);
+ Supplier<ComponentQuery.Builder> query = () -> ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT).setOnProvisionedOnly(true);
assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), null, projectQualifiers, new RowBounds(0, 10)))
.extracting(ComponentDto::uuid)
.containsOnly(provisionedProject.uuid());
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().build(), 0, 10))
+ .extracting(ComponentDto::uuid)
+ .containsOnly(provisionedProject.uuid());
// pagination
- assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), null, projectQualifiers, new RowBounds(2, 10)))
- .isEmpty();
+ assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), null, projectQualifiers, new RowBounds(2, 10))).isEmpty();
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().build(), 2, 10)).isEmpty();
// filter on qualifiers
- assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), null, newHashSet("XXX"), new RowBounds(0, 10)))
- .isEmpty();
+ assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), null, newHashSet("XXX"), new RowBounds(0, 10))).isEmpty();
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().setQualifiers("XXX").build(), 0, 10)).isEmpty();
assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), null, newHashSet(Qualifiers.PROJECT, "XXX"), new RowBounds(0, 10)))
.extracting(ComponentDto::uuid)
.containsOnly(provisionedProject.uuid());
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().setQualifiers(Qualifiers.PROJECT, "XXX").build(), 0, 10))
+ .extracting(ComponentDto::uuid)
+ .containsOnly(provisionedProject.uuid());
assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), null, newHashSet(Qualifiers.PROJECT, Qualifiers.VIEW), new RowBounds(0, 10)))
.extracting(ComponentDto::uuid)
.containsOnly(provisionedProject.uuid(), provisionedView.uuid());
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().setQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW).build(), 0, 10))
+ .extracting(ComponentDto::uuid)
+ .containsOnly(provisionedProject.uuid(), provisionedView.uuid());
// match key
assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), provisionedProject.getDbKey(), projectQualifiers, new RowBounds(0, 10)))
.extracting(ComponentDto::uuid)
.containsExactly(provisionedProject.uuid());
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().setNameOrKeyQuery(provisionedProject.getDbKey()).build(), 0, 10))
+ .extracting(ComponentDto::uuid)
+ .containsExactly(provisionedProject.uuid());
assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), "pROvisiONed.proJEcT", projectQualifiers, new RowBounds(0, 10)))
.extracting(ComponentDto::uuid)
.containsExactly(provisionedProject.uuid());
- assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), "missing", projectQualifiers, new RowBounds(0, 10)))
- .isEmpty();
- assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), "to be escaped '\"\\%", projectQualifiers, new RowBounds(0, 10)))
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().setNameOrKeyQuery("pROvisiONed.proJEcT").setPartialMatchOnKey(true).build(), 0, 10))
+ .extracting(ComponentDto::uuid)
+ .containsExactly(provisionedProject.uuid());
+ assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), "missing", projectQualifiers, new RowBounds(0, 10))).isEmpty();
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().setNameOrKeyQuery("missing").setPartialMatchOnKey(true).build(), 0, 10)).isEmpty();
+ assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), "to be escaped '\"\\%", projectQualifiers, new RowBounds(0, 10))).isEmpty();
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().setNameOrKeyQuery("to be escaped '\"\\%").setPartialMatchOnKey(true).build(), 0, 10))
.isEmpty();
// match name
assertThat(underTest.selectProvisioned(dbSession, organization.getUuid(), "ned proj", projectQualifiers, new RowBounds(0, 10)))
.extracting(ComponentDto::uuid)
.containsExactly(provisionedProject.uuid());
+ assertThat(underTest.selectByQuery(dbSession, organization.getUuid(), query.get().setNameOrKeyQuery("ned proj").setPartialMatchOnKey(true).build(), 0, 10))
+ .extracting(ComponentDto::uuid)
+ .containsExactly(provisionedProject.uuid());
}
@Test
assertThat(underTest.getLanguage()).isEqualTo("java");
assertThat(underTest.getQualifiers()).containsOnly(PROJECT);
assertThat(underTest.getAnalyzedBefore()).isEqualTo(1_000_000_000L);
+ assertThat(underTest.isOnProvisionedOnly()).isFalse();
+ assertThat(underTest.isPartialMatchOnKey()).isFalse();
}
@Test
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_SEARCH;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.MAX_PAGE_SIZE;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
.setDescription("Filter the projects for which last analysis is older than the given date (exclusive).<br> " +
"Format: date or datetime ISO formats.")
.setSince("6.6");
+
+ action.createParam(PARAM_ON_PROVISIONED_ONLY)
+ .setDescription("Filter the projects that are provisioned")
+ .setBooleanPossibleValues()
+ .setDefaultValue("false")
+ .setSince("6.6");
}
@Override
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE))
.setVisibility(request.param(PARAM_VISIBILITY))
.setAnalyzedBefore(request.param(PARAM_ANALYZED_BEFORE))
+ .setOnProvisionedOnly(request.mandatoryParamAsBoolean(PARAM_ON_PROVISIONED_ONLY))
.build();
}
});
setNullable(request.getVisibility(), v -> query.setPrivate(Visibility.isPrivate(v)));
setNullable(request.getAnalyzedBefore(), d -> query.setAnalyzedBefore(parseDateOrDateTime(d).getTime()));
+ setNullable(request.isOnProvisionedOnly(), query::setOnProvisionedOnly);
return query.build();
}
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.Param;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
assertThat(response.getComponentsList()).extracting(Component::getKey).containsExactly("project-key-4", "project-key-5", "project-key-6");
}
+ @Test
+ public void provisioned_projects() {
+ userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
+ ComponentDto provisionedProject = db.components().insertPrivateProject();
+ ComponentDto analyzedProject = db.components().insertPrivateProject();
+ db.components().insertSnapshot(newAnalysis(analyzedProject));
+
+ SearchWsResponse response = call(SearchWsRequest.builder().setOnProvisionedOnly(true).build());
+
+ assertThat(response.getComponentsList()).extracting(Component::getKey)
+ .containsExactlyInAnyOrder(provisionedProject.getKey())
+ .doesNotContain(analyzedProject.getKey());
+ }
+
@Test
public void fail_when_not_system_admin() throws Exception {
userSession.addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization());
assertThat(action.isInternal()).isTrue();
assertThat(action.since()).isEqualTo("6.3");
assertThat(action.handler()).isEqualTo(ws.getDef().handler());
- assertThat(action.params()).hasSize(7);
+ assertThat(action.params()).hasSize(8).extracting(Param::key)
+ .containsExactlyInAnyOrder("organization", "q", "qualifiers", "p", "ps", "visibility", "analyzedBefore", "onProvisionedOnly");
assertThat(action.responseExample()).isEqualTo(getClass().getResource("search-example.json"));
- WebService.Param organization = action.param("organization");
+ Param organization = action.param("organization");
Assertions.assertThat(organization.description()).isEqualTo("The key of the organization");
Assertions.assertThat(organization.isInternal()).isTrue();
Assertions.assertThat(organization.isRequired()).isFalse();
Assertions.assertThat(organization.since()).isEqualTo("6.3");
- WebService.Param qParam = action.param("q");
+ Param qParam = action.param("q");
assertThat(qParam.isRequired()).isFalse();
assertThat(qParam.description()).isEqualTo("Limit search to: " +
"<ul>" +
"<li>component keys that contain the supplied string</li>" +
"</ul>");
- WebService.Param qualifierParam = action.param("qualifiers");
+ Param qualifierParam = action.param("qualifiers");
assertThat(qualifierParam.isRequired()).isFalse();
assertThat(qualifierParam.description()).isEqualTo("Comma-separated list of component qualifiers. Filter the results with the specified qualifiers");
assertThat(qualifierParam.possibleValues()).containsOnly("TRK", "VW", "APP");
assertThat(qualifierParam.defaultValue()).isEqualTo("TRK");
- WebService.Param pParam = action.param("p");
+ Param pParam = action.param("p");
assertThat(pParam.isRequired()).isFalse();
assertThat(pParam.defaultValue()).isEqualTo("1");
assertThat(pParam.description()).isEqualTo("1-based page number");
- WebService.Param psParam = action.param("ps");
+ Param psParam = action.param("ps");
assertThat(psParam.isRequired()).isFalse();
assertThat(psParam.defaultValue()).isEqualTo("100");
assertThat(psParam.description()).isEqualTo("Page size. Must be greater than 0 and less than 500");
- WebService.Param visibilityParam = action.param("visibility");
+ Param visibilityParam = action.param("visibility");
assertThat(visibilityParam.isRequired()).isFalse();
assertThat(visibilityParam.description()).isEqualTo("Filter the projects that should be visible to everyone (public), or only specific user/groups (private).<br/>" +
"If no visibility is specified, the default project visibility of the organization will be used.");
- WebService.Param lastAnalysisBefore = action.param("analyzedBefore");
+ Param lastAnalysisBefore = action.param("analyzedBefore");
assertThat(lastAnalysisBefore.isRequired()).isFalse();
assertThat(lastAnalysisBefore.since()).isEqualTo("6.6");
+
+ Param onProvisionedOnly = action.param("onProvisionedOnly");
+ assertThat(onProvisionedOnly.possibleValues()).containsExactlyInAnyOrder("true", "false", "yes", "no");
+ assertThat(onProvisionedOnly.defaultValue()).isEqualTo("false");
+ assertThat(onProvisionedOnly.since()).isEqualTo("6.6");
}
@Test
setNullable(wsRequest.getPageSize(), pageSize -> request.setParam(PAGE_SIZE, String.valueOf(pageSize)));
setNullable(wsRequest.getVisibility(), v -> request.setParam(PARAM_VISIBILITY, v));
setNullable(wsRequest.getAnalyzedBefore(), d -> request.setParam(PARAM_ANALYZED_BEFORE, d));
+ request.setParam(PARAM_ON_PROVISIONED_ONLY, String.valueOf(wsRequest.isOnProvisionedOnly()));
return request.executeProtobuf(SearchWsResponse.class);
}
import static org.sonar.api.server.ws.WebService.Param.PAGE;
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
-import static org.sonar.api.utils.DateUtils.formatDateTimeNullSafe;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_BULK_UPDATE_KEY;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_CREATE;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_SEARCH;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_BRANCH;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_FROM;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_ID;
.setParam(PARAM_ANALYZED_BEFORE, request.getAnalyzedBefore())
.setParam(TEXT_QUERY, request.getQuery())
.setParam(PAGE, request.getPage())
- .setParam(PAGE_SIZE, request.getPageSize());
+ .setParam(PAGE_SIZE, request.getPageSize())
+ .setParam(PARAM_ON_PROVISIONED_ONLY, request.isOnProvisionedOnly());
return call(get, SearchWsResponse.parser());
}
public static final String PARAM_DRY_RUN = "dryRun";
public static final String PARAM_VISIBILITY = "visibility";
public static final String PARAM_ANALYZED_BEFORE = "analyzedBefore";
+ public static final String PARAM_ON_PROVISIONED_ONLY = "onProvisionedOnly";
public static final String FILTER_LANGUAGES = "languages";
public static final String FILTER_TAGS = "tags";
private final Integer page;
private final Integer pageSize;
private final String analyzedBefore;
+ private final boolean onProvisionedOnly;
public SearchWsRequest(Builder builder) {
this.organization = builder.organization;
this.page = builder.page;
this.pageSize = builder.pageSize;
this.analyzedBefore = builder.analyzedBefore;
+ this.onProvisionedOnly = builder.onProvisionedOnly;
}
@CheckForNull
return analyzedBefore;
}
+ public boolean isOnProvisionedOnly() {
+ return onProvisionedOnly;
+ }
+
public static Builder builder() {
return new Builder();
}
private String query;
private String visibility;
private String analyzedBefore;
+ private boolean onProvisionedOnly = false;
public Builder setOrganization(@Nullable String organization) {
this.organization = organization;
return this;
}
+ public Builder setOnProvisionedOnly(boolean onProvisionedOnly) {
+ this.onProvisionedOnly = onProvisionedOnly;
+ return this;
+ }
+
public SearchWsRequest build() {
checkArgument(pageSize == null || pageSize <= MAX_PAGE_SIZE, "Page size must not be greater than %s", MAX_PAGE_SIZE);
return new SearchWsRequest(this);
.setQuery("project")
.setQualifiers(asList("TRK", "VW"))
.setAnalyzedBefore("2017-09-01")
+ .setOnProvisionedOnly(true)
.setPage(3)
.setPageSize(10)
.build());
.hasParam("q", "project")
.hasParam("analyzedBefore", "2017-09-01")
.hasParam("qualifiers", "TRK,VW")
+ .hasParam("onProvisionedOnly", "true")
.hasParam(PAGE, 3)
.hasParam(PAGE_SIZE, 10)
.andNoOtherParam();
import org.sonarqube.ws.Organizations;
import org.sonarqube.ws.WsProjects.CreateWsResponse;
import org.sonarqube.ws.WsProjects.SearchWsResponse;
+import org.sonarqube.ws.WsProjects.SearchWsResponse.Component;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.project.SearchWsRequest;
.setQualifiers(singletonList("TRK"))
.setAnalyzedBefore(formatDate(oneYearAgo)).build());
- assertThat(result.getComponentsList()).extracting(SearchWsResponse.Component::getKey).containsExactlyInAnyOrder(oldProject.getKey());
+ assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(oldProject.getKey());
}
@Test
.setQuery("JeCt-K")
.build());
- assertThat(result.getComponentsList()).extracting(SearchWsResponse.Component::getKey)
+ assertThat(result.getComponentsList()).extracting(Component::getKey)
.containsExactlyInAnyOrder(lowerCaseProject.getKey(), upperCaseProject.getKey())
.doesNotContain(anotherProject.getKey());
}
String result = tester.wsClient().wsConnector().call(new GetRequest("api/projects/provisioned")
.setParam("organization", organization.getKey()))
.failIfNotSuccessful().content();
-
- assertThat(result)
- .contains(firstProvisionedProject.getKey(), secondProvisionedProject.getKey())
+ SearchWsResponse searchResult = tester.wsClient().projects().search(SearchWsRequest.builder()
+ .setQualifiers(singletonList("TRK"))
+ .setOrganization(organization.getKey())
+ .setOnProvisionedOnly(true).build());
+
+ assertThat(result).contains(firstProvisionedProject.getKey(), secondProvisionedProject.getKey()).doesNotContain(analyzedProject.getKey());
+ assertThat(searchResult.getComponentsList()).extracting(Component::getKey)
+ .containsOnly(firstProvisionedProject.getKey(), secondProvisionedProject.getKey())
.doesNotContain(analyzedProject.getKey());
}