private void appendChanges(Notification notif, StringBuilder sb) {
appendField(sb, "Comment", null, notif.getFieldValue("comment"));
- appendField(sb, "Assignee", notif.getFieldValue("old.assignee"), notif.getFieldValue("new.assignee"));
+ appendFieldWithoutHistory(sb, "Assignee", notif.getFieldValue("old.assignee"), notif.getFieldValue("new.assignee"));
appendField(sb, "Severity", notif.getFieldValue("old.severity"), notif.getFieldValue("new.severity"));
appendField(sb, "Resolution", notif.getFieldValue("old.resolution"), notif.getFieldValue("new.resolution"));
appendField(sb, "Status", notif.getFieldValue("old.status"), notif.getFieldValue("new.status"));
appendField(sb, "Message", notif.getFieldValue("old.message"), notif.getFieldValue("new.message"));
appendField(sb, "Author", notif.getFieldValue("old.author"), notif.getFieldValue("new.author"));
- appendField(sb, "Action Plan", notif.getFieldValue("old.actionPlanKey"), notif.getFieldValue("new.actionPlanKey"));
+ appendFieldWithoutHistory(sb, "Action Plan", notif.getFieldValue("old.actionPlan"), notif.getFieldValue("new.actionPlan")) ;
}
private void appendHeader(Notification notif, StringBuilder sb) {
}
}
+ private void appendFieldWithoutHistory(StringBuilder sb, String name, @Nullable String oldValue, @Nullable String newValue) {
+ if (oldValue != null || newValue != null) {
+ sb.append(name);
+ if (newValue != null) {
+ sb.append(" changed to ");
+ sb.append(newValue);
+ } else {
+ sb.append(" removed");
+ }
+ sb.append(NEW_LINE);
+ }
+ }
+
private String getUserFullName(@Nullable String login) {
if (login == null) {
return null;
}
@Test
- public void test_email_with_changes() {
- Notification notification = new Notification("issue-changes")
- .setFieldValue("projectName", "Struts")
- .setFieldValue("projectKey", "org.apache:struts")
- .setFieldValue("componentName", "org.apache.struts.Action")
- .setFieldValue("key", "ABCDE")
- .setFieldValue("ruleName", "Avoid Cycles")
- .setFieldValue("message", "Has 3 cycles")
+ public void email_should_display_assignee_change() throws Exception {
+ Notification notification = generateNotification()
+ .setFieldValue("old.assignee", "simon")
+ .setFieldValue("new.assignee", "louis");
+
+ EmailMessage email = template.format(notification);
+ assertThat(email.getMessageId()).isEqualTo("issue-changes/ABCDE");
+ assertThat(email.getSubject()).isEqualTo("Struts, change on issue #ABCDE");
+
+ String message = email.getMessage();
+ String expectedMessage = TestUtils.getResourceContent("/org/sonar/plugins/core/issue/notification/IssueChangesEmailTemplateTest/email_with_assignee_change.txt");
+ expectedMessage = StringUtils.remove(expectedMessage, '\r');
+ assertThat(message).isEqualTo(expectedMessage);
+ assertThat(email.getFrom()).isNull();
+ }
+
+ @Test
+ public void email_should_display_plan_change() throws Exception {
+ Notification notification = generateNotification()
+ .setFieldValue("old.actionPlan", null)
+ .setFieldValue("new.actionPlan", "ABC 1.0");
+
+ EmailMessage email = template.format(notification);
+ assertThat(email.getMessageId()).isEqualTo("issue-changes/ABCDE");
+ assertThat(email.getSubject()).isEqualTo("Struts, change on issue #ABCDE");
+
+ String message = email.getMessage();
+ String expectedMessage = TestUtils.getResourceContent("/org/sonar/plugins/core/issue/notification/IssueChangesEmailTemplateTest/email_with_action_plan_change.txt");
+ expectedMessage = StringUtils.remove(expectedMessage, '\r');
+ assertThat(message).isEqualTo(expectedMessage);
+ assertThat(email.getFrom()).isNull();
+ }
+
+ @Test
+ public void test_email_with_multiple_changes() {
+ Notification notification = generateNotification()
.setFieldValue("comment", "How to fix it?")
.setFieldValue("old.assignee", "simon")
.setFieldValue("new.assignee", "louis")
assertThat(email.getSubject()).isEqualTo("Struts, change on issue #ABCDE");
String message = email.getMessage();
- String expectedMessage = TestUtils.getResourceContent("/org/sonar/plugins/core/issue/notification/IssueChangesEmailTemplateTest/email_with_changes.txt");
+ String expectedMessage = TestUtils.getResourceContent("/org/sonar/plugins/core/issue/notification/IssueChangesEmailTemplateTest/email_with_multiple_changes.txt");
expectedMessage = StringUtils.remove(expectedMessage, '\r');
assertThat(message).isEqualTo(expectedMessage);
assertThat(email.getFrom()).isNull();
assertThat(message.getFrom()).isEqualTo("Simon");
}
+ private Notification generateNotification() {
+ Notification notification = new Notification("issue-changes")
+ .setFieldValue("projectName", "Struts")
+ .setFieldValue("projectKey", "org.apache:struts")
+ .setFieldValue("componentName", "org.apache.struts.Action")
+ .setFieldValue("key", "ABCDE")
+ .setFieldValue("ruleName", "Avoid Cycles")
+ .setFieldValue("message", "Has 3 cycles");
+ return notification;
+ }
}
--- /dev/null
+org.apache.struts.Action
+Rule: Avoid Cycles
+Message: Has 3 cycles
+
+Action Plan changed to ABC 1.0
+
+See it in SonarQube: http://nemo.sonarsource.org/issue/show/ABCDE
--- /dev/null
+org.apache.struts.Action
+Rule: Avoid Cycles
+Message: Has 3 cycles
+
+Assignee changed to louis
+
+See it in SonarQube: http://nemo.sonarsource.org/issue/show/ABCDE
+++ /dev/null
-org.apache.struts.Action
-Rule: Avoid Cycles
-Message: Has 3 cycles
-
-Comment: How to fix it?
-Assignee: louis (was simon)
-Resolution: FALSE-POSITIVE
-Status: RESOLVED
-
-See it in SonarQube: http://nemo.sonarsource.org/issue/show/ABCDE
--- /dev/null
+org.apache.struts.Action
+Rule: Avoid Cycles
+Message: Has 3 cycles
+
+Comment: How to fix it?
+Assignee changed to louis
+Resolution: FALSE-POSITIVE
+Status: RESOLVED
+
+See it in SonarQube: http://nemo.sonarsource.org/issue/show/ABCDE
assertThat(notification).isNull();
Mockito.verifyZeroInteractions(manager);
}
+
+ @Test
+ public void should_store_changelog_in_notification() throws Exception {
+ IssueChangeContext context = IssueChangeContext.createScan(new Date());
+
+ DefaultIssue issue = new DefaultIssue()
+ .setMessage("the message")
+ .setKey("ABCDE")
+ .setAssignee("freddy")
+ .setFieldChange(context, "resolution", null, "FIXED")
+ .setFieldChange(context, "status", "OPEN", "RESOLVED")
+ .setSendNotifications(true)
+ .setComponentKey("struts:Action")
+ .setProjectKey("struts");
+ DefaultIssueQueryResult queryResult = new DefaultIssueQueryResult(Arrays.<Issue>asList(issue));
+ queryResult.addProjects(Arrays.<Component>asList(new Project("struts")));
+
+ Notification notification = issueNotifications.sendChanges(issue, context, queryResult);
+
+ assertThat(notification.getFieldValue("changeLog")).contains("Resolution: FIXED");
+ assertThat(notification.getFieldValue("changeLog")).contains("Status: RESOLVED (was OPEN)");
+ }
}
private final UserFinder userFinder;
private final IssueUpdater issueUpdater;
+ private User assignee;
+
public AssignAction(UserFinder userFinder, IssueUpdater issueUpdater) {
super(KEY);
this.userFinder = userFinder;
@Override
public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession){
- String assignee = assignee(properties);
- if (!Strings.isNullOrEmpty(assignee) && userFinder.findByLogin(assignee) == null) {
+ String assignee = assigneeValue(properties);
+ if (!Strings.isNullOrEmpty(assignee) && getOrSelectUser(assignee) == null) {
throw new IllegalArgumentException("Unknown user: " + assignee);
}
return true;
@Override
public boolean execute(Map<String, Object> properties, Context context) {
- User user = userFinder.findByLogin(assignee(properties));
- return issueUpdater.assign((DefaultIssue) context.issue(), user, context.issueChangeContext());
+ String assignee = assigneeValue(properties);
+ return issueUpdater.assign((DefaultIssue) context.issue(), getOrSelectUser(assignee), context.issueChangeContext());
}
- private String assignee(Map<String, Object> properties){
+ private String assigneeValue(Map<String, Object> properties) {
return (String) properties.get("assignee");
}
+
+ private User getOrSelectUser(String assigneeKey) {
+ if(assignee == null) {
+ assignee = userFinder.findByLogin(assigneeKey);
+ }
+ return assignee;
+ }
}
\ No newline at end of file
private final ActionPlanService actionPlanService;
private final IssueUpdater issueUpdater;
+ private ActionPlan actionPlan;
+
public PlanAction(ActionPlanService actionPlanService, IssueUpdater issueUpdater) {
super(KEY);
this.actionPlanService = actionPlanService;
@Override
public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
- String actionPlanKey = planKey(properties);
- if (!Strings.isNullOrEmpty(actionPlanKey)) {
- ActionPlan actionPlan = actionPlanService.findByKey(actionPlanKey, userSession);
+ String actionPlanValue = planValue(properties);
+ if (!Strings.isNullOrEmpty(actionPlanValue)) {
+ ActionPlan actionPlan = getOrSelectActionPlan(actionPlanValue, userSession);
if (actionPlan == null) {
- throw new IllegalArgumentException("Unknown action plan: " + actionPlanKey);
+ throw new IllegalArgumentException("Unknown action plan: " + actionPlanValue);
}
verifyIssuesAreAllRelatedOnActionPlanProject(issues, actionPlan);
}
@Override
public boolean execute(Map<String, Object> properties, Context context) {
- ActionPlan actionPlan = actionPlanService.findByKey(planKey(properties), UserSession.get());
- return issueUpdater.plan((DefaultIssue) context.issue(), actionPlan, context.issueChangeContext());
+ String actionPlan = planValue(properties);
+ return issueUpdater.plan((DefaultIssue) context.issue(), getOrSelectActionPlan(actionPlan, UserSession.get()), context.issueChangeContext());
}
- private String planKey(Map<String, Object> properties) {
+ private String planValue(Map<String, Object> properties) {
return (String) properties.get("plan");
}
}
}
+ private ActionPlan getOrSelectActionPlan(String planValue, UserSession userSession) {
+ if(actionPlan == null) {
+ actionPlan = actionPlanService.findByKey(planValue, userSession);
+ }
+ return actionPlan;
+ }
}
\ No newline at end of file