@@ -690,42 +690,6 @@ public class BranchDaoIT { | |||
assertThat(underTest.countByTypeAndCreationDate(dbSession, BranchType.PULL_REQUEST, NOW + 100)).isZero(); | |||
} | |||
@Test | |||
public void countByNeedIssueSync() { | |||
assertThat(underTest.countByNeedIssueSync(dbSession, true)).isZero(); | |||
assertThat(underTest.countByNeedIssueSync(dbSession, false)).isZero(); | |||
// master branch with flag set to false | |||
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); | |||
// branches & PRs | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(true)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(true)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(false)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(false)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST).setNeedIssueSync(true)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST).setNeedIssueSync(false)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST).setNeedIssueSync(true)); | |||
assertThat(underTest.countByNeedIssueSync(dbSession, true)).isEqualTo(4); | |||
assertThat(underTest.countByNeedIssueSync(dbSession, false)).isEqualTo(4); | |||
} | |||
@Test | |||
public void countAll() { | |||
assertThat(underTest.countAll(dbSession)).isZero(); | |||
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(true)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(true)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(false)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(false)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST).setNeedIssueSync(true)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST).setNeedIssueSync(false)); | |||
db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST).setNeedIssueSync(true)); | |||
assertThat(underTest.countAll(dbSession)).isEqualTo(8); | |||
} | |||
@Test | |||
public void selectBranchNeedingIssueSync() { | |||
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); |
@@ -43,6 +43,7 @@ import org.sonar.db.Pagination; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.NoOpAuditPersister; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ProjectData; | |||
import org.sonar.db.measure.LiveMeasureDto; | |||
@@ -369,6 +370,33 @@ public class ProjectDaoIT { | |||
assertThat(projectDtos).extracting(ProjectDto::getName).containsOnly("Project_2", "Project_3"); | |||
} | |||
@Test | |||
public void countIndexedProjects() { | |||
assertThat(projectDao.countIndexedProjects(db.getSession())).isZero(); | |||
// master branch with flag set to false | |||
ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent(); | |||
ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent(); | |||
// branches & PRs | |||
db.components().insertProjectBranch(project1, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(true)); | |||
db.components().insertProjectBranch(project1, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(false)); | |||
db.components().insertProjectBranch(project2, b -> b.setBranchType(BranchType.BRANCH).setNeedIssueSync(false)); | |||
db.components().insertProjectBranch(project1, b -> b.setBranchType(BranchType.PULL_REQUEST).setNeedIssueSync(true)); | |||
db.components().insertProjectBranch(project1, b -> b.setBranchType(BranchType.PULL_REQUEST).setNeedIssueSync(false)); | |||
db.components().insertProjectBranch(project2, b -> b.setBranchType(BranchType.PULL_REQUEST).setNeedIssueSync(false)); | |||
assertThat(projectDao.countIndexedProjects(db.getSession())).isEqualTo(1); | |||
} | |||
@Test | |||
public void countProjects() { | |||
assertThat(projectDao.countProjects(db.getSession())).isZero(); | |||
IntStream.range(0, 10).forEach(x -> db.components().insertPrivateProject()); | |||
assertThat(projectDao.countProjects(db.getSession())).isEqualTo(10); | |||
} | |||
private void insertDefaultQualityProfile(String language) { | |||
QProfileDto profile = db.qualityProfiles().insert(qp -> qp.setIsBuiltIn(true).setLanguage(language)); | |||
db.qualityProfiles().setAsDefault(profile); |
@@ -160,14 +160,6 @@ public class BranchDao implements Dao { | |||
return mapper(dbSession).countByTypeAndCreationDate(branchType.name(), sinceDate); | |||
} | |||
public int countByNeedIssueSync(DbSession session, boolean needIssueSync) { | |||
return mapper(session).countByNeedIssueSync(needIssueSync); | |||
} | |||
public int countAll(DbSession session) { | |||
return mapper(session).countAll(); | |||
} | |||
private static BranchMapper mapper(DbSession dbSession) { | |||
return dbSession.getMapper(BranchMapper.class); | |||
} |
@@ -58,10 +58,6 @@ public interface BranchMapper { | |||
short hasAnyBranchWhereNeedIssueSync(@Param("needIssueSync") boolean needIssueSync); | |||
int countByNeedIssueSync(@Param("needIssueSync") boolean needIssueSync); | |||
int countAll(); | |||
List<BranchDto> selectBranchNeedingIssueSync(); | |||
List<BranchDto> selectBranchNeedingIssueSyncForProject(@Param("projectUuid") String projectUuid); |
@@ -152,4 +152,12 @@ public class ProjectDao implements Dao { | |||
public long getNclocSum(DbSession dbSession, @Nullable String projectUuidToExclude) { | |||
return Optional.ofNullable(mapper(dbSession).getNclocSum(projectUuidToExclude)).orElse(0L); | |||
} | |||
public int countIndexedProjects(DbSession session) { | |||
return mapper(session).countIndexedProjects(); | |||
} | |||
public int countProjects(DbSession session) { | |||
return mapper(session).countProjects(); | |||
} | |||
} |
@@ -74,4 +74,8 @@ public interface ProjectMapper { | |||
@CheckForNull | |||
Long getNclocSum(@Nullable @Param("projectUuidToExclude") String projectUuidToExclude); | |||
int countIndexedProjects(); | |||
int countProjects(); | |||
} |
@@ -228,20 +228,6 @@ | |||
from dual | |||
</select> | |||
<select id="countByNeedIssueSync" parameterType="map" resultType="int"> | |||
select | |||
count(pb.uuid) | |||
from project_branches pb | |||
where | |||
pb.need_issue_sync = #{needIssueSync, jdbcType=BOOLEAN} | |||
</select> | |||
<select id="countAll" parameterType="map" resultType="int"> | |||
select | |||
count(pb.uuid) | |||
from project_branches pb | |||
</select> | |||
<select id="selectBranchNeedingIssueSync" resultType="org.sonar.db.component.BranchDto"> | |||
select | |||
<include refid="columns"/> |
@@ -217,4 +217,18 @@ | |||
and uuid <> #{projectUuidToExclude,jdbcType=VARCHAR} | |||
</if> | |||
</select> | |||
<select id="countIndexedProjects" resultType="int"> | |||
select count(p.uuid) | |||
from projects p | |||
where p.qualifier = 'TRK' | |||
and not exists (select 1 from project_branches pb where pb.project_uuid = p.uuid and pb.need_issue_sync = ${_true}) | |||
</select> | |||
<select id="countProjects" resultType="int"> | |||
select count(p.uuid) | |||
from projects p | |||
where p.qualifier = 'TRK' | |||
</select> | |||
</mapper> |
@@ -41,11 +41,11 @@ public class IssueIndexSyncProgressChecker { | |||
} | |||
public IssueSyncProgress getIssueSyncProgress(DbSession dbSession) { | |||
int completed = dbClient.branchDao().countByNeedIssueSync(dbSession, false); | |||
int completedCount = dbClient.projectDao().countIndexedProjects(dbSession); | |||
int total = dbClient.projectDao().countProjects(dbSession); | |||
boolean hasFailures = dbClient.ceActivityDao().hasAnyFailedOrCancelledIssueSyncTask(dbSession); | |||
boolean isCompleted = !dbClient.ceQueueDao().hasAnyIssueSyncTaskPendingOrInProgress(dbSession); | |||
int total = dbClient.branchDao().countAll(dbSession); | |||
return new IssueSyncProgress(isCompleted, completed, total, hasFailures); | |||
return new IssueSyncProgress(isCompleted, completedCount, total, hasFailures); | |||
} | |||
public void checkIfAnyComponentsNeedIssueSync(DbSession dbSession, List<String> componentKeys) { |
@@ -20,23 +20,21 @@ | |||
package org.sonar.server.issue.index; | |||
public class IssueSyncProgress { | |||
private static final int PERCENT_100 = 100; | |||
private final int completed; | |||
private final int completedCount; | |||
private final int total; | |||
private final boolean hasFailures; | |||
private final boolean isCompleted; | |||
public IssueSyncProgress(boolean isCompleted, int completed, int total, boolean hasFailures) { | |||
this.completed = completed; | |||
public IssueSyncProgress(boolean isCompleted, int completedCount, int total, boolean hasFailures) { | |||
this.completedCount = completedCount; | |||
this.hasFailures = hasFailures; | |||
this.isCompleted = isCompleted; | |||
this.total = total; | |||
} | |||
public int getCompleted() { | |||
return completed; | |||
public int getCompletedCount() { | |||
return completedCount; | |||
} | |||
public boolean hasFailures() { | |||
@@ -47,14 +45,7 @@ public class IssueSyncProgress { | |||
return total; | |||
} | |||
public int toPercentCompleted() { | |||
if (total != 0) { | |||
return (int) Math.floor(PERCENT_100 * (double) completed / total); | |||
} | |||
return PERCENT_100; | |||
} | |||
public boolean isCompleted() { | |||
return completed == total || isCompleted; | |||
return completedCount == total || isCompleted; | |||
} | |||
} |
@@ -19,9 +19,7 @@ | |||
*/ | |||
package org.sonar.server.issue.index; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.List; | |||
@@ -56,30 +54,27 @@ public class IssueIndexSyncProgressCheckerTest { | |||
private final IssueIndexSyncProgressChecker underTest = new IssueIndexSyncProgressChecker(db.getDbClient()); | |||
@Test | |||
public void return_100_if_there_is_no_tasks_left() { | |||
public void getIssueSyncProgress_whenNoTasksLeft_shouldReturnCompleted() { | |||
IssueSyncProgress issueSyncProgress = underTest.getIssueSyncProgress(db.getSession()); | |||
assertThat(issueSyncProgress.getCompleted()).isZero(); | |||
assertThat(issueSyncProgress.getCompletedCount()).isZero(); | |||
assertThat(issueSyncProgress.getTotal()).isZero(); | |||
assertThat(issueSyncProgress.toPercentCompleted()).isEqualTo(100); | |||
assertThat(issueSyncProgress.isCompleted()).isTrue(); | |||
assertThat(issueSyncProgress.hasFailures()).isFalse(); | |||
} | |||
@Test | |||
public void return_100_if_all_branches_have_need_issue_sync_set_FALSE() { | |||
IntStream.range(0, 13).forEach(value -> insertProjectWithBranches(false, 2)); | |||
IntStream.range(0, 14).forEach(value -> insertProjectWithBranches(false, 4)); | |||
IntStream.range(0, 4).forEach(value -> insertProjectWithBranches(false, 10)); | |||
public void getIssueSyncProgress_whenNoBranchesNeedsIssueSync_shouldReturnCompleted() { | |||
IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1)); | |||
IntStream.range(0, 20).forEach(value -> insertProjectWithBranches(false, 2)); | |||
IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession()); | |||
assertThat(result.getCompleted()).isEqualTo(153); | |||
assertThat(result.getTotal()).isEqualTo(153); | |||
assertThat(result.toPercentCompleted()).isEqualTo(100); | |||
assertThat(result.getCompletedCount()).isEqualTo(30); | |||
assertThat(result.getTotal()).isEqualTo(30); | |||
assertThat(result.isCompleted()).isTrue(); | |||
} | |||
@Test | |||
public void return_has_failure_true_if_exists_task() { | |||
public void getIssueSyncProgress_whenTasksExist_shouldReturnFailures() { | |||
assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isFalse(); | |||
ProjectData projectData1 = insertProjectWithBranches(false, 0); | |||
@@ -97,36 +92,8 @@ public class IssueIndexSyncProgressCheckerTest { | |||
} | |||
@Test | |||
@UseDataProvider("various_task_numbers") | |||
public void return_correct_percent_value_for_branches_to_sync(int toSync, int synced, int expectedPercent) { | |||
IntStream.range(0, toSync).forEach(value -> insertProjectWithBranches(true, 0)); | |||
IntStream.range(0, synced).forEach(value -> insertProjectWithBranches(false, 0)); | |||
IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession()); | |||
assertThat(result.getCompleted()).isEqualTo(synced); | |||
assertThat(result.getTotal()).isEqualTo(toSync + synced); | |||
assertThat(result.toPercentCompleted()).isEqualTo(expectedPercent); | |||
} | |||
@DataProvider | |||
public static Object[][] various_task_numbers() { | |||
return new Object[][] { | |||
// toSync, synced, expected result | |||
{0, 0, 100}, | |||
{0, 9, 100}, | |||
{10, 0, 0}, | |||
{99, 1, 1}, | |||
{2, 1, 33}, | |||
{6, 4, 40}, | |||
{7, 7, 50}, | |||
{1, 2, 66}, | |||
{4, 10, 71}, | |||
{1, 99, 99}, | |||
}; | |||
} | |||
@Test | |||
public void return_0_if_all_branches_have_need_issue_sync_set_true() { | |||
public void getIssueSyncProgress_whenBranchesNeedIssueSync_shouldReturnNotCompleted() { | |||
insertCeQueue("TASK_1", Status.PENDING); | |||
// only project | |||
IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0)); | |||
@@ -134,9 +101,9 @@ public class IssueIndexSyncProgressCheckerTest { | |||
IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 1)); | |||
IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession()); | |||
assertThat(result.getCompleted()).isZero(); | |||
assertThat(result.getTotal()).isEqualTo(30); | |||
assertThat(result.toPercentCompleted()).isZero(); | |||
assertThat(result.getCompletedCount()).isZero(); | |||
assertThat(result.getTotal()).isEqualTo(20); | |||
assertThat(result.isCompleted()).isFalse(); | |||
} | |||
@Test |
@@ -48,7 +48,7 @@ public class IndexationStatusActionIT { | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
private WsActionTester ws = new WsActionTester(new IndexationStatusAction(db.getDbClient(), issueIndexSyncProgressCheckerMock)); | |||
private final WsActionTester ws = new WsActionTester(new IndexationStatusAction(db.getDbClient(), issueIndexSyncProgressCheckerMock)); | |||
@Test | |||
public void definition() { | |||
@@ -61,27 +61,29 @@ public class IndexationStatusActionIT { | |||
@Test | |||
public void verify_example_of_response() { | |||
when(issueIndexSyncProgressCheckerMock.getIssueSyncProgress(any())).thenReturn(new IssueSyncProgress(true,0, 0, false)); | |||
when(issueIndexSyncProgressCheckerMock.getIssueSyncProgress(any())).thenReturn(new IssueSyncProgress(false, 22, 38, false)); | |||
ws.newRequest().execute().assertJson(ws.getDef().responseExampleAsString()); | |||
} | |||
@Test | |||
public void return_100_if_there_is_no_tasks_left() { | |||
public void call_whenNoTasksLeft_shouldReturnCompleted() { | |||
when(issueIndexSyncProgressCheckerMock.getIssueSyncProgress(any())).thenReturn(new IssueSyncProgress(true, 10, 10, false)); | |||
IndexationStatusWsResponse response = ws.newRequest() | |||
.executeProtobuf(IndexationStatusWsResponse.class); | |||
assertThat(response.getPercentCompleted()).isEqualTo(100); | |||
assertThat(response.getCompletedCount()).isEqualTo(10); | |||
assertThat(response.getTotal()).isEqualTo(10); | |||
assertThat(response.getIsCompleted()).isTrue(); | |||
assertThat(response.getHasFailures()).isFalse(); | |||
} | |||
@Test | |||
public void return_0_if_all_branches_have_need_issue_sync_set_TRUE() { | |||
when(issueIndexSyncProgressCheckerMock.getIssueSyncProgress(any())).thenReturn(new IssueSyncProgress(false,0, 10, false)); | |||
public void call_whenBranchesNeedIssueSync_shouldReturnNotCompleted() { | |||
when(issueIndexSyncProgressCheckerMock.getIssueSyncProgress(any())).thenReturn(new IssueSyncProgress(false, 0, 10, false)); | |||
IndexationStatusWsResponse response = ws.newRequest() | |||
.executeProtobuf(IndexationStatusWsResponse.class); | |||
assertThat(response.getPercentCompleted()).isZero(); | |||
assertThat(response.getCompletedCount()).isZero(); | |||
assertThat(response.getTotal()).isEqualTo(10); | |||
assertThat(response.getIsCompleted()).isFalse(); | |||
assertThat(response.getHasFailures()).isFalse(); | |||
} |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.ce.ws; | |||
import org.sonar.api.server.ws.Change; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
@@ -42,8 +43,9 @@ public class IndexationStatusAction implements CeWsAction { | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
controller.createAction("indexation_status") | |||
.setDescription("Returns percentage of completed issue synchronization.") | |||
.setDescription("Returns the count of projects with completed issue indexation.") | |||
.setResponseExample(getClass().getResource("indexation_status-example.json")) | |||
.setChangelog(new Change("10.2", "Project count is returned instead of branch percentage.")) | |||
.setHandler(this) | |||
.setInternal(true) | |||
.setSince("8.4"); | |||
@@ -63,8 +65,9 @@ public class IndexationStatusAction implements CeWsAction { | |||
return IndexationStatusWsResponse.newBuilder() | |||
.setIsCompleted(issueSyncProgress.isCompleted()) | |||
.setPercentCompleted(issueSyncProgress.toPercentCompleted()) | |||
.setHasFailures(issueSyncProgress.hasFailures()) | |||
.setCompletedCount(issueSyncProgress.getCompletedCount()) | |||
.setTotal(issueSyncProgress.getTotal()) | |||
.build(); | |||
} | |||
@@ -1,5 +1,6 @@ | |||
{ | |||
"isCompleted": true, | |||
"percentCompleted": 100, | |||
"hasFailures": false | |||
"isCompleted": false, | |||
"hasFailures": false, | |||
"completedCount": 22, | |||
"total": 38 | |||
} |
@@ -55,8 +55,9 @@ message ActivityStatusWsResponse { | |||
// GET api/ce/indexation_status | |||
message IndexationStatusWsResponse { | |||
optional bool isCompleted = 1; | |||
optional int32 percentCompleted = 2; | |||
optional bool hasFailures = 3; | |||
optional bool hasFailures = 2; | |||
optional int32 completedCount = 3; | |||
optional int32 total = 4; | |||
} | |||
// GET api/ce/analysis_status |