From: Julien HENRY
Date: Mon, 16 Oct 2017 14:25:09 +0000 (+0200)
Subject: SONAR-9987 Add a changelog entry when copying/merging issues
X-Git-Tag: 6.7-RC1~151
X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a45212f715dbf525d0686523b76fcb46f62f101a;p=sonarqube.git
SONAR-9987 Add a changelog entry when copying/merging issues
---
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/core/issue/ShortBranchIssue.java b/server/sonar-db-dao/src/main/java/org/sonar/core/issue/ShortBranchIssue.java
index 11095124c97..f6c6bcd977b 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/core/issue/ShortBranchIssue.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/core/issue/ShortBranchIssue.java
@@ -33,14 +33,16 @@ public class ShortBranchIssue implements Trackable {
private final String lineHash;
private final RuleKey ruleKey;
private final String status;
+ private final String branchName;
- public ShortBranchIssue(String key, @Nullable Integer line, String message, @Nullable String lineHash, RuleKey ruleKey, String status) {
+ public ShortBranchIssue(String key, @Nullable Integer line, String message, @Nullable String lineHash, RuleKey ruleKey, String status, String branchName) {
this.key = key;
this.line = line;
this.message = message;
this.lineHash = lineHash;
this.ruleKey = ruleKey;
this.status = status;
+ this.branchName = branchName;
}
public String getKey() {
@@ -74,6 +76,10 @@ public class ShortBranchIssue implements Trackable {
return status;
}
+ public String getBranchName() {
+ return branchName;
+ }
+
@Override
public int hashCode() {
return key.hashCode();
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/ShortBranchIssueDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/ShortBranchIssueDto.java
index 3a68ea03af2..3c1901041e4 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/ShortBranchIssueDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/ShortBranchIssueDto.java
@@ -38,6 +38,7 @@ public final class ShortBranchIssueDto implements Serializable {
// joins
private String ruleKey;
private String ruleRepo;
+ private String branchName;
public String getKey() {
return kee;
@@ -68,6 +69,15 @@ public final class ShortBranchIssueDto implements Serializable {
return this;
}
+ public String getBranchName() {
+ return branchName;
+ }
+
+ public ShortBranchIssueDto setBranchName(String s) {
+ this.branchName = s;
+ return this;
+ }
+
public String getStatus() {
return status;
}
@@ -105,6 +115,6 @@ public final class ShortBranchIssueDto implements Serializable {
}
public static ShortBranchIssue toShortBranchIssue(ShortBranchIssueDto dto) {
- return new ShortBranchIssue(dto.getKey(), dto.getLine(), dto.getMessage(), dto.getChecksum(), dto.getRuleKey(), dto.getStatus());
+ return new ShortBranchIssue(dto.getKey(), dto.getLine(), dto.getMessage(), dto.getChecksum(), dto.getRuleKey(), dto.getStatus(), dto.getBranchName());
}
}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
index 8c365703f9e..09d43435502 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
@@ -221,9 +221,11 @@
i.status as status,
i.checksum as checksum,
r.plugin_rule_key as ruleKey,
- r.plugin_name as ruleRepo
+ r.plugin_name as ruleRepo,
+ b.kee as branchName
from issues i
inner join rules r on r.id = i.rule_id
+ inner join project_branches b on i.project_uuid = b.uuid
where i.component_uuid in
#{key,jdbcType=VARCHAR}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDaoTest.java
index 5201db84197..8c4682215c1 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDaoTest.java
@@ -33,6 +33,7 @@ import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.RowNotFoundException;
+import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.organization.OrganizationDto;
@@ -185,14 +186,19 @@ public class IssueDaoTest {
@Test
public void selectResolvedOrConfirmedByComponentUuid() {
RuleDefinitionDto rule = db.rules().insert();
- ComponentDto project = db.components().insertPrivateProject();
- ComponentDto file = db.components().insertComponent(newFileDto(project));
- IssueDto openIssue = db.issues().insert(rule, project, file, i -> i.setStatus(Issue.STATUS_OPEN).setResolution(null));
- IssueDto closedIssue = db.issues().insert(rule, project, file, i -> i.setStatus(Issue.STATUS_CLOSED).setResolution(Issue.RESOLUTION_FIXED));
- IssueDto reopenedIssue = db.issues().insert(rule, project, file, i -> i.setStatus(Issue.STATUS_REOPENED).setResolution(null));
- IssueDto confirmedIssue = db.issues().insert(rule, project, file, i -> i.setStatus(Issue.STATUS_CONFIRMED).setResolution(null));
- IssueDto wontfixIssue = db.issues().insert(rule, project, file, i -> i.setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_WONT_FIX));
- IssueDto fpIssue = db.issues().insert(rule, project, file, i -> i.setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_FALSE_POSITIVE));
+ ComponentDto project = db.components().insertMainBranch();
+ ComponentDto projectBranch = db.components().insertProjectBranch(project,
+ b -> b.setKey("feature/foo")
+ .setBranchType(BranchType.SHORT));
+
+ ComponentDto file = db.components().insertComponent(newFileDto(projectBranch));
+
+ IssueDto openIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_OPEN).setResolution(null));
+ IssueDto closedIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_CLOSED).setResolution(Issue.RESOLUTION_FIXED));
+ IssueDto reopenedIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_REOPENED).setResolution(null));
+ IssueDto confirmedIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_CONFIRMED).setResolution(null));
+ IssueDto wontfixIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_WONT_FIX));
+ IssueDto fpIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_FALSE_POSITIVE));
assertThat(underTest.selectResolvedOrConfirmedByComponentUuids(db.getSession(), Collections.singletonList(file.uuid())))
.extracting("kee")
@@ -202,9 +208,13 @@ public class IssueDaoTest {
@Test
public void selectResolvedOrConfirmedByComponentUuid_should_correctly_map_required_fields() {
RuleDefinitionDto rule = db.rules().insert();
- ComponentDto project = db.components().insertPrivateProject();
- ComponentDto file = db.components().insertComponent(newFileDto(project));
- IssueDto fpIssue = db.issues().insert(rule, project, file, i -> i.setStatus("RESOLVED").setResolution("FALSE-POSITIVE"));
+ ComponentDto project = db.components().insertMainBranch();
+ ComponentDto projectBranch = db.components().insertProjectBranch(project,
+ b -> b.setKey("feature/foo")
+ .setBranchType(BranchType.SHORT));
+
+ ComponentDto file = db.components().insertComponent(newFileDto(projectBranch));
+ IssueDto fpIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus("RESOLVED").setResolution("FALSE-POSITIVE"));
ShortBranchIssueDto fp = underTest.selectResolvedOrConfirmedByComponentUuids(db.getSession(), Collections.singletonList(file.uuid())).get(0);
assertThat(fp.getLine()).isEqualTo(fpIssue.getLine());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/MergeBranchComponentUuids.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/MergeBranchComponentUuids.java
index 9817dadbfdf..e91d1fc8c4a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/MergeBranchComponentUuids.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/MergeBranchComponentUuids.java
@@ -37,31 +37,38 @@ public class MergeBranchComponentUuids {
private final AnalysisMetadataHolder analysisMetadataHolder;
private final DbClient dbClient;
private Map uuidsByKey;
+ private String mergeBranchName;
public MergeBranchComponentUuids(AnalysisMetadataHolder analysisMetadataHolder, DbClient dbClient) {
this.analysisMetadataHolder = analysisMetadataHolder;
this.dbClient = dbClient;
}
- private void loadMergeBranchComponents() {
- String mergeBranchUuid = analysisMetadataHolder.getBranch().get().getMergeBranchUuid().get();
+ private void lazyInit() {
+ if (uuidsByKey == null) {
+ String mergeBranchUuid = analysisMetadataHolder.getBranch().get().getMergeBranchUuid().get();
+
+ uuidsByKey = new HashMap<>();
+ try (DbSession dbSession = dbClient.openSession(false)) {
- uuidsByKey = new HashMap<>();
- try (DbSession dbSession = dbClient.openSession(false)) {
+ List components = dbClient.componentDao().selectByProjectUuid(mergeBranchUuid, dbSession);
+ for (ComponentDto dto : components) {
+ uuidsByKey.put(dto.getKey(), dto.uuid());
+ }
- List components = dbClient.componentDao().selectByProjectUuid(mergeBranchUuid, dbSession);
- for (ComponentDto dto : components) {
- uuidsByKey.put(dto.getKey(), dto.uuid());
+ mergeBranchName = dbClient.branchDao().selectByUuid(dbSession, mergeBranchUuid).get().getKey();
}
}
}
+ public String getMergeBranchName() {
+ lazyInit();
+ return mergeBranchName;
+ }
+
@CheckForNull
public String getUuid(String dbKey) {
- if (uuidsByKey == null) {
- loadMergeBranchComponents();
- }
-
+ lazyInit();
String cleanComponentKey = removeBranchFromKey(dbKey);
return uuidsByKey.get(cleanComponentKey);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IntegrateIssuesVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IntegrateIssuesVisitor.java
index e0c9bd92fc1..d381db8fa36 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IntegrateIssuesVisitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IntegrateIssuesVisitor.java
@@ -26,6 +26,7 @@ import org.sonar.core.issue.DefaultIssue;
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.server.computation.task.projectanalysis.component.Component;
import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit;
+import org.sonar.server.computation.task.projectanalysis.component.MergeBranchComponentUuids;
import org.sonar.server.computation.task.projectanalysis.component.TypeAwareVisitorAdapter;
import org.sonar.server.util.cache.DiskCache;
@@ -39,9 +40,11 @@ public class IntegrateIssuesVisitor extends TypeAwareVisitorAdapter {
private final IssueTrackingDelegator issueTracking;
private final ShortBranchIssueMerger issueStatusCopier;
private final AnalysisMetadataHolder analysisMetadataHolder;
+ private final MergeBranchComponentUuids mergeBranchComponentUuids;
public IntegrateIssuesVisitor(IssueCache issueCache, IssueLifecycle issueLifecycle, IssueVisitors issueVisitors,
- AnalysisMetadataHolder analysisMetadataHolder, IssueTrackingDelegator issueTracking, ShortBranchIssueMerger issueStatusCopier) {
+ AnalysisMetadataHolder analysisMetadataHolder, IssueTrackingDelegator issueTracking, ShortBranchIssueMerger issueStatusCopier,
+ MergeBranchComponentUuids mergeBranchComponentUuids) {
super(CrawlerDepthLimit.FILE, POST_ORDER);
this.issueCache = issueCache;
this.issueLifecycle = issueLifecycle;
@@ -49,6 +52,7 @@ public class IntegrateIssuesVisitor extends TypeAwareVisitorAdapter {
this.analysisMetadataHolder = analysisMetadataHolder;
this.issueTracking = issueTracking;
this.issueStatusCopier = issueStatusCopier;
+ this.mergeBranchComponentUuids = mergeBranchComponentUuids;
}
@Override
@@ -92,7 +96,7 @@ public class IntegrateIssuesVisitor extends TypeAwareVisitorAdapter {
for (Map.Entry entry : matched.entrySet()) {
DefaultIssue raw = entry.getKey();
DefaultIssue base = entry.getValue();
- issueLifecycle.copyExistingOpenIssueFromLongLivingBranch(raw, base);
+ issueLifecycle.copyExistingOpenIssueFromLongLivingBranch(raw, base, mergeBranchComponentUuids.getMergeBranchName());
process(component, raw, cacheAppender);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueLifecycle.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueLifecycle.java
index 6b40c04feb4..00322067935 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueLifecycle.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueLifecycle.java
@@ -45,13 +45,16 @@ public class IssueLifecycle {
private final IssueChangeContext changeContext;
private final IssueFieldsSetter updater;
private final DebtCalculator debtCalculator;
+ private final AnalysisMetadataHolder analysisMetadataHolder;
public IssueLifecycle(AnalysisMetadataHolder analysisMetadataHolder, IssueWorkflow workflow, IssueFieldsSetter updater, DebtCalculator debtCalculator) {
- this(IssueChangeContext.createScan(new Date(analysisMetadataHolder.getAnalysisDate())), workflow, updater, debtCalculator);
+ this(analysisMetadataHolder, IssueChangeContext.createScan(new Date(analysisMetadataHolder.getAnalysisDate())), workflow, updater, debtCalculator);
}
@VisibleForTesting
- IssueLifecycle(IssueChangeContext changeContext, IssueWorkflow workflow, IssueFieldsSetter updater, DebtCalculator debtCalculator) {
+ IssueLifecycle(AnalysisMetadataHolder analysisMetadataHolder, IssueChangeContext changeContext, IssueWorkflow workflow, IssueFieldsSetter updater,
+ DebtCalculator debtCalculator) {
+ this.analysisMetadataHolder = analysisMetadataHolder;
this.workflow = workflow;
this.updater = updater;
this.debtCalculator = debtCalculator;
@@ -66,13 +69,19 @@ public class IssueLifecycle {
issue.setEffort(debtCalculator.calculate(issue));
}
- public void copyExistingOpenIssueFromLongLivingBranch(DefaultIssue raw, DefaultIssue base) {
+ public void copyExistingOpenIssueFromLongLivingBranch(DefaultIssue raw, DefaultIssue base, String fromLongBranchName) {
raw.setKey(Uuids.create());
raw.setNew(false);
copyIssueAttributes(raw, base);
+ raw.setFieldChange(changeContext, IssueFieldsSetter.FROM_LONG_BRANCH, fromLongBranchName, analysisMetadataHolder.getBranch().get().getName());
}
- public void copyIssueAttributes(DefaultIssue to, DefaultIssue from) {
+ public void mergeConfirmedOrResolvedFromShortLivingBranch(DefaultIssue raw, DefaultIssue base, String fromShortBranchName) {
+ copyIssueAttributes(raw, base);
+ raw.setFieldChange(changeContext, IssueFieldsSetter.FROM_SHORT_BRANCH, fromShortBranchName, analysisMetadataHolder.getBranch().get().getName());
+ }
+
+ private void copyIssueAttributes(DefaultIssue to, DefaultIssue from) {
to.setCopied(true);
copyFields(to, from);
if (from.manualSeverity()) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/ShortBranchIssueMerger.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/ShortBranchIssueMerger.java
index 79d5e5c2a77..41d55e85704 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/ShortBranchIssueMerger.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/ShortBranchIssueMerger.java
@@ -56,7 +56,7 @@ public class ShortBranchIssueMerger {
for (Map.Entry e : matchedRaws.entrySet()) {
ShortBranchIssue issue = e.getValue();
- issueLifecycle.copyIssueAttributes(e.getKey(), defaultIssues.get(issue));
+ issueLifecycle.mergeConfirmedOrResolvedFromShortLivingBranch(e.getKey(), defaultIssues.get(issue), issue.getBranchName());
}
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueFieldsSetter.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueFieldsSetter.java
index a1de892c458..1bfdd848ce8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueFieldsSetter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueFieldsSetter.java
@@ -58,6 +58,8 @@ public class IssueFieldsSetter {
public static final String STATUS = "status";
public static final String AUTHOR = "author";
public static final String FILE = "file";
+ public static final String FROM_LONG_BRANCH = "from_long_branch";
+ public static final String FROM_SHORT_BRANCH = "from_short_branch";
/**
* It should be renamed to 'effort', but it hasn't been done to prevent a massive update in database
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/ChangelogAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/ChangelogAction.java
index 35542267b9b..b1eebdecdd6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/ChangelogAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/ChangelogAction.java
@@ -175,5 +175,6 @@ public class ChangelogAction implements IssuesWsAction {
ComponentDto file = files.get(fileUuid);
return file == null ? null : file.longName();
}
+
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java
index 1427302612c..0f695c19d65 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java
@@ -119,6 +119,8 @@ public class IntegrateIssuesVisitorTest {
private MergeBranchComponentUuids mergeBranchComponentsUuids;
@Mock
private ShortBranchIssueMerger issueStatusCopier;
+ @Mock
+ private MergeBranchComponentUuids mergeBranchComponentUuids;
ArgumentCaptor defaultIssueCaptor;
@@ -150,7 +152,7 @@ public class IntegrateIssuesVisitorTest {
treeRootHolder.setRoot(PROJECT);
issueCache = new IssueCache(temp.newFile(), System2.INSTANCE);
when(issueFilter.accept(any(DefaultIssue.class), eq(FILE))).thenReturn(true);
- underTest = new IntegrateIssuesVisitor(issueCache, issueLifecycle, issueVisitors, analysisMetadataHolder, trackingDelegator, issueStatusCopier);
+ underTest = new IntegrateIssuesVisitor(issueCache, issueLifecycle, issueVisitors, analysisMetadataHolder, trackingDelegator, issueStatusCopier, mergeBranchComponentUuids);
}
@Test
@@ -258,6 +260,7 @@ public class IntegrateIssuesVisitorTest {
public void copy_issues_when_creating_new_long_living_branch() throws Exception {
when(mergeBranchComponentsUuids.getUuid(FILE_KEY)).thenReturn(FILE_UUID_ON_BRANCH);
+ when(mergeBranchComponentUuids.getMergeBranchName()).thenReturn("master");
when(analysisMetadataHolder.isLongLivingBranch()).thenReturn(true);
when(analysisMetadataHolder.isFirstAnalysis()).thenReturn(true);
@@ -284,7 +287,7 @@ public class IntegrateIssuesVisitorTest {
ArgumentCaptor rawIssueCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
ArgumentCaptor baseIssueCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueLifecycle).copyExistingOpenIssueFromLongLivingBranch(rawIssueCaptor.capture(), baseIssueCaptor.capture());
+ verify(issueLifecycle).copyExistingOpenIssueFromLongLivingBranch(rawIssueCaptor.capture(), baseIssueCaptor.capture(), eq("master"));
assertThat(rawIssueCaptor.getValue().severity()).isEqualTo(Severity.BLOCKER);
assertThat(baseIssueCaptor.getValue().severity()).isEqualTo(Severity.MAJOR);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueLifecycleTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueLifecycleTest.java
index ecd79be5617..5b13b2ea7f8 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueLifecycleTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueLifecycleTest.java
@@ -21,12 +21,16 @@ package org.sonar.server.computation.task.projectanalysis.issue;
import com.google.common.collect.ImmutableMap;
import java.util.Date;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.Duration;
import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
import org.sonar.core.issue.IssueChangeContext;
import org.sonar.db.protobuf.DbCommons;
import org.sonar.db.protobuf.DbIssues;
+import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
+import org.sonar.server.computation.task.projectanalysis.analysis.Branch;
import org.sonar.server.issue.IssueFieldsSetter;
import org.sonar.server.issue.workflow.IssueWorkflow;
@@ -57,7 +61,10 @@ public class IssueLifecycleTest {
DebtCalculator debtCalculator = mock(DebtCalculator.class);
- IssueLifecycle underTest = new IssueLifecycle(issueChangeContext, workflow, updater, debtCalculator);
+ @Rule
+ public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
+
+ IssueLifecycle underTest = new IssueLifecycle(analysisMetadataHolder, issueChangeContext, workflow, updater, debtCalculator);
@Test
public void initNewOpenIssue() throws Exception {
@@ -81,9 +88,23 @@ public class IssueLifecycleTest {
DefaultIssue fromShort = new DefaultIssue();
fromShort.setResolution("resolution");
fromShort.setStatus("status");
- underTest.copyIssueAttributes(raw, fromShort);
+
+ Date commentDate = new Date();
+ fromShort.addComment(new DefaultIssueComment()
+ .setIssueKey("short")
+ .setCreatedAt(commentDate)
+ .setUserLogin("user")
+ .setMarkdownText("A comment"));
+
+ Branch branch = mock(Branch.class);
+ when(branch.getName()).thenReturn("master");
+ analysisMetadataHolder.setBranch(branch);
+
+ underTest.mergeConfirmedOrResolvedFromShortLivingBranch(raw, fromShort, "feature/foo");
assertThat(raw.resolution()).isEqualTo("resolution");
assertThat(raw.status()).isEqualTo("status");
+ assertThat(raw.changes().get(0).get(IssueFieldsSetter.FROM_SHORT_BRANCH).oldValue()).isEqualTo("feature/foo");
+ assertThat(raw.changes().get(0).get(IssueFieldsSetter.FROM_SHORT_BRANCH).newValue()).isEqualTo("master");
}
@Test
@@ -123,7 +144,11 @@ public class IssueLifecycleTest {
when(debtCalculator.calculate(raw)).thenReturn(DEFAULT_DURATION);
- underTest.copyExistingOpenIssueFromLongLivingBranch(raw, base);
+ Branch branch = mock(Branch.class);
+ when(branch.getName()).thenReturn("release-2.x");
+ analysisMetadataHolder.setBranch(branch);
+
+ underTest.copyExistingOpenIssueFromLongLivingBranch(raw, base, "master");
assertThat(raw.isNew()).isFalse();
assertThat(raw.isCopied()).isTrue();
@@ -140,6 +165,8 @@ public class IssueLifecycleTest {
assertThat(raw.debt()).isEqualTo(DEFAULT_DURATION);
assertThat(raw.isOnDisabledRule()).isTrue();
assertThat(raw.selectedAt()).isEqualTo(1000L);
+ assertThat(raw.changes().get(0).get(IssueFieldsSetter.FROM_LONG_BRANCH).oldValue()).isEqualTo("master");
+ assertThat(raw.changes().get(0).get(IssueFieldsSetter.FROM_LONG_BRANCH).newValue()).isEqualTo("release-2.x");
verifyZeroInteractions(updater);
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/ShortBranchIssueMergerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/ShortBranchIssueMergerTest.java
index fcda03e282c..134f83b9d4e 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/ShortBranchIssueMergerTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/ShortBranchIssueMergerTest.java
@@ -72,7 +72,7 @@ public class ShortBranchIssueMergerTest {
@Test
public void do_nothing_if_no_new_issue() {
DefaultIssue i = createIssue("issue1", "rule1", Issue.STATUS_CONFIRMED, null);
- when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Collections.singleton(newShortBranchIssue(i)));
+ when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Collections.singleton(newShortBranchIssue(i, "myBranch")));
copier.tryMerge(component, Collections.emptyList());
verify(resolvedShortBranchIssuesLoader).loadCandidateIssuesForMergingInTargetBranch(component);
@@ -82,7 +82,7 @@ public class ShortBranchIssueMergerTest {
@Test
public void update_status_on_matches() {
DefaultIssue issue1 = createIssue("issue1", "rule1", Issue.STATUS_CONFIRMED, null);
- ShortBranchIssue shortBranchIssue = newShortBranchIssue(issue1);
+ ShortBranchIssue shortBranchIssue = newShortBranchIssue(issue1, "myBranch");
DefaultIssue newIssue = createIssue("issue2", "rule1", Issue.STATUS_OPEN, null);
when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Collections.singleton(shortBranchIssue));
@@ -91,21 +91,21 @@ public class ShortBranchIssueMergerTest {
ArgumentCaptor captor = ArgumentCaptor.forClass(Collection.class);
verify(resolvedShortBranchIssuesLoader).loadDefaultIssuesWithChanges(captor.capture());
assertThat(captor.getValue()).containsOnly(shortBranchIssue);
- verify(issueLifecycle).copyIssueAttributes(newIssue, issue1);
+ verify(issueLifecycle).mergeConfirmedOrResolvedFromShortLivingBranch(newIssue, issue1, "myBranch");
}
@Test
public void prefer_resolved_issues() {
- ShortBranchIssue shortBranchIssue1 = newShortBranchIssue(createIssue("issue1", "rule1", Issue.STATUS_CONFIRMED, null));
- ShortBranchIssue shortBranchIssue2 = newShortBranchIssue(createIssue("issue2", "rule1", Issue.STATUS_CONFIRMED, null));
+ ShortBranchIssue shortBranchIssue1 = newShortBranchIssue(createIssue("issue1", "rule1", Issue.STATUS_CONFIRMED, null), "myBranch1");
+ ShortBranchIssue shortBranchIssue2 = newShortBranchIssue(createIssue("issue2", "rule1", Issue.STATUS_CONFIRMED, null), "myBranch2");
DefaultIssue issue3 = createIssue("issue3", "rule1", Issue.STATUS_RESOLVED, Issue.RESOLUTION_FALSE_POSITIVE);
- ShortBranchIssue shortBranchIssue3 = newShortBranchIssue(issue3);
+ ShortBranchIssue shortBranchIssue3 = newShortBranchIssue(issue3, "myBranch3");
DefaultIssue newIssue = createIssue("newIssue", "rule1", Issue.STATUS_OPEN, null);
when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Arrays.asList(shortBranchIssue1, shortBranchIssue2, shortBranchIssue3));
when(resolvedShortBranchIssuesLoader.loadDefaultIssuesWithChanges(anyListOf(ShortBranchIssue.class))).thenReturn(ImmutableMap.of(shortBranchIssue3, issue3));
copier.tryMerge(component, Collections.singleton(newIssue));
- verify(issueLifecycle).copyIssueAttributes(newIssue, issue3);
+ verify(issueLifecycle).mergeConfirmedOrResolvedFromShortLivingBranch(newIssue, issue3, "myBranch3");
}
private static DefaultIssue createIssue(String key, String ruleKey, String status, @Nullable String resolution) {
@@ -119,7 +119,7 @@ public class ShortBranchIssueMergerTest {
return issue;
}
- private ShortBranchIssue newShortBranchIssue(DefaultIssue i) {
- return new ShortBranchIssue(i.key(), i.line(), i.message(), i.getLineHash(), i.ruleKey(), i.status());
+ private ShortBranchIssue newShortBranchIssue(DefaultIssue i, String originBranch) {
+ return new ShortBranchIssue(i.key(), i.line(), i.message(), i.getLineHash(), i.ruleKey(), i.status(), originBranch);
}
}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueChangelogDiff.js b/server/sonar-web/src/main/js/components/issue/components/IssueChangelogDiff.js
index e0b1a93556b..f858a13810a 100644
--- a/server/sonar-web/src/main/js/components/issue/components/IssueChangelogDiff.js
+++ b/server/sonar-web/src/main/js/components/issue/components/IssueChangelogDiff.js
@@ -43,6 +43,28 @@ export default function IssueChangelogDiff(props /*: { diff: ChangelogDiff } */)
);
}
+ if (diff.key === 'from_long_branch') {
+ return (
+
+ {translateWithParameters(
+ 'issue.change.from_long_branch',
+ diff.oldValue || '',
+ diff.newValue || ''
+ )}
+
+ );
+ }
+ if (diff.key === 'from_short_branch') {
+ return (
+
+ {translateWithParameters(
+ 'issue.change.from_short_branch',
+ diff.oldValue || '',
+ diff.newValue || ''
+ )}
+
+ );
+ }
let message;
if (diff.newValue != null) {
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 970c8424246..06b017e85f6 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -607,6 +607,8 @@ issues.my_issues=My Issues
issue.changelog.changed_to={0} changed to {1}
issue.changelog.was=was {0}
issue.change.file_move=The file has been moved from {0} to {1}
+issue.change.from_long_branch=The issue has been copied from branch '{0}' to branch '{1}'
+issue.change.from_short_branch=The issue has been merged from branch '{0}' into branch '{1}'
issue.changelog.removed={0} removed
issue.changelog.field.severity=Severity
issue.changelog.field.actionPlan=Action Plan