@@ -39,7 +39,6 @@ import static org.assertj.core.api.Assertions.tuple; | |||
public class GitlabHttpClientTest { | |||
@Rule | |||
public LogTester logTester = new LogTester(); | |||
@@ -132,7 +131,7 @@ public class GitlabHttpClientTest { | |||
} | |||
@Test | |||
public void get_branches(){ | |||
public void get_branches() { | |||
MockResponse response = new MockResponse() | |||
.setResponseCode(200) | |||
.setBody("[{\n" | |||
@@ -219,12 +218,12 @@ public class GitlabHttpClientTest { | |||
assertThat(projectList.getProjects()).hasSize(3); | |||
assertThat(projectList.getProjects()).extracting( | |||
Project::getId, Project::getName, Project::getNameWithNamespace, Project::getPath, Project::getPathWithNamespace, Project::getWebUrl).containsExactly( | |||
tuple(1L, "SonarQube example 1", "SonarSource / SonarQube / SonarQube example 1", "sonarqube-example-1", "sonarsource/sonarqube/sonarqube-example-1", | |||
"https://example.gitlab.com/sonarsource/sonarqube/sonarqube-example-1"), | |||
tuple(2L, "SonarQube example 2", "SonarSource / SonarQube / SonarQube example 2", "sonarqube-example-2", "sonarsource/sonarqube/sonarqube-example-2", | |||
"https://example.gitlab.com/sonarsource/sonarqube/sonarqube-example-2"), | |||
tuple(3L, "SonarQube example 3", "SonarSource / SonarQube / SonarQube example 3", "sonarqube-example-3", "sonarsource/sonarqube/sonarqube-example-3", | |||
"https://example.gitlab.com/sonarsource/sonarqube/sonarqube-example-3")); | |||
tuple(1L, "SonarQube example 1", "SonarSource / SonarQube / SonarQube example 1", "sonarqube-example-1", "sonarsource/sonarqube/sonarqube-example-1", | |||
"https://example.gitlab.com/sonarsource/sonarqube/sonarqube-example-1"), | |||
tuple(2L, "SonarQube example 2", "SonarSource / SonarQube / SonarQube example 2", "sonarqube-example-2", "sonarsource/sonarqube/sonarqube-example-2", | |||
"https://example.gitlab.com/sonarsource/sonarqube/sonarqube-example-2"), | |||
tuple(3L, "SonarQube example 3", "SonarSource / SonarQube / SonarQube example 3", "sonarqube-example-3", "sonarsource/sonarqube/sonarqube-example-3", | |||
"https://example.gitlab.com/sonarsource/sonarqube/sonarqube-example-3")); | |||
RecordedRequest projectGitlabRequest = server.takeRequest(10, TimeUnit.SECONDS); | |||
String gitlabUrlCall = projectGitlabRequest.getRequestUrl().toString(); | |||
@@ -320,8 +319,8 @@ public class GitlabHttpClientTest { | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Could not validate GitLab read permission. Got an unexpected answer."); | |||
assertThat(logTester.logs(LoggerLevel.INFO).get(0)) | |||
.contains("Gitlab API call to [http://localhost:"+server.getPort()+"/projects] " + | |||
"failed with error message : [Failed to connect to localhost"); | |||
.contains("Gitlab API call to [" + server.url("/projects") + "] " + | |||
"failed with error message : [Failed to connect to " + server.getHostName()); | |||
} | |||
@Test | |||
@@ -332,8 +331,8 @@ public class GitlabHttpClientTest { | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Could not validate GitLab token. Got an unexpected answer."); | |||
assertThat(logTester.logs(LoggerLevel.INFO).get(0)) | |||
.contains("Gitlab API call to [http://localhost:"+server.getPort()+"/user] " + | |||
"failed with error message : [Failed to connect to localhost"); | |||
.contains("Gitlab API call to [" + server.url("user") + "] " + | |||
"failed with error message : [Failed to connect to " + server.getHostName()); | |||
} | |||
@Test | |||
@@ -344,8 +343,8 @@ public class GitlabHttpClientTest { | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Could not validate GitLab write permission. Got an unexpected answer."); | |||
assertThat(logTester.logs(LoggerLevel.INFO).get(0)) | |||
.contains("Gitlab API call to [http://localhost:"+server.getPort()+"/markdown] " + | |||
"failed with error message : [Failed to connect to localhost"); | |||
.contains("Gitlab API call to [" + server.url("/markdown") + "] " + | |||
"failed with error message : [Failed to connect to " + server.getHostName()); | |||
} | |||
@Test | |||
@@ -354,10 +353,10 @@ public class GitlabHttpClientTest { | |||
assertThatThrownBy(() -> underTest.getProject(gitlabUrl, "token", 0L)) | |||
.isInstanceOf(IllegalStateException.class) | |||
.hasMessageContaining("Failed to connect to localhost"); | |||
.hasMessageContaining("Failed to connect to"); | |||
assertThat(logTester.logs(LoggerLevel.INFO).get(0)) | |||
.contains("Gitlab API call to [http://localhost:"+server.getPort()+"/projects/0] " + | |||
"failed with error message : [Failed to connect to localhost"); | |||
.contains("Gitlab API call to [" + server.url("/projects/0") + "] " + | |||
"failed with error message : [Failed to connect to " + server.getHostName()); | |||
} | |||
@Test | |||
@@ -366,10 +365,10 @@ public class GitlabHttpClientTest { | |||
assertThatThrownBy(() -> underTest.getBranches(gitlabUrl, "token", 0L)) | |||
.isInstanceOf(IllegalStateException.class) | |||
.hasMessageContaining("Failed to connect to localhost"); | |||
.hasMessageContaining("Failed to connect to " + server.getHostName()); | |||
assertThat(logTester.logs(LoggerLevel.INFO).get(0)) | |||
.contains("Gitlab API call to [http://localhost:"+server.getPort()+"/projects/0/repository/branches] " + | |||
"failed with error message : [Failed to connect to localhost"); | |||
.contains("Gitlab API call to [" + server.url("/projects/0/repository/branches") + "] " + | |||
"failed with error message : [Failed to connect to " + server.getHostName()); | |||
} | |||
@Test | |||
@@ -378,9 +377,11 @@ public class GitlabHttpClientTest { | |||
assertThatThrownBy(() -> underTest.searchProjects(gitlabUrl, "token", null, 1, 1)) | |||
.isInstanceOf(IllegalStateException.class) | |||
.hasMessageContaining("Failed to connect to localhost"); | |||
.hasMessageContaining("Failed to connect to"); | |||
assertThat(logTester.logs(LoggerLevel.INFO).get(0)) | |||
.contains("Gitlab API call to [http://localhost:"+server.getPort()+"/projects?archived=false&simple=true&membership=true&order_by=name&sort=asc&search=&page=1&per_page=1] " + | |||
"failed with error message : [Failed to connect to localhost"); | |||
.contains( | |||
"Gitlab API call to [" + server.url("/projects?archived=false&simple=true&membership=true&order_by=name&sort=asc&search=&page=1&per_page=1") | |||
+ "] " + | |||
"failed with error message : [Failed to connect to " + server.getHostName()); | |||
} | |||
} |
@@ -33,7 +33,9 @@ import org.sonar.db.component.KeyWithUuidDto; | |||
import static org.sonar.db.component.ComponentDto.removeBranchAndPullRequestFromKey; | |||
/** | |||
* Cache a map of component key -> set<uuid> in sibling PRs that have open issues | |||
* Cache a map of component key -> set<uuid> in: | |||
* - sibling PRs that have open issues | |||
* - branches that use reference branch as new code period setting and have it set to currently analysed branch | |||
*/ | |||
public class SiblingComponentsWithOpenIssues { | |||
private final DbClient dbClient; | |||
@@ -52,18 +54,37 @@ public class SiblingComponentsWithOpenIssues { | |||
String currentBranchUuid = treeRootHolder.getRoot().getUuid(); | |||
String referenceBranchUuid; | |||
if (metadataHolder.isPullRequest()) { | |||
referenceBranchUuid = metadataHolder.getBranch().getReferenceBranchUuid(); | |||
} else { | |||
referenceBranchUuid = currentBranchUuid; | |||
} | |||
uuidsByKey = new HashMap<>(); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
List<KeyWithUuidDto> components = dbClient.componentDao().selectAllSiblingComponentKeysHavingOpenIssues(dbSession, referenceBranchUuid, currentBranchUuid); | |||
for (KeyWithUuidDto dto : components) { | |||
uuidsByKey.computeIfAbsent(removeBranchAndPullRequestFromKey(dto.key()), s -> new HashSet<>()).add(dto.uuid()); | |||
if (metadataHolder.isPullRequest()) { | |||
referenceBranchUuid = metadataHolder.getBranch().getReferenceBranchUuid(); | |||
} else { | |||
referenceBranchUuid = currentBranchUuid; | |||
addComponentsFromBranchesThatUseCurrentBranchAsNewCodePeriodReferenceAndHaveOpenIssues(dbSession); | |||
} | |||
addComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues(dbSession, referenceBranchUuid, currentBranchUuid); | |||
} | |||
} | |||
private void addComponentsFromBranchesThatUseCurrentBranchAsNewCodePeriodReferenceAndHaveOpenIssues(DbSession dbSession) { | |||
String projectUuid = metadataHolder.getProject().getUuid(); | |||
String currentBranchName = metadataHolder.getBranch().getName(); | |||
Set<String> branchUuids = dbClient.newCodePeriodDao().selectBranchesReferencing(dbSession, projectUuid, currentBranchName); | |||
List<KeyWithUuidDto> components = dbClient.componentDao().selectComponentsFromBranchesThatHaveOpenIssues(dbSession, branchUuids); | |||
for (KeyWithUuidDto dto : components) { | |||
uuidsByKey.computeIfAbsent(removeBranchAndPullRequestFromKey(dto.key()), s -> new HashSet<>()).add(dto.uuid()); | |||
} | |||
} | |||
private void addComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues(DbSession dbSession, String referenceBranchUuid, String currentBranchUuid) { | |||
List<KeyWithUuidDto> components = dbClient.componentDao().selectComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues( | |||
dbSession, referenceBranchUuid, currentBranchUuid); | |||
for (KeyWithUuidDto dto : components) { | |||
uuidsByKey.computeIfAbsent(removeBranchAndPullRequestFromKey(dto.key()), s -> new HashSet<>()).add(dto.uuid()); | |||
} | |||
} | |||
@@ -31,6 +31,7 @@ import org.sonar.core.issue.DefaultIssueComment; | |||
import org.sonar.core.issue.FieldDiffs; | |||
import org.sonar.core.issue.IssueChangeContext; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.server.issue.IssueFieldsSetter; | |||
import org.sonar.server.issue.workflow.IssueWorkflow; | |||
@@ -58,8 +59,7 @@ public class IssueLifecycle { | |||
this(analysisMetadataHolder, IssueChangeContext.createScan(new Date(analysisMetadataHolder.getAnalysisDate())), workflow, updater, debtCalculator, ruleRepository); | |||
} | |||
@VisibleForTesting | |||
IssueLifecycle(AnalysisMetadataHolder analysisMetadataHolder, IssueChangeContext changeContext, IssueWorkflow workflow, IssueFieldsSetter updater, | |||
@VisibleForTesting IssueLifecycle(AnalysisMetadataHolder analysisMetadataHolder, IssueChangeContext changeContext, IssueWorkflow workflow, IssueFieldsSetter updater, | |||
DebtCalculator debtCalculator, RuleRepository ruleRepository) { | |||
this.analysisMetadataHolder = analysisMetadataHolder; | |||
this.workflow = workflow; | |||
@@ -102,9 +102,9 @@ public class IssueLifecycle { | |||
raw.setFieldChange(changeContext, IssueFieldsSetter.FROM_BRANCH, branchName, analysisMetadataHolder.getBranch().getName()); | |||
} | |||
public void mergeConfirmedOrResolvedFromPr(DefaultIssue raw, DefaultIssue base, String pr) { | |||
public void mergeConfirmedOrResolvedFromPrOrBranch(DefaultIssue raw, DefaultIssue base, BranchType branchType, String prOrBranchKey) { | |||
copyAttributesOfIssueFromAnotherBranch(raw, base); | |||
String from = "#" + pr; | |||
String from = (branchType == BranchType.PULL_REQUEST) ? "#" + prOrBranchKey : prOrBranchKey; | |||
String to = analysisMetadataHolder.isPullRequest() ? ("#" + analysisMetadataHolder.getPullRequestKey()) : analysisMetadataHolder.getBranch().getName(); | |||
raw.setFieldChange(changeContext, IssueFieldsSetter.FROM_BRANCH, from, to); | |||
} |
@@ -25,6 +25,7 @@ import javax.annotation.Nullable; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.core.issue.tracking.Trackable; | |||
import org.sonar.db.component.BranchType; | |||
@Immutable | |||
public class SiblingIssue implements Trackable { | |||
@@ -35,9 +36,11 @@ public class SiblingIssue implements Trackable { | |||
private final RuleKey ruleKey; | |||
private final String status; | |||
private final String prKey; | |||
private final BranchType branchType; | |||
private final Date updateDate; | |||
SiblingIssue(String key, @Nullable Integer line, @Nullable String message, @Nullable String lineHash, RuleKey ruleKey, String status, String prKey, Date updateDate) { | |||
SiblingIssue(String key, @Nullable Integer line, @Nullable String message, @Nullable String lineHash, RuleKey ruleKey, String status, String prKey, BranchType branchType, | |||
Date updateDate) { | |||
this.key = key; | |||
this.line = line; | |||
this.message = message; | |||
@@ -45,6 +48,7 @@ public class SiblingIssue implements Trackable { | |||
this.ruleKey = ruleKey; | |||
this.status = status; | |||
this.prKey = prKey; | |||
this.branchType = branchType; | |||
this.updateDate = updateDate; | |||
} | |||
@@ -64,6 +68,10 @@ public class SiblingIssue implements Trackable { | |||
return message; | |||
} | |||
public BranchType getBranchType() { | |||
return branchType; | |||
} | |||
@CheckForNull | |||
@Override | |||
public String getLineHash() { |
@@ -55,7 +55,7 @@ public class SiblingsIssueMerger { | |||
for (Map.Entry<DefaultIssue, SiblingIssue> e : matchedRaws.entrySet()) { | |||
SiblingIssue issue = e.getValue(); | |||
issueLifecycle.mergeConfirmedOrResolvedFromPr(e.getKey(), defaultIssues.get(issue), issue.getPrKey()); | |||
issueLifecycle.mergeConfirmedOrResolvedFromPrOrBranch(e.getKey(), defaultIssues.get(issue), issue.getBranchType(), issue.getPrKey()); | |||
} | |||
} | |||
} |
@@ -25,13 +25,11 @@ import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import org.sonar.api.utils.Preconditions; | |||
import org.sonar.ce.task.projectanalysis.component.Component; | |||
import org.sonar.ce.task.projectanalysis.component.SiblingComponentsWithOpenIssues; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.issue.PrIssueDto; | |||
@@ -69,9 +67,8 @@ public class SiblingsIssuesLoader { | |||
} | |||
private static SiblingIssue toSiblingIssue(PrIssueDto dto) { | |||
Preconditions.checkState(dto.getBranchType().equals(BranchType.PULL_REQUEST), "Expected all issues to belong to P/Rs"); | |||
return new SiblingIssue(dto.getKey(), dto.getLine(), dto.getMessage(), dto.getChecksum(), dto.getRuleKey(), dto.getStatus(), dto.getBranchKey(), | |||
longToDate(dto.getIssueUpdateDate())); | |||
dto.getBranchType(), longToDate(dto.getIssueUpdateDate())); | |||
} | |||
public Map<SiblingIssue, DefaultIssue> loadDefaultIssuesWithChanges(Collection<SiblingIssue> lightIssues) { |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.ce.task.projectanalysis.component; | |||
import java.util.Collections; | |||
import javax.annotation.Nullable; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
@@ -29,8 +30,8 @@ import org.sonar.db.DbTester; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.issue.IssueTesting; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.server.project.Project; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@@ -64,6 +65,7 @@ public class SiblingComponentsWithOpenIssuesTest { | |||
@Before | |||
public void setUp() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
metadataHolder.setProject(new Project(project.uuid(), project.getKey(), project.name(), project.description(), Collections.emptyList())); | |||
branch1 = db.components().insertProjectBranch(project, b -> b.setKey("branch1"), b -> b.setBranchType(BranchType.BRANCH)); | |||
branch1pr1 = db.components().insertProjectBranch(project, |
@@ -145,7 +145,7 @@ public class IssueLifecycleTest { | |||
when(branch.getName()).thenReturn("master"); | |||
analysisMetadataHolder.setBranch(branch); | |||
underTest.mergeConfirmedOrResolvedFromPr(raw, fromShort, "2"); | |||
underTest.mergeConfirmedOrResolvedFromPrOrBranch(raw, fromShort, BranchType.PULL_REQUEST, "2"); | |||
assertThat(raw.resolution()).isEqualTo("resolution"); | |||
assertThat(raw.status()).isEqualTo("status"); |
@@ -27,8 +27,6 @@ import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.mockito.ArgumentCaptor; | |||
import org.mockito.Mock; | |||
import org.mockito.MockitoAnnotations; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.rule.RuleKey; | |||
@@ -48,9 +46,11 @@ import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.issue.IssueTesting; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.project.Project; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoInteractions; | |||
import static org.mockito.Mockito.when; | |||
@@ -58,11 +58,8 @@ import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builde | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
public class SiblingsIssueMergerTest { | |||
@Mock | |||
private IssueLifecycle issueLifecycle; | |||
@Mock | |||
private Branch branch; | |||
private final IssueLifecycle issueLifecycle = mock(IssueLifecycle.class); | |||
private final Branch branch = mock(Branch.class); | |||
@Rule | |||
public DbTester db = DbTester.create(); | |||
@@ -102,7 +99,6 @@ public class SiblingsIssueMergerTest { | |||
@Before | |||
public void setUp() { | |||
MockitoAnnotations.initMocks(this); | |||
DbClient dbClient = db.getDbClient(); | |||
ComponentIssuesLoader componentIssuesLoader = new ComponentIssuesLoader(dbClient, null, null, new MapSettings().asConfig(), System2.INSTANCE); | |||
copier = new SiblingsIssueMerger(new SiblingsIssuesLoader(new SiblingComponentsWithOpenIssues(treeRootHolder, metadataHolder, dbClient), dbClient, componentIssuesLoader), | |||
@@ -124,6 +120,7 @@ public class SiblingsIssueMergerTest { | |||
rule = db.rules().insert(); | |||
when(branch.getReferenceBranchUuid()).thenReturn(projectDto.uuid()); | |||
metadataHolder.setBranch(branch); | |||
metadataHolder.setProject(new Project(projectDto.uuid(), projectDto.getKey(), projectDto.name(), projectDto.description(), Collections.emptyList())); | |||
} | |||
@Test | |||
@@ -150,7 +147,7 @@ public class SiblingsIssueMergerTest { | |||
copier.tryMerge(FILE_1, Collections.singleton(newIssue)); | |||
ArgumentCaptor<DefaultIssue> issueToMerge = ArgumentCaptor.forClass(DefaultIssue.class); | |||
verify(issueLifecycle).mergeConfirmedOrResolvedFromPr(eq(newIssue), issueToMerge.capture(), eq("myBranch1")); | |||
verify(issueLifecycle).mergeConfirmedOrResolvedFromPrOrBranch(eq(newIssue), issueToMerge.capture(), eq(BranchType.PULL_REQUEST), eq("myBranch1")); | |||
assertThat(issueToMerge.getValue().key()).isEqualTo("issue1"); | |||
} | |||
@@ -169,7 +166,7 @@ public class SiblingsIssueMergerTest { | |||
copier.tryMerge(FILE_1, Collections.singleton(newIssue)); | |||
ArgumentCaptor<DefaultIssue> issueToMerge = ArgumentCaptor.forClass(DefaultIssue.class); | |||
verify(issueLifecycle).mergeConfirmedOrResolvedFromPr(eq(newIssue), issueToMerge.capture(), eq("myBranch1")); | |||
verify(issueLifecycle).mergeConfirmedOrResolvedFromPrOrBranch(eq(newIssue), issueToMerge.capture(), eq(BranchType.PULL_REQUEST), eq("myBranch1")); | |||
assertThat(issueToMerge.getValue().key()).isEqualTo("issue1"); | |||
} | |||
@@ -186,7 +183,7 @@ public class SiblingsIssueMergerTest { | |||
copier.tryMerge(FILE_1, Collections.singleton(newIssue)); | |||
ArgumentCaptor<DefaultIssue> issueToMerge = ArgumentCaptor.forClass(DefaultIssue.class); | |||
verify(issueLifecycle).mergeConfirmedOrResolvedFromPr(eq(newIssue), issueToMerge.capture(), eq("myBranch2")); | |||
verify(issueLifecycle).mergeConfirmedOrResolvedFromPrOrBranch(eq(newIssue), issueToMerge.capture(), eq(BranchType.PULL_REQUEST), eq("myBranch2")); | |||
assertThat(issueToMerge.getValue().key()).isEqualTo("issue"); | |||
assertThat(issueToMerge.getValue().defaultIssueComments()).isNotEmpty(); |
@@ -302,8 +302,19 @@ public class ComponentDao implements Dao { | |||
* Returns components with open issues from P/Rs that use a certain branch as reference (reference branch). | |||
* Excludes components from the current branch. | |||
*/ | |||
public List<KeyWithUuidDto> selectAllSiblingComponentKeysHavingOpenIssues(DbSession dbSession, String referenceBranchUuid, String currentBranchUuid) { | |||
return mapper(dbSession).selectAllSiblingComponentKeysHavingOpenIssues(referenceBranchUuid, currentBranchUuid); | |||
public List<KeyWithUuidDto> selectComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues(DbSession dbSession, String referenceBranchUuid, String currentBranchUuid) { | |||
return mapper(dbSession).selectComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues(referenceBranchUuid, currentBranchUuid); | |||
} | |||
/** | |||
* Returns components with open issues from the given branches | |||
*/ | |||
public List<KeyWithUuidDto> selectComponentsFromBranchesThatHaveOpenIssues(DbSession dbSession, Set<String> branchUuids) { | |||
if (branchUuids.isEmpty()) { | |||
return emptyList(); | |||
} | |||
return executeLargeInputs(branchUuids, input -> mapper(dbSession).selectComponentsFromBranchesThatHaveOpenIssues(input)); | |||
} | |||
/** |
@@ -138,8 +138,10 @@ public interface ComponentMapper { | |||
void delete(String componentUuid); | |||
List<KeyWithUuidDto> selectAllSiblingComponentKeysHavingOpenIssues(@Param("referenceBranchUuid") String referenceBranchUuid, | |||
@Param("currentBranchUuid") String currentBranchUuid); | |||
List<KeyWithUuidDto> selectComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues(@Param("referenceBranchUuid") String referenceBranchUuid, | |||
@Param("currentBranchUuid") String currentBranchUuid); | |||
List<KeyWithUuidDto> selectComponentsFromBranchesThatHaveOpenIssues(@Param("branchUuids") List<String> branchUuids); | |||
List<ProjectNclocDistributionDto> selectPrivateProjectsWithNcloc(); | |||
@@ -21,6 +21,7 @@ package org.sonar.db.newcodeperiod; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.util.UuidFactory; | |||
@@ -89,6 +90,10 @@ public class NewCodePeriodDao implements Dao { | |||
return ofNullable(mapper(dbSession).selectByBranch(projectUuid, branchUuid)); | |||
} | |||
public Set<String> selectBranchesReferencing(DbSession dbSession, String projectUuid, String referenceBranchName) { | |||
return mapper(dbSession).selectBranchesReferencing(projectUuid, referenceBranchName); | |||
} | |||
public boolean existsByProjectAnalysisUuid(DbSession dbSession, String projectAnalysisUuid) { | |||
requireNonNull(projectAnalysisUuid, MSG_PROJECT_UUID_NOT_SPECIFIED); | |||
return mapper(dbSession).countByProjectAnalysis(projectAnalysisUuid) > 0; |
@@ -91,11 +91,12 @@ public class NewCodePeriodDto { | |||
return this; | |||
} | |||
@CheckForNull | |||
public String getValue() { | |||
return value; | |||
} | |||
public NewCodePeriodDto setValue(String value) { | |||
public NewCodePeriodDto setValue(@Nullable String value) { | |||
this.value = value; | |||
return this; | |||
} |
@@ -21,6 +21,7 @@ package org.sonar.db.newcodeperiod; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import org.apache.ibatis.annotations.Param; | |||
public interface NewCodePeriodMapper { | |||
@@ -39,6 +40,8 @@ public interface NewCodePeriodMapper { | |||
NewCodePeriodDto selectByBranch(@Param("projectUuid") String projectUuid, @Param("branchUuid") String branchUuid); | |||
Set<String> selectBranchesReferencing(@Param("projectUuid") String projectUuid, @Param("referenceBranchName") String referenceBranchName); | |||
long countByProjectAnalysis(String projectAnalysisUuid); | |||
List<NewCodePeriodDto> selectAllByProject(String projectUuid); |
@@ -678,7 +678,7 @@ | |||
DELETE FROM components WHERE uuid=#{componentUuid,jdbcType=VARCHAR} | |||
</delete> | |||
<select id="selectAllSiblingComponentKeysHavingOpenIssues" resultType="KeyWithUuid"> | |||
<select id="selectComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues" resultType="KeyWithUuid"> | |||
SELECT DISTINCT p.kee as kee, p.uuid as uuid FROM components p | |||
JOIN issues i | |||
ON p.uuid = i.component_uuid | |||
@@ -690,6 +690,19 @@ | |||
AND i.status != 'CLOSED' | |||
</select> | |||
<select id="selectComponentsFromBranchesThatHaveOpenIssues" resultType="KeyWithUuid"> | |||
SELECT DISTINCT p.kee as kee, p.uuid as uuid | |||
FROM components p | |||
JOIN issues i | |||
ON p.uuid = i.component_uuid | |||
JOIN project_branches b | |||
ON i.project_uuid = b.uuid | |||
AND b.uuid in <foreach collection="branchUuids" open="(" close=")" item="branchUuid" separator=","> | |||
#{branchUuid,jdbcType=VARCHAR} | |||
</foreach> | |||
AND i.status != 'CLOSED' | |||
</select> | |||
<select id="selectPrivateProjectsWithNcloc" resultType="org.sonar.db.component.ProjectNclocDistributionDto"> | |||
select p.kee as kee, p.name as name, max(lm.value) as ncloc | |||
from live_measures lm |
@@ -70,6 +70,31 @@ | |||
</choose> | |||
</update> | |||
<select id="selectBranchesReferencing" parameterType="map" resultType="string"> | |||
<!-- branch setting --> | |||
SELECT ncp.branch_uuid | |||
FROM new_code_periods ncp | |||
WHERE | |||
ncp.branch_uuid IS NOT NULL | |||
AND ncp.project_uuid = #{projectUuid, jdbcType=VARCHAR} | |||
AND ncp.type='REFERENCE_BRANCH' | |||
AND ncp.value=#{referenceBranchName, jdbcType=VARCHAR} | |||
UNION | |||
<!-- project default setting--> | |||
SELECT pb.uuid | |||
FROM project_branches pb, new_code_periods ncp1 | |||
WHERE | |||
ncp1.project_uuid = pb.project_uuid | |||
AND ncp1.branch_uuid IS NULL | |||
AND ncp1.project_uuid = #{projectUuid, jdbcType=VARCHAR} | |||
AND ncp1.type='REFERENCE_BRANCH' | |||
AND ncp1.value=#{referenceBranchName, jdbcType=VARCHAR} | |||
AND NOT EXISTS (select ncp2.value from new_code_periods ncp2 where ncp2.branch_uuid = pb.uuid) | |||
AND pb.kee != #{referenceBranchName, jdbcType=VARCHAR} | |||
</select> | |||
<select id="selectByProject" parameterType="map" resultType="org.sonar.db.newcodeperiod.NewCodePeriodDto"> | |||
SELECT | |||
<include refid="newCodePeriodMapperColumns"/> |
@@ -490,6 +490,8 @@ CREATE TABLE "NEW_CODE_PERIODS"( | |||
); | |||
ALTER TABLE "NEW_CODE_PERIODS" ADD CONSTRAINT "PK_NEW_CODE_PERIODS" PRIMARY KEY("UUID"); | |||
CREATE UNIQUE INDEX "UNIQ_NEW_CODE_PERIODS" ON "NEW_CODE_PERIODS"("PROJECT_UUID", "BRANCH_UUID"); | |||
CREATE INDEX "IDX_NCP_TYPE" ON "NEW_CODE_PERIODS"("TYPE"); | |||
CREATE INDEX "IDX_NCP_VALUE" ON "NEW_CODE_PERIODS"("VALUE"); | |||
CREATE TABLE "NOTIFICATIONS"( | |||
"DATA" BLOB, |
@@ -20,6 +20,7 @@ | |||
package org.sonar.db.component; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.google.common.collect.ImmutableSet; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
@@ -49,7 +50,10 @@ import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.RowNotFoundException; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.db.source.FileSourceDto; | |||
import static com.google.common.collect.ImmutableSet.of; | |||
@@ -65,6 +69,9 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.assertj.core.api.Assertions.entry; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.sonar.api.issue.Issue.STATUS_CLOSED; | |||
import static org.sonar.api.issue.Issue.STATUS_CONFIRMED; | |||
import static org.sonar.api.issue.Issue.STATUS_OPEN; | |||
import static org.sonar.api.resources.Qualifiers.APP; | |||
import static org.sonar.api.resources.Qualifiers.PROJECT; | |||
import static org.sonar.api.resources.Qualifiers.SUBVIEW; | |||
@@ -1799,6 +1806,38 @@ public class ComponentDaoTest { | |||
assertThat(underTest.existAnyOfComponentsWithQualifiers(db.getSession(), newHashSet(projectDto.getKey(), view.getKey()), newHashSet(APP, VIEW, SUBVIEW))).isTrue(); | |||
} | |||
@Test | |||
public void selectComponentsFromBranchesThatHaveOpenIssues() { | |||
final ProjectDto project = db.components().insertPrivateProjectDto(b -> b.setName("foo")); | |||
ComponentDto branch1 = db.components().insertProjectBranch(project, ComponentTesting.newBranchDto(project.getUuid(), BRANCH).setKey("branch1")); | |||
ComponentDto fileBranch1 = db.components().insertComponent(ComponentTesting.newFileDto(branch1)); | |||
ComponentDto branch2 = db.components().insertProjectBranch(project, ComponentTesting.newBranchDto(project.getUuid(), BRANCH).setKey("branch2")); | |||
ComponentDto fileBranch2 = db.components().insertComponent(ComponentTesting.newFileDto(branch2)); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
db.issues().insert(new IssueDto().setKee("i1").setComponent(fileBranch1).setProject(branch1).setRule(rule).setStatus(STATUS_CONFIRMED)); | |||
db.issues().insert(new IssueDto().setKee("i2").setComponent(fileBranch2).setProject(branch2).setRule(rule).setStatus(STATUS_CLOSED)); | |||
db.issues().insert(new IssueDto().setKee("i3").setComponent(fileBranch2).setProject(branch2).setRule(rule).setStatus(STATUS_OPEN)); | |||
List<KeyWithUuidDto> result = underTest.selectComponentsFromBranchesThatHaveOpenIssues(db.getSession(), of(branch1.uuid(), branch2.uuid())); | |||
assertThat(result).extracting(KeyWithUuidDto::uuid).contains(fileBranch2.uuid()); | |||
} | |||
@Test | |||
public void selectComponentsFromBranchesThatHaveOpenIssues_returns_nothing_if_no_open_issues_in_sibling_branches() { | |||
final ProjectDto project = db.components().insertPrivateProjectDto(b -> b.setName("foo")); | |||
ComponentDto branch1 = db.components().insertProjectBranch(project, ComponentTesting.newBranchDto(project.getUuid(), BRANCH).setKey("branch1")); | |||
ComponentDto fileBranch1 = db.components().insertComponent(ComponentTesting.newFileDto(branch1)); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
db.issues().insert(new IssueDto().setKee("i").setComponent(fileBranch1).setProject(branch1).setRule(rule).setStatus(STATUS_CLOSED)); | |||
List<KeyWithUuidDto> result = underTest.selectComponentsFromBranchesThatHaveOpenIssues(db.getSession(), singleton(branch1.uuid())); | |||
assertThat(result).isEmpty(); | |||
} | |||
private boolean privateFlagOfUuid(String uuid) { | |||
return underTest.selectByUuid(db.getSession(), uuid).get().isPrivate(); | |||
} | |||
@@ -1818,5 +1857,4 @@ public class ComponentDaoTest { | |||
return t -> { | |||
}; | |||
} | |||
} |
@@ -20,17 +20,23 @@ | |||
package org.sonar.db.newcodeperiod; | |||
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.core.util.SequenceUuidFactory; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.project.ProjectDto; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS; | |||
import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION; | |||
import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH; | |||
import static org.sonar.db.newcodeperiod.NewCodePeriodType.SPECIFIC_ANALYSIS; | |||
public class NewCodePeriodDaoTest { | |||
@@ -38,30 +44,23 @@ public class NewCodePeriodDaoTest { | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
private final DbSession dbSession = db.getSession(); | |||
private final UuidFactory uuidFactory = mock(UuidFactory.class); | |||
private final UuidFactory uuidFactory = new SequenceUuidFactory(); | |||
private final NewCodePeriodDao underTest = new NewCodePeriodDao(System2.INSTANCE, uuidFactory); | |||
private static final String NEW_CODE_PERIOD_UUID = "ncp-uuid-1"; | |||
@Test | |||
public void insert_new_code_period() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid("branch-uuid") | |||
.setType(NewCodePeriodType.NUMBER_OF_DAYS) | |||
.setValue("5")); | |||
insert("proj-uuid", "branch-uuid", NUMBER_OF_DAYS, "5"); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, NEW_CODE_PERIOD_UUID); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, "1"); | |||
assertThat(resultOpt).isNotNull() | |||
.isNotEmpty(); | |||
NewCodePeriodDto result = resultOpt.get(); | |||
assertThat(result.getUuid()).isEqualTo(NEW_CODE_PERIOD_UUID); | |||
assertThat(result.getUuid()).isEqualTo("1"); | |||
assertThat(result.getProjectUuid()).isEqualTo("proj-uuid"); | |||
assertThat(result.getBranchUuid()).isEqualTo("branch-uuid"); | |||
assertThat(result.getType()).isEqualTo(NewCodePeriodType.NUMBER_OF_DAYS); | |||
assertThat(result.getType()).isEqualTo(NUMBER_OF_DAYS); | |||
assertThat(result.getValue()).isEqualTo("5"); | |||
assertThat(result.getCreatedAt()).isNotZero(); | |||
assertThat(result.getUpdatedAt()).isNotZero(); | |||
@@ -77,31 +76,25 @@ public class NewCodePeriodDaoTest { | |||
@Test | |||
public void update_new_code_period() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid("branch-uuid") | |||
.setType(NewCodePeriodType.NUMBER_OF_DAYS) | |||
.setValue("5")); | |||
insert("proj-uuid", "branch-uuid", NUMBER_OF_DAYS, "5"); | |||
underTest.update(dbSession, new NewCodePeriodDto() | |||
.setUuid(NEW_CODE_PERIOD_UUID) | |||
.setType(NewCodePeriodType.SPECIFIC_ANALYSIS) | |||
.setUuid("1") | |||
.setType(SPECIFIC_ANALYSIS) | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid("branch-uuid") | |||
.setValue("analysis-uuid")); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, NEW_CODE_PERIOD_UUID); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, "1"); | |||
assertThat(resultOpt).isNotNull() | |||
.isNotEmpty(); | |||
NewCodePeriodDto result = resultOpt.get(); | |||
assertThat(result.getUuid()).isEqualTo(NEW_CODE_PERIOD_UUID); | |||
assertThat(result.getUuid()).isEqualTo("1"); | |||
assertThat(result.getProjectUuid()).isEqualTo("proj-uuid"); | |||
assertThat(result.getBranchUuid()).isEqualTo("branch-uuid"); | |||
assertThat(result.getType()).isEqualTo(NewCodePeriodType.SPECIFIC_ANALYSIS); | |||
assertThat(result.getType()).isEqualTo(SPECIFIC_ANALYSIS); | |||
assertThat(result.getValue()).isEqualTo("analysis-uuid"); | |||
assertThat(result.getCreatedAt()).isNotZero(); | |||
assertThat(result.getUpdatedAt()).isNotZero(); | |||
@@ -112,26 +105,19 @@ public class NewCodePeriodDaoTest { | |||
@Test | |||
public void insert_with_upsert() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.upsert(dbSession, new NewCodePeriodDto() | |||
.setUuid(NEW_CODE_PERIOD_UUID) | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid("branch-uuid") | |||
.setType(NewCodePeriodType.NUMBER_OF_DAYS) | |||
.setValue("5")); | |||
insert("proj-uuid", "branch-uuid", NUMBER_OF_DAYS, "5"); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, NEW_CODE_PERIOD_UUID); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, "1"); | |||
assertThat(resultOpt) | |||
.isNotNull() | |||
.isNotEmpty(); | |||
NewCodePeriodDto result = resultOpt.get(); | |||
assertThat(result.getUuid()).isEqualTo(NEW_CODE_PERIOD_UUID); | |||
assertThat(result.getUuid()).isEqualTo("1"); | |||
assertThat(result.getProjectUuid()).isEqualTo("proj-uuid"); | |||
assertThat(result.getBranchUuid()).isEqualTo("branch-uuid"); | |||
assertThat(result.getType()).isEqualTo(NewCodePeriodType.NUMBER_OF_DAYS); | |||
assertThat(result.getType()).isEqualTo(NUMBER_OF_DAYS); | |||
assertThat(result.getValue()).isEqualTo("5"); | |||
assertThat(result.getCreatedAt()).isNotZero(); | |||
assertThat(result.getUpdatedAt()).isNotZero(); | |||
@@ -142,32 +128,26 @@ public class NewCodePeriodDaoTest { | |||
@Test | |||
public void update_with_upsert() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid("branch-uuid") | |||
.setType(NewCodePeriodType.NUMBER_OF_DAYS) | |||
.setValue("5")); | |||
insert("proj-uuid", "branch-uuid", NUMBER_OF_DAYS, "5"); | |||
underTest.upsert(dbSession, new NewCodePeriodDto() | |||
.setUuid(NEW_CODE_PERIOD_UUID) | |||
.setUuid("1") | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid("branch-uuid") | |||
.setType(NewCodePeriodType.SPECIFIC_ANALYSIS) | |||
.setType(SPECIFIC_ANALYSIS) | |||
.setValue("analysis-uuid")); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, NEW_CODE_PERIOD_UUID); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByUuid(dbSession, "1"); | |||
assertThat(resultOpt) | |||
.isNotNull() | |||
.isNotEmpty(); | |||
NewCodePeriodDto result = resultOpt.get(); | |||
assertThat(result.getUuid()).isEqualTo(NEW_CODE_PERIOD_UUID); | |||
assertThat(result.getUuid()).isEqualTo("1"); | |||
assertThat(result.getProjectUuid()).isEqualTo("proj-uuid"); | |||
assertThat(result.getBranchUuid()).isEqualTo("branch-uuid"); | |||
assertThat(result.getType()).isEqualTo(NewCodePeriodType.SPECIFIC_ANALYSIS); | |||
assertThat(result.getType()).isEqualTo(SPECIFIC_ANALYSIS); | |||
assertThat(result.getValue()).isEqualTo("analysis-uuid"); | |||
assertThat(result.getCreatedAt()).isNotZero(); | |||
assertThat(result.getUpdatedAt()).isNotZero(); | |||
@@ -178,13 +158,7 @@ public class NewCodePeriodDaoTest { | |||
@Test | |||
public void select_by_project_and_branch_uuids() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid("branch-uuid") | |||
.setType(NewCodePeriodType.NUMBER_OF_DAYS) | |||
.setValue("5")); | |||
insert("proj-uuid", "branch-uuid", NUMBER_OF_DAYS, "5"); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByBranch(dbSession, "proj-uuid", "branch-uuid"); | |||
assertThat(resultOpt) | |||
@@ -192,24 +166,34 @@ public class NewCodePeriodDaoTest { | |||
.isNotEmpty(); | |||
NewCodePeriodDto result = resultOpt.get(); | |||
assertThat(result.getUuid()).isEqualTo(NEW_CODE_PERIOD_UUID); | |||
assertThat(result.getUuid()).isEqualTo("1"); | |||
assertThat(result.getProjectUuid()).isEqualTo("proj-uuid"); | |||
assertThat(result.getBranchUuid()).isEqualTo("branch-uuid"); | |||
assertThat(result.getType()).isEqualTo(NewCodePeriodType.NUMBER_OF_DAYS); | |||
assertThat(result.getType()).isEqualTo(NUMBER_OF_DAYS); | |||
assertThat(result.getValue()).isEqualTo("5"); | |||
assertThat(result.getCreatedAt()).isNotZero(); | |||
assertThat(result.getUpdatedAt()).isNotZero(); | |||
} | |||
@Test | |||
public void select_by_project_uuid() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
public void select_branches_referencing() { | |||
ProjectDto project = db.components().insertPrivateProjectDto(); | |||
BranchDto mainBranch = db.getDbClient().branchDao().selectByUuid(dbSession, project.getUuid()).get(); | |||
BranchDto branch1 = db.components().insertProjectBranch(project); | |||
BranchDto branch2 = db.components().insertProjectBranch(project); | |||
BranchDto branch3 = db.components().insertProjectBranch(project); | |||
insert(project.getUuid(), null, REFERENCE_BRANCH, mainBranch.getKey()); | |||
insert(project.getUuid(), branch1.getUuid(), REFERENCE_BRANCH, mainBranch.getKey()); | |||
insert(project.getUuid(), branch2.getUuid(), NUMBER_OF_DAYS, "5"); | |||
insert(project.getUuid(), project.getUuid(), PREVIOUS_VERSION, null); | |||
db.commit(); | |||
assertThat(underTest.selectBranchesReferencing(dbSession, project.getUuid(), mainBranch.getKey())).containsOnly(branch1.getUuid(), branch3.getUuid()); | |||
} | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid(null) | |||
.setType(NewCodePeriodType.NUMBER_OF_DAYS) | |||
.setValue("5")); | |||
@Test | |||
public void select_by_project_uuid() { | |||
insert("proj-uuid", null, NUMBER_OF_DAYS, "5"); | |||
Optional<NewCodePeriodDto> resultOpt = underTest.selectByProject(dbSession, "proj-uuid"); | |||
assertThat(resultOpt) | |||
@@ -217,10 +201,10 @@ public class NewCodePeriodDaoTest { | |||
.isNotEmpty(); | |||
NewCodePeriodDto result = resultOpt.get(); | |||
assertThat(result.getUuid()).isEqualTo(NEW_CODE_PERIOD_UUID); | |||
assertThat(result.getUuid()).isEqualTo("1"); | |||
assertThat(result.getProjectUuid()).isEqualTo("proj-uuid"); | |||
assertThat(result.getBranchUuid()).isNull(); | |||
assertThat(result.getType()).isEqualTo(NewCodePeriodType.NUMBER_OF_DAYS); | |||
assertThat(result.getType()).isEqualTo(NUMBER_OF_DAYS); | |||
assertThat(result.getValue()).isEqualTo("5"); | |||
assertThat(result.getCreatedAt()).isNotZero(); | |||
assertThat(result.getUpdatedAt()).isNotZero(); | |||
@@ -228,22 +212,16 @@ public class NewCodePeriodDaoTest { | |||
@Test | |||
public void select_global() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid(null) | |||
.setBranchUuid(null) | |||
.setType(NewCodePeriodType.NUMBER_OF_DAYS) | |||
.setValue("30")); | |||
insert(null, null, NUMBER_OF_DAYS, "30"); | |||
Optional<NewCodePeriodDto> newCodePeriodDto = underTest.selectGlobal(dbSession); | |||
assertThat(newCodePeriodDto).isNotEmpty(); | |||
NewCodePeriodDto result = newCodePeriodDto.get(); | |||
assertThat(result.getUuid()).isEqualTo(NEW_CODE_PERIOD_UUID); | |||
assertThat(result.getUuid()).isEqualTo("1"); | |||
assertThat(result.getProjectUuid()).isNull(); | |||
assertThat(result.getBranchUuid()).isNull(); | |||
assertThat(result.getType()).isEqualTo(NewCodePeriodType.NUMBER_OF_DAYS); | |||
assertThat(result.getType()).isEqualTo(NUMBER_OF_DAYS); | |||
assertThat(result.getValue()).isEqualTo("30"); | |||
assertThat(result.getCreatedAt()).isNotZero(); | |||
assertThat(result.getUpdatedAt()).isNotZero(); | |||
@@ -251,13 +229,7 @@ public class NewCodePeriodDaoTest { | |||
@Test | |||
public void exists_by_project_analysis_is_true() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid("branch-uuid") | |||
.setType(NewCodePeriodType.SPECIFIC_ANALYSIS) | |||
.setValue("analysis-uuid")); | |||
insert("proj-uuid", "branch-uuid", SPECIFIC_ANALYSIS, "analysis-uuid"); | |||
boolean exists = underTest.existsByProjectAnalysisUuid(dbSession, "analysis-uuid"); | |||
assertThat(exists).isTrue(); | |||
@@ -265,13 +237,7 @@ public class NewCodePeriodDaoTest { | |||
@Test | |||
public void delete_by_project_uuid_and_branch_uuid() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid("proj-uuid") | |||
.setBranchUuid("branch-uuid") | |||
.setType(NewCodePeriodType.SPECIFIC_ANALYSIS) | |||
.setValue("analysis-uuid")); | |||
insert("proj-uuid", "branch-uuid", SPECIFIC_ANALYSIS, "analysis-uuid"); | |||
underTest.delete(dbSession, "proj-uuid", "branch-uuid"); | |||
db.commit(); | |||
@@ -280,12 +246,7 @@ public class NewCodePeriodDaoTest { | |||
@Test | |||
public void delete_by_project_uuid() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid("proj-uuid") | |||
.setType(NewCodePeriodType.SPECIFIC_ANALYSIS) | |||
.setValue("analysis-uuid")); | |||
insert("proj-uuid", null, SPECIFIC_ANALYSIS, "analysis-uuid"); | |||
underTest.delete(dbSession, "proj-uuid", null); | |||
db.commit(); | |||
@@ -294,11 +255,7 @@ public class NewCodePeriodDaoTest { | |||
@Test | |||
public void delete_global() { | |||
when(uuidFactory.create()).thenReturn(NEW_CODE_PERIOD_UUID); | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setType(NewCodePeriodType.SPECIFIC_ANALYSIS) | |||
.setValue("analysis-uuid")); | |||
insert(null, null, SPECIFIC_ANALYSIS, "analysis-uuid"); | |||
underTest.delete(dbSession, null, null); | |||
db.commit(); | |||
@@ -336,4 +293,12 @@ public class NewCodePeriodDaoTest { | |||
assertThat(db.countRowsOfTable("new_code_periods")) | |||
.isEqualTo(expected); | |||
} | |||
private void insert(@Nullable String projectUuid, @Nullable String branchUuid, NewCodePeriodType type, @Nullable String value) { | |||
underTest.insert(dbSession, new NewCodePeriodDto() | |||
.setProjectUuid(projectUuid) | |||
.setBranchUuid(branchUuid) | |||
.setType(type) | |||
.setValue(value)); | |||
} | |||
} |
@@ -36,6 +36,7 @@ import org.sonar.server.platform.db.migration.version.v85.DbVersion85; | |||
import org.sonar.server.platform.db.migration.version.v86.DbVersion86; | |||
import org.sonar.server.platform.db.migration.version.v87.DbVersion87; | |||
import org.sonar.server.platform.db.migration.version.v88.DbVersion88; | |||
import org.sonar.server.platform.db.migration.version.v89.DbVersion89; | |||
public class MigrationConfigurationModule extends Module { | |||
@Override | |||
@@ -52,6 +53,7 @@ public class MigrationConfigurationModule extends Module { | |||
DbVersion86.class, | |||
DbVersion87.class, | |||
DbVersion88.class, | |||
DbVersion89.class, | |||
// migration steps | |||
MigrationStepRegistryImpl.class, |
@@ -0,0 +1,75 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 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.server.platform.db.migration.version.v89; | |||
import java.sql.Connection; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.db.DatabaseUtils; | |||
import org.sonar.server.platform.db.migration.def.VarcharColumnDef; | |||
import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
public class AddIndicesToNewCodePeriodTable extends DdlChange { | |||
private static final String TABLE_NAME = "new_code_periods"; | |||
private static final String TYPE_INDEX_NAME = "idx_ncp_type"; | |||
private static final String VALUE_INDEX_NAME = "idx_ncp_value"; | |||
public AddIndicesToNewCodePeriodTable(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
if (!indexExists(TYPE_INDEX_NAME)) { | |||
context.execute(new CreateIndexBuilder() | |||
.setUnique(false) | |||
.setTable(TABLE_NAME) | |||
.setName(TYPE_INDEX_NAME) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("type") | |||
.setIsNullable(false) | |||
.setLimit(30) | |||
.build()) | |||
.build()); | |||
} | |||
if (!indexExists(VALUE_INDEX_NAME)) { | |||
context.execute(new CreateIndexBuilder() | |||
.setUnique(false) | |||
.setTable(TABLE_NAME) | |||
.setName(VALUE_INDEX_NAME) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("value") | |||
.setIsNullable(true) | |||
.setLimit(VarcharColumnDef.UUID_SIZE) | |||
.build()) | |||
.build()); | |||
} | |||
} | |||
private boolean indexExists(String index) throws SQLException { | |||
try (Connection connection = getDatabase().getDataSource().getConnection()) { | |||
return DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, index, connection); | |||
} | |||
} | |||
} |
@@ -0,0 +1,32 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 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.server.platform.db.migration.version.v89; | |||
import org.sonar.server.platform.db.migration.step.MigrationStepRegistry; | |||
import org.sonar.server.platform.db.migration.version.DbVersion; | |||
public class DbVersion89 implements DbVersion { | |||
@Override | |||
public void addSteps(MigrationStepRegistry registry) { | |||
registry | |||
.add(4400, "Add indices on columns 'type' and 'value' to 'new_code_periods' table", AddIndicesToNewCodePeriodTable.class); | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 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.server.platform.db.migration.version.v89; | |||
import java.sql.SQLException; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.db.CoreDbTester; | |||
import org.sonar.server.platform.db.migration.step.MigrationStep; | |||
public class AddIndicesToNewCodePeriodTableTest { | |||
private static final String TABLE_NAME = "new_code_periods"; | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(AddIndicesToNewCodePeriodTableTest.class, "schema.sql"); | |||
private final MigrationStep underTest = new AddIndicesToNewCodePeriodTable(db.database()); | |||
@Test | |||
public void execute() throws SQLException { | |||
underTest.execute(); | |||
db.assertIndex(TABLE_NAME, "idx_ncp_type", "type"); | |||
db.assertIndex(TABLE_NAME, "idx_ncp_value", "value"); | |||
} | |||
@Test | |||
public void migration_is_re_entrant() throws SQLException { | |||
underTest.execute(); | |||
// re-entrant | |||
underTest.execute(); | |||
db.assertIndex(TABLE_NAME, "idx_ncp_type", "type"); | |||
db.assertIndex(TABLE_NAME, "idx_ncp_value", "value"); | |||
} | |||
} |
@@ -0,0 +1,42 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 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.server.platform.db.migration.version.v89; | |||
import org.junit.Test; | |||
import org.sonar.server.platform.db.migration.version.DbVersion; | |||
import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationNotEmpty; | |||
import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber; | |||
public class DbVersion89Test { | |||
private final DbVersion underTest = new DbVersion89(); | |||
@Test | |||
public void migrationNumber_starts_at_4400() { | |||
verifyMinimumMigrationNumber(underTest, 4400); | |||
} | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationNotEmpty(underTest); | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
CREATE TABLE "NEW_CODE_PERIODS"( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"PROJECT_UUID" VARCHAR(40), | |||
"BRANCH_UUID" VARCHAR(40), | |||
"TYPE" VARCHAR(30) NOT NULL, | |||
"VALUE" VARCHAR(40), | |||
"UPDATED_AT" BIGINT NOT NULL, | |||
"CREATED_AT" BIGINT NOT NULL | |||
); | |||
ALTER TABLE "NEW_CODE_PERIODS" ADD CONSTRAINT "PK_NEW_CODE_PERIODS" PRIMARY KEY("UUID"); | |||
CREATE UNIQUE INDEX "UNIQ_NEW_CODE_PERIODS" ON "NEW_CODE_PERIODS"("PROJECT_UUID", "BRANCH_UUID"); |