return executeLargeInputs(uuids, mapper(session)::selectProjectUuidsWithIssuesNeedSync);
}
+ public boolean hasAnyBranchWhereNeedIssueSync(DbSession session, boolean needIssueSync) {
+ return mapper(session).hasAnyBranchWhereNeedIssueSync(needIssueSync) > 0;
+ }
+
public boolean hasNonMainBranches(DbSession dbSession) {
return mapper(dbSession).countNonMainBranches() > 0L;
}
long countByTypeAndCreationDate(@Param("branchType") String branchType, @Param("sinceDate") long sinceDate);
+ short hasAnyBranchWhereNeedIssueSync(@Param("needIssueSync") boolean needIssueSync);
}
select count(pb.uuid)
from project_branches pb
where
- pb.branch_type = #{branchType, jdbcType=VARCHAR}
- and pb.created_at >= #{sinceDate, jdbcType=BIGINT}
+ pb.branch_type = #{branchType, jdbcType=VARCHAR}
+ and pb.created_at >= #{sinceDate, jdbcType=BIGINT}
+ </select>
+
+ <select id="hasAnyBranchWhereNeedIssueSync" parameterType="map" resultType="short">
+ select
+ case when exists
+ (
+ select pb.uuid from project_branches pb where need_issue_sync = #{needIssueSync, jdbcType=BOOLEAN}
+ )
+ then 1
+ else 0
+ end
</select>
</mapper>
assertThat(underTest.hasNonMainBranches(dbSession)).isTrue();
}
+ @Test
+ public void hasAnyBranchWhereNeedIssueSync() {
+ assertThat(underTest.hasAnyBranchWhereNeedIssueSync(dbSession, true)).isFalse();
+ assertThat(underTest.hasAnyBranchWhereNeedIssueSync(dbSession, false)).isFalse();
+
+ ComponentDto project = db.components().insertPrivateProject();
+ ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setNeedIssueSync(false));
+
+ assertThat(underTest.hasAnyBranchWhereNeedIssueSync(dbSession, true)).isFalse();
+ assertThat(underTest.hasAnyBranchWhereNeedIssueSync(dbSession, false)).isTrue();
+
+ project = db.components().insertPrivateProject();
+ branch = db.components().insertProjectBranch(project, b -> b.setNeedIssueSync(true));
+ assertThat(underTest.hasAnyBranchWhereNeedIssueSync(dbSession, true)).isTrue();
+ }
+
@Test
public void countByTypeAndCreationDate() {
assertThat(underTest.countByTypeAndCreationDate(dbSession, BranchType.BRANCH, 0L)).isEqualTo(0);
package org.sonar.server.component.ws;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public class ShowAction implements ComponentsWsAction {
private static final Set<String> PROJECT_OR_APP_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.APP);
+ private static final Set<String> VIEW_OR_SUBVIEW_QUALIFIERS = ImmutableSet.of(Qualifiers.VIEW, Qualifiers.SUBVIEW);
private final UserSession userSession;
private final DbClient dbClient;
private final ComponentFinder componentFinder;
Optional<SnapshotDto> lastAnalysis = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, component.projectUuid());
List<ComponentDto> ancestors = dbClient.componentDao().selectAncestors(dbSession, component);
OrganizationDto organizationDto = componentFinder.getOrganization(dbSession, component);
- return buildResponse(dbClient, dbSession, component, organizationDto, ancestors, lastAnalysis.orElse(null));
+ return buildResponse(dbSession, component, organizationDto, ancestors, lastAnalysis.orElse(null));
}
}
return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, componentKey, branch, pullRequest);
}
- private static ShowWsResponse buildResponse(DbClient dbClient, DbSession dbSession, ComponentDto component,
+ private ShowWsResponse buildResponse(DbSession dbSession, ComponentDto component,
OrganizationDto organizationDto, List<ComponentDto> orderedAncestors,
@Nullable SnapshotDto lastAnalysis) {
ShowWsResponse.Builder response = ShowWsResponse.newBuilder();
- response.setComponent(toWsComponent(dbClient, dbSession, component, organizationDto, lastAnalysis));
- addAncestorsToResponse(dbClient, dbSession, response, orderedAncestors, organizationDto, lastAnalysis);
+ response.setComponent(toWsComponent(dbSession, component, organizationDto, lastAnalysis));
+ addAncestorsToResponse(dbSession, response, orderedAncestors, organizationDto, lastAnalysis);
return response.build();
}
- private static void addAncestorsToResponse(DbClient dbClient, DbSession dbSession, ShowWsResponse.Builder response, List<ComponentDto> orderedAncestors,
+ private void addAncestorsToResponse(DbSession dbSession, ShowWsResponse.Builder response, List<ComponentDto> orderedAncestors,
OrganizationDto organizationDto,
@Nullable SnapshotDto lastAnalysis) {
// ancestors are ordered from root to leaf, whereas it's the opposite in WS response
int size = orderedAncestors.size() - 1;
IntStream.rangeClosed(0, size).forEach(
- index -> response.addAncestors(toWsComponent(dbClient, dbSession, orderedAncestors.get(size - index), organizationDto, lastAnalysis)));
+ index -> response.addAncestors(toWsComponent(dbSession, orderedAncestors.get(size - index), organizationDto, lastAnalysis)));
}
- private static Components.Component.Builder toWsComponent(DbClient dbClient, DbSession dbSession, ComponentDto component, OrganizationDto organizationDto,
+ private Components.Component.Builder toWsComponent(DbSession dbSession, ComponentDto component, OrganizationDto organizationDto,
@Nullable SnapshotDto lastAnalysis) {
if (isProjectOrApp(component)) {
ProjectDto project = dbClient.projectDao().selectProjectOrAppByKey(dbSession, component.getKey())
.orElseThrow(() -> new IllegalStateException("Project is in invalid state."));
- return projectOrAppToWsComponent(project, organizationDto, lastAnalysis);
+ boolean needIssueSync = needIssueSync(dbSession, component, project);
+ return projectOrAppToWsComponent(project, organizationDto, lastAnalysis)
+ .setNeedIssueSync(needIssueSync);
} else {
Optional<ProjectDto> parentProject = dbClient.projectDao().selectByUuid(dbSession,
ofNullable(component.getMainBranchProjectUuid()).orElse(component.projectUuid()));
- return componentDtoToWsComponent(component, parentProject.orElse(null), organizationDto, lastAnalysis);
+ boolean needIssueSync = needIssueSync(dbSession, component, parentProject.orElse(null));
+ return componentDtoToWsComponent(component, parentProject.orElse(null), organizationDto, lastAnalysis)
+ .setNeedIssueSync(needIssueSync);
}
}
return component.getMainBranchProjectUuid() == null && PROJECT_OR_APP_QUALIFIERS.contains(component.qualifier());
}
+ private boolean needIssueSync(DbSession dbSession, ComponentDto component, @Nullable ProjectDto projectDto) {
+ if (projectDto == null || VIEW_OR_SUBVIEW_QUALIFIERS.contains(component.qualifier())) {
+ return dbClient.branchDao().hasAnyBranchWhereNeedIssueSync(dbSession, true);
+ }
+
+ return !dbClient.branchDao().selectProjectUuidsWithIssuesNeedSync(dbSession, Sets.newHashSet(projectDto.getUuid())).isEmpty();
+ }
+
private static Request toShowWsRequest(org.sonar.api.server.ws.Request request) {
return new Request()
.setComponentKey(request.mandatoryParam(PARAM_COMPONENT))
package org.sonar.server.component.ws;
import java.util.Date;
+import java.util.Optional;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbTester;
+import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.component.TestComponentFinder;
import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.api.utils.DateUtils.parseDateTime;
import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.db.component.BranchType.BRANCH;
import static org.sonar.db.component.BranchType.PULL_REQUEST;
import static org.sonar.db.component.ComponentTesting.newDirectory;
import static org.sonar.db.component.ComponentTesting.newFileDto;
tuple(branch.getKey(), pullRequest, "1.1"));
}
+ @Test
+ public void verify_need_issue_sync_pr() {
+ ComponentDto portfolio1 = db.components().insertPublicPortfolio(db.getDefaultOrganization());
+ ComponentDto portfolio2 = db.components().insertPublicPortfolio(db.getDefaultOrganization());
+ ComponentDto subview = db.components().insertSubView(portfolio1);
+
+ ComponentDto project1 = db.components().insertPrivateProject();
+ ComponentDto branch1 = db.components().insertProjectBranch(project1, b -> b.setBranchType(PULL_REQUEST).setNeedIssueSync(true));
+ ComponentDto module = db.components().insertComponent(newModuleDto(branch1));
+ ComponentDto directory = db.components().insertComponent(newDirectory(module, "dir"));
+ ComponentDto file = db.components().insertComponent(newFileDto(directory));
+
+ ComponentDto project2 = db.components().insertPrivateProject();
+ ComponentDto branch2 = db.components().insertProjectBranch(project2, b -> b.setBranchType(BRANCH).setNeedIssueSync(true));
+ ComponentDto branch3 = db.components().insertProjectBranch(project2, b -> b.setBranchType(BRANCH).setNeedIssueSync(false));
+
+ ComponentDto project3 = db.components().insertPrivateProject();
+ ComponentDto branch4 = db.components().insertProjectBranch(project3, b -> b.setBranchType(PULL_REQUEST).setNeedIssueSync(false));
+ ComponentDto moduleOfBranch4 = db.components().insertComponent(newModuleDto(branch4));
+ ComponentDto directoryOfBranch4 = db.components().insertComponent(newDirectory(moduleOfBranch4, "dir"));
+ ComponentDto fileOfBranch4 = db.components().insertComponent(newFileDto(directoryOfBranch4));
+ ComponentDto branch5 = db.components().insertProjectBranch(project3, b -> b.setBranchType(BRANCH).setNeedIssueSync(false));
+
+ userSession.addMembership(db.getDefaultOrganization());
+ userSession.addProjectPermission(UserRole.USER, project1, project2, project3);
+ userSession.registerComponents(portfolio1, portfolio2, subview, project1, project2, project3);
+
+ //for portfolios, sub-views need issue sync flag is set to true if any project need sync
+ assertNeedIssueSyncEqual(null, null, portfolio1, true);
+ assertNeedIssueSyncEqual(null, null, subview, true);
+ assertNeedIssueSyncEqual(null, null, portfolio2, true);
+
+ //if branch need sync it is propagated to other components
+ assertNeedIssueSyncEqual(null, null, project1, true);
+ assertNeedIssueSyncEqual(branch1.getPullRequest(), null, branch1, true);
+ assertNeedIssueSyncEqual(branch1.getPullRequest(), null, module, true);
+ assertNeedIssueSyncEqual(branch1.getPullRequest(), null, directory, true);
+ assertNeedIssueSyncEqual(branch1.getPullRequest(), null, file, true);
+
+ assertNeedIssueSyncEqual(null, null, project2, true);
+ assertNeedIssueSyncEqual(null, branch2.getBranch(), branch2, true);
+ assertNeedIssueSyncEqual(null, branch3.getBranch(), branch3, true);
+
+ //if all branches are synced, need issue sync on project is is set to false
+ assertNeedIssueSyncEqual(null, null, project3, false);
+ assertNeedIssueSyncEqual(branch4.getPullRequest(), null, branch4, false);
+ assertNeedIssueSyncEqual(branch4.getPullRequest(), null, moduleOfBranch4, false);
+ assertNeedIssueSyncEqual(branch4.getPullRequest(), null, directoryOfBranch4, false);
+ assertNeedIssueSyncEqual(branch4.getPullRequest(), null, fileOfBranch4, false);
+ assertNeedIssueSyncEqual(null, branch5.getBranch(), branch5, false);
+ }
+
+ private void assertNeedIssueSyncEqual(@Nullable String pullRequest, @Nullable String branch, ComponentDto component, boolean needIssueSync) {
+ TestRequest testRequest = ws.newRequest()
+ .setParam(PARAM_COMPONENT, component.getKey());
+
+ Optional.ofNullable(pullRequest).ifPresent(pr -> testRequest.setParam(PARAM_PULL_REQUEST, pr));
+ Optional.ofNullable(branch).ifPresent(br -> testRequest.setParam(PARAM_BRANCH, br));
+
+ ShowWsResponse response = testRequest.executeProtobuf(ShowWsResponse.class);
+
+ assertThat(response.getComponent())
+ .extracting(Component::getNeedIssueSync)
+ .isEqualTo(needIssueSync);
+ }
+
@Test
public void throw_ForbiddenException_if_user_doesnt_have_browse_permission_on_project() {
userSession.logIn();