From: Janos Gyerik Date: Thu, 24 Aug 2017 12:20:51 +0000 (+0200) Subject: SONAR-9616 Support notifications on branches (#2413) X-Git-Tag: 6.6-RC1~380^2~66 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=0de8f0ee51349bc43d072b8f8cd0fe94074ae214;p=sonarqube.git SONAR-9616 Support notifications on branches (#2413) --- diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml index a30f402448c..c61e9363f90 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml @@ -83,6 +83,7 @@ from projects p where p.enabled=${_true} + and p.main_branch_project_uuid is null and p.kee in #{key,jdbcType=VARCHAR} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java index d39e3c4021a..5a042baf574 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java @@ -25,6 +25,7 @@ import org.sonar.api.measures.CoreMetrics; import org.sonar.api.notifications.Notification; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; +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.ComponentVisitor; import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; @@ -52,15 +53,17 @@ public class QualityGateEventsStep implements ComputationStep { private final MeasureRepository measureRepository; private final EventRepository eventRepository; private final NotificationService notificationService; + private final AnalysisMetadataHolder analysisMetadataHolder; public QualityGateEventsStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository, EventRepository eventRepository, - NotificationService notificationService) { + NotificationService notificationService, AnalysisMetadataHolder analysisMetadataHolder) { this.treeRootHolder = treeRootHolder; this.metricRepository = metricRepository; this.measureRepository = measureRepository; this.eventRepository = eventRepository; this.notificationService = notificationService; + this.analysisMetadataHolder = analysisMetadataHolder; } @Override @@ -129,6 +132,7 @@ public class QualityGateEventsStep implements ComputationStep { .setFieldValue("alertText", rawStatus.getText()) .setFieldValue("alertLevel", rawStatus.getStatus().toString()) .setFieldValue("isNewAlert", Boolean.toString(isNewAlert)); + analysisMetadataHolder.getBranch().ifPresent(branch -> notification.setFieldValue("branch", branch.getName().orElse(null))); notificationService.deliver(notification); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SendIssueNotificationsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SendIssueNotificationsStep.java index 8e8360ac669..1688932db8d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SendIssueNotificationsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SendIssueNotificationsStep.java @@ -26,6 +26,7 @@ import java.util.Set; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.util.CloseableIterator; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; import org.sonar.server.computation.task.projectanalysis.issue.IssueCache; @@ -105,7 +106,8 @@ public class SendIssueNotificationsStep implements ComputationStep { IssueChangeNotification changeNotification = new IssueChangeNotification(); changeNotification.setRuleName(rules.getByKey(issue.ruleKey()).getName()); changeNotification.setIssue(issue); - changeNotification.setProject(project.getKey(), project.getName()); + String branchName = analysisMetadataHolder.getBranch().flatMap(Branch::getName).orElse(null); + changeNotification.setProject(project.getKey(), project.getName(), branchName); service.deliver(changeNotification); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueUpdater.java index b10635e4354..a368b01ca7a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueUpdater.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueUpdater.java @@ -80,7 +80,7 @@ public class IssueUpdater { .setIssue(issue) .setChangeAuthorLogin(context.login()) .setRuleName(rule.map(RuleDefinitionDto::getName).orElse(null)) - .setProject(project.getDbKey(), project.name()) + .setProject(project.getKey(), project.name(), project.getBranch()) .setComponent(component) .setComment(comment)); return issueDto; diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/AbstractNewIssuesEmailTemplate.java b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/AbstractNewIssuesEmailTemplate.java index 09c6611dcfe..caecaa2851e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/AbstractNewIssuesEmailTemplate.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/AbstractNewIssuesEmailTemplate.java @@ -52,6 +52,7 @@ public abstract class AbstractNewIssuesEmailTemplate extends EmailTemplate { static final String FIELD_PROJECT_DATE = "projectDate"; static final String FIELD_PROJECT_UUID = "projectUuid"; static final String FIELD_ASSIGNEE = "assignee"; + static final String FIELD_BRANCH = "branch"; protected final EmailSettings settings; protected final I18n i18n; @@ -175,8 +176,13 @@ public abstract class AbstractNewIssuesEmailTemplate extends EmailTemplate { String dateString = notification.getFieldValue(FIELD_PROJECT_DATE); if (projectKey != null && dateString != null) { Date date = DateUtils.parseDateTime(dateString); - String url = String.format("%s/project/issues?id=%s&createdAt=%s", - settings.getServerBaseURL(), encode(projectKey), encode(DateUtils.formatDateTime(date))); + String url = String.format("%s/project/issues?id=%s", + settings.getServerBaseURL(), encode(projectKey)); + String branchName = notification.getFieldValue("branch"); + if (branchName != null) { + url += "&branch=" + encode(branchName); + } + url += "&createdAt=" + encode(DateUtils.formatDateTime(date)); message .append("See it in SonarQube: ") .append(url) diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangeNotification.java b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangeNotification.java index 7c91d749fd8..f5aaa6cf104 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangeNotification.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangeNotification.java @@ -55,14 +55,15 @@ public class IssueChangeNotification extends Notification { } public IssueChangeNotification setProject(ComponentDto project) { - setFieldValue("projectName", project.longName()); - setFieldValue("projectKey", project.getDbKey()); - return this; + return setProject(project.getKey(), project.longName(), project.getBranch()); } - public IssueChangeNotification setProject(String projectKey, String projectName) { + public IssueChangeNotification setProject(String projectKey, String projectName, @Nullable String branch) { setFieldValue("projectName", projectName); setFieldValue("projectKey", projectKey); + if (branch != null) { + setFieldValue("branch", branch); + } return this; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangesEmailTemplate.java b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangesEmailTemplate.java index 6835d58a35f..81c8a698502 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangesEmailTemplate.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangesEmailTemplate.java @@ -109,8 +109,12 @@ public class IssueChangesEmailTemplate extends EmailTemplate { sb.append("See it in SonarQube: ").append(settings.getServerBaseURL()) .append("/project/issues?id=").append(encode(notification.getFieldValue("projectKey"), "UTF-8")) .append("&issues=").append(issueKey) - .append("&open=").append(issueKey) - .append(NEW_LINE); + .append("&open=").append(issueKey); + String branchName = notification.getFieldValue("branch"); + if (branchName != null) { + sb.append("&branch=").append(branchName); + } + sb.append(NEW_LINE); } catch (UnsupportedEncodingException e) { throw new IllegalStateException("Encoding not supported", e); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplate.java b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplate.java index e57c8f4beb1..3beaa27762c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplate.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplate.java @@ -58,13 +58,17 @@ public class MyNewIssuesEmailTemplate extends AbstractNewIssuesEmailTemplate { String projectUuid = notification.getFieldValue(FIELD_PROJECT_UUID); String dateString = notification.getFieldValue(FIELD_PROJECT_DATE); String assignee = notification.getFieldValue(FIELD_ASSIGNEE); + String branch = notification.getFieldValue(FIELD_BRANCH); if (projectUuid != null && dateString != null && assignee != null) { Date date = DateUtils.parseDateTime(dateString); - String url = String.format("%s/issues?projectUuids=%s&assignees=%s&createdAt=%s", + String url = String.format("%s/issues?projectUuids=%s&assignees=%s", settings.getServerBaseURL(), encode(projectUuid), - encode(assignee), - encode(DateUtils.formatDateTime(date))); + encode(assignee)); + if (branch != null) { + url += "&branch=" + encode(branch); + } + url += "&createdAt=" + encode(DateUtils.formatDateTime(date)); message.append("See it in SonarQube: ").append(url).append(NEW_LINE); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java index bd4b62667f8..5012cd3b96b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java @@ -129,7 +129,7 @@ public abstract class AbstractUserSession implements UserSession { protected List doKeepAuthorizedComponents(String permission, Collection components) { boolean allowPublicComponent = ProjectPermissions.PUBLIC_PERMISSIONS.contains(permission); return components.stream() - .filter(c -> (allowPublicComponent && !c.isPrivate()) || hasProjectUuidPermission(permission, c.projectUuid())) + .filter(c -> (allowPublicComponent && !c.isPrivate()) || hasComponentPermission(permission, c)) .collect(MoreCollectors.toList()); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStepTest.java index 8f634c9b33e..2508728aa4a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStepTest.java @@ -25,7 +25,9 @@ import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.sonar.api.notifications.Notification; +import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; import org.sonar.server.computation.task.projectanalysis.component.Component; +import org.sonar.server.computation.task.projectanalysis.component.DefaultBranchImpl; import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; import org.sonar.server.computation.task.projectanalysis.event.Event; @@ -62,6 +64,9 @@ public class QualityGateEventsStepTest { @Rule public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); + @Rule + public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule(); + private ArgumentCaptor eventArgumentCaptor = ArgumentCaptor.forClass(Event.class); private ArgumentCaptor notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); @@ -71,11 +76,12 @@ public class QualityGateEventsStepTest { private MeasureRepository measureRepository = mock(MeasureRepository.class); private EventRepository eventRepository = mock(EventRepository.class); private NotificationService notificationService = mock(NotificationService.class); - private QualityGateEventsStep underTest = new QualityGateEventsStep(treeRootHolder, metricRepository, measureRepository, eventRepository, notificationService); + private QualityGateEventsStep underTest = new QualityGateEventsStep(treeRootHolder, metricRepository, measureRepository, eventRepository, notificationService, analysisMetadataHolder); @Before public void setUp() { when(metricRepository.getByKey(ALERT_STATUS_KEY)).thenReturn(alertStatusMetric); + analysisMetadataHolder.setBranch(null); treeRootHolder.setRoot(PROJECT_COMPONENT); } @@ -182,6 +188,7 @@ public class QualityGateEventsStepTest { assertThat(notification.getFieldValue("projectKey")).isEqualTo(PROJECT_COMPONENT.getKey()); assertThat(notification.getFieldValue("projectUuid")).isEqualTo(PROJECT_COMPONENT.getUuid()); assertThat(notification.getFieldValue("projectName")).isEqualTo(PROJECT_COMPONENT.getName()); + assertThat(notification.getFieldValue("branch")).isNull(); assertThat(notification.getFieldValue("alertLevel")).isEqualTo(rawAlterStatus.name()); assertThat(notification.getFieldValue("alertName")).isEqualTo(expectedLabel); } @@ -233,10 +240,33 @@ public class QualityGateEventsStepTest { assertThat(notification.getFieldValue("projectKey")).isEqualTo(PROJECT_COMPONENT.getKey()); assertThat(notification.getFieldValue("projectUuid")).isEqualTo(PROJECT_COMPONENT.getUuid()); assertThat(notification.getFieldValue("projectName")).isEqualTo(PROJECT_COMPONENT.getName()); + assertThat(notification.getFieldValue("branch")).isNull(); assertThat(notification.getFieldValue("alertLevel")).isEqualTo(newQualityGateStatus.getStatus().name()); assertThat(notification.getFieldValue("alertName")).isEqualTo(expectedLabel); reset(measureRepository, eventRepository, notificationService); } + @Test + public void verify_branch_name_is_set_in_notification() { + String branchName = "feature1"; + analysisMetadataHolder.setBranch(new DefaultBranchImpl(branchName)); + + when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(Measure.newMeasureBuilder().setQualityGateStatus(WARN_QUALITY_GATE_STATUS).createNoValue())); + when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn( + of(Measure.newMeasureBuilder().setQualityGateStatus(new QualityGateStatus(ERROR)).createNoValue())); + + underTest.execute(); + + verify(notificationService).deliver(notificationArgumentCaptor.capture()); + Notification notification = notificationArgumentCaptor.getValue(); + assertThat(notification.getType()).isEqualTo("alerts"); + assertThat(notification.getFieldValue("projectKey")).isEqualTo(PROJECT_COMPONENT.getKey()); + assertThat(notification.getFieldValue("projectUuid")).isEqualTo(PROJECT_COMPONENT.getUuid()); + assertThat(notification.getFieldValue("projectName")).isEqualTo(PROJECT_COMPONENT.getName()); + assertThat(notification.getFieldValue("branch")).isEqualTo(branchName); + + reset(measureRepository, eventRepository, notificationService); + } + } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueUpdaterTest.java index ce7fd1dc762..8e33f079c96 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueUpdaterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueUpdaterTest.java @@ -123,6 +123,26 @@ public class IssueUpdaterTest { assertThat(issueChangeNotification.getFieldValue("comment")).isEqualTo("increase severity"); } + @Test + public void verify_notification_on_branch() throws Exception { + RuleDto rule = ruleDbTester.insertRule(newRuleDto()); + ComponentDto project = componentDbTester.insertMainBranch(); + ComponentDto branch = componentDbTester.insertProjectBranch(project); + ComponentDto file = componentDbTester.insertComponent(newFileDto(branch)); + DefaultIssue issue = issueDbTester.insertIssue(IssueTesting.newIssue(rule.getDefinition(), branch, file)).setSeverity(MAJOR).toDefaultIssue(); + IssueChangeContext context = IssueChangeContext.createUser(new Date(), "john"); + issueFieldsSetter.setSeverity(issue, BLOCKER, context); + + underTest.saveIssue(dbTester.getSession(), issue, context, "increase severity"); + + verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture()); + IssueChangeNotification issueChangeNotification = notificationArgumentCaptor.getValue(); + assertThat(issueChangeNotification.getFieldValue("key")).isEqualTo(issue.key()); + assertThat(issueChangeNotification.getFieldValue("projectKey")).isEqualTo(project.getDbKey()); + assertThat(issueChangeNotification.getFieldValue("projectName")).isEqualTo(project.name()); + assertThat(issueChangeNotification.getFieldValue("branch")).isEqualTo(branch.getBranch()); + } + @Test public void verify_notification_when_issue_is_linked_on_removed_rule() throws Exception { RuleDto rule = ruleDbTester.insertRule(newRuleDto().setStatus(RuleStatus.REMOVED)); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangeNotificationTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangeNotificationTest.java index 0d02dcbd8cd..c3eae3dbea8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangeNotificationTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangeNotificationTest.java @@ -84,10 +84,19 @@ public class IssueChangeNotificationTest { } @Test - public void set_project() { - IssueChangeNotification result = notification.setProject("MyService", "My Service"); + public void set_project_without_branch() { + IssueChangeNotification result = notification.setProject("MyService", "My Service", null); assertThat(result.getFieldValue("projectKey")).isEqualTo("MyService"); assertThat(result.getFieldValue("projectName")).isEqualTo("My Service"); + assertThat(result.getFieldValue("branch")).isNull(); + } + + @Test + public void set_project_with_branch() { + IssueChangeNotification result = notification.setProject("MyService", "My Service", "feature1"); + assertThat(result.getFieldValue("projectKey")).isEqualTo("MyService"); + assertThat(result.getFieldValue("projectName")).isEqualTo("My Service"); + assertThat(result.getFieldValue("branch")).isEqualTo("feature1"); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest.java index 544c2304213..3e858e61915 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest.java @@ -147,13 +147,30 @@ public class IssueChangesEmailTemplateTest { assertThat(email.getFrom()).isNull(); } + @Test + public void test_email_with_issue_on_branch() throws Exception { + Notification notification = generateNotification() + .setFieldValue("branch", "feature1"); + + EmailMessage email = underTest.format(notification); + assertThat(email.getMessageId()).isEqualTo("issue-changes/ABCDE"); + assertThat(email.getSubject()).isEqualTo("Struts, change on issue #ABCDE"); + + String message = email.getMessage(); + String expected = Resources.toString(Resources.getResource( + "org/sonar/server/issue/notification/IssueChangesEmailTemplateTest/email_with_issue_on_branch.txt"), + StandardCharsets.UTF_8); + expected = StringUtils.remove(expected, '\r'); + assertThat(message).isEqualTo(expected); + } + @Test public void notification_sender_should_be_the_author_of_change() { db.users().insertUser(newUserDto().setLogin("simon").setName("Simon")); Notification notification = new IssueChangeNotification() .setChangeAuthorLogin("simon") - .setProject("Struts", "org.apache:struts"); + .setProject("Struts", "org.apache:struts", null); EmailMessage message = underTest.format(notification); assertThat(message.getFrom()).isEqualTo("Simon"); @@ -165,7 +182,7 @@ public class IssueChangesEmailTemplateTest { Notification notification = new IssueChangeNotification() .setChangeAuthorLogin("simon") - .setProject("Struts", "org.apache:struts"); + .setProject("Struts", "org.apache:struts", null); EmailMessage message = underTest.format(notification); assertThat(message.getFrom()).isEqualTo("simon"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest.java index 0c00dba4dce..8922e3fe0c6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest.java @@ -95,7 +95,7 @@ public class MyNewIssuesEmailTemplateTest { EmailMessage message = underTest.format(notification); // TODO datetime to be completed when test is isolated from JVM timezone - assertStartsWithFile(message.getMessage(), getClass().getResource("MyNewIssuesEmailTemplateTest/email_with_all_details.txt")); + assertStartsWithFile(message.getMessage(), "MyNewIssuesEmailTemplateTest/email_with_all_details.txt"); } @Test @@ -123,7 +123,18 @@ public class MyNewIssuesEmailTemplateTest { EmailMessage message = underTest.format(notification); // TODO datetime to be completed when test is isolated from JVM timezone - assertStartsWithFile(message.getMessage(), getClass().getResource("MyNewIssuesEmailTemplateTest/email_with_no_assignee_tags_components.txt")); + assertStartsWithFile(message.getMessage(), "MyNewIssuesEmailTemplateTest/email_with_no_assignee_tags_components.txt"); + } + + @Test + public void format_email_with_issue_on_branch() throws Exception { + Notification notification = newNotification() + .setFieldValue("branch", "feature1"); + + EmailMessage message = underTest.format(notification); + + // TODO datetime to be completed when test is isolated from JVM timezone + assertStartsWithFile(message.getMessage(), "MyNewIssuesEmailTemplateTest/email_with_issue_on_branch.txt"); } @Test @@ -176,8 +187,8 @@ public class MyNewIssuesEmailTemplateTest { .setFieldValue(RULE + ".2.count", "5"); } - private static void assertStartsWithFile(String message, URL file) throws IOException { - String fileContent = IOUtils.toString(file, StandardCharsets.UTF_8); + private void assertStartsWithFile(String message, String resourcePath) throws IOException { + String fileContent = IOUtils.toString(getClass().getResource(resourcePath), StandardCharsets.UTF_8); assertThat(sanitizeString(message)).startsWith(sanitizeString(fileContent)); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest.java index 341ccd92a14..b2116b238fd 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.issue.notification; +import java.io.IOException; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.junit.Before; @@ -112,8 +113,7 @@ public class NewIssuesEmailTemplateTest { EmailMessage message = template.format(notification); // TODO datetime to be completed when test is isolated from JVM timezone - String expectedContent = IOUtils.toString(getClass().getResource("NewIssuesEmailTemplateTest/email_with_all_details.txt"), StandardCharsets.UTF_8); - assertThat(message.getMessage()).startsWith(StringUtils.remove(expectedContent, '\r')); + assertStartsWithFile(message.getMessage(), "NewIssuesEmailTemplateTest/email_with_all_details.txt"); } @Test @@ -123,8 +123,18 @@ public class NewIssuesEmailTemplateTest { EmailMessage message = template.format(notification); // TODO datetime to be completed when test is isolated from JVM timezone - String expectedContent = IOUtils.toString(getClass().getResource("NewIssuesEmailTemplateTest/email_with_partial_details.txt"), StandardCharsets.UTF_8); - assertThat(message.getMessage()).startsWith(StringUtils.remove(expectedContent, '\r')); + assertStartsWithFile(message.getMessage(), "NewIssuesEmailTemplateTest/email_with_partial_details.txt"); + } + + @Test + public void format_email_with_issue_on_branch() throws Exception { + Notification notification = newNotification() + .setFieldValue("branch", "feature1"); + + EmailMessage message = template.format(notification); + + // TODO datetime to be completed when test is isolated from JVM timezone + assertStartsWithFile(message.getMessage(), "NewIssuesEmailTemplateTest/email_with_issue_on_branch.txt"); } @Test @@ -184,4 +194,16 @@ public class NewIssuesEmailTemplateTest { .setFieldValue(RULE + ".2.label", "Rule the World (Java)") .setFieldValue(RULE + ".2.count", "5"); } + + private void assertStartsWithFile(String message, String resourcePath) throws IOException { + String fileContent = IOUtils.toString(getClass().getResource(resourcePath), StandardCharsets.UTF_8); + assertThat(sanitizeString(message)).startsWith(sanitizeString(fileContent)); + } + + /** + * sanitize EOL and tabs if git clone is badly configured + */ + private static String sanitizeString(String s) { + return s.replaceAll("\\r\\n|\\r|\\s+", ""); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java index 42d036f3e04..5225acb63db 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java @@ -123,7 +123,7 @@ public class BulkChangeActionTest { issueWorkflow.start(); rule = db.rules().insertRule(newRuleDto()); organization = db.organizations().insert(); - project = db.components().insertPrivateProject(organization); + project = db.components().insertMainBranch(organization); file = db.components().insertComponent(newFileDto(project)); user = db.users().insertUser("john"); when(system2.now()).thenReturn(NOW); @@ -241,7 +241,6 @@ public class BulkChangeActionTest { public void send_notification() throws Exception { setUserProjectPermissions(USER); IssueDto issueDto = db.issues().insertIssue(newUnresolvedIssue().setType(BUG)); - ArgumentCaptor issueChangeNotificationCaptor = ArgumentCaptor.forClass(IssueChangeNotification.class); BulkChangeWsResponse response = call(BulkChangeRequest.builder() .setIssues(singletonList(issueDto.getKey())) @@ -250,6 +249,8 @@ public class BulkChangeActionTest { .build()); checkResponse(response, 1, 1, 0, 0); + + ArgumentCaptor issueChangeNotificationCaptor = ArgumentCaptor.forClass(IssueChangeNotification.class); verify(notificationManager).scheduleForSending(issueChangeNotificationCaptor.capture()); assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("key")).isEqualTo(issueDto.getKey()); assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("componentName")).isEqualTo(file.longName()); @@ -257,6 +258,35 @@ public class BulkChangeActionTest { assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectKey")).isEqualTo(project.getDbKey()); assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("ruleName")).isEqualTo(rule.getName()); assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("changeAuthor")).isEqualTo(user.getLogin()); + assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("branch")).isNull(); + } + + @Test + public void send_notification_on_branch() throws Exception { + setUserProjectPermissions(USER); + + String branchName = "feature1"; + ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey(branchName)); + ComponentDto fileOnBranch = db.components().insertComponent(newFileDto(branch)); + IssueDto issueDto = db.issues().insertIssue(newUnresolvedIssue(rule, fileOnBranch, branch).setType(BUG)); + + BulkChangeWsResponse response = call(BulkChangeRequest.builder() + .setIssues(singletonList(issueDto.getKey())) + .setDoTransition("confirm") + .setSendNotifications(true) + .build()); + + checkResponse(response, 1, 1, 0, 0); + + ArgumentCaptor issueChangeNotificationCaptor = ArgumentCaptor.forClass(IssueChangeNotification.class); + verify(notificationManager).scheduleForSending(issueChangeNotificationCaptor.capture()); + assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("key")).isEqualTo(issueDto.getKey()); + assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("componentName")).isEqualTo(fileOnBranch.longName()); + assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectName")).isEqualTo(project.longName()); + assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectKey")).isEqualTo(project.getDbKey()); + assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("ruleName")).isEqualTo(rule.getName()); + assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("changeAuthor")).isEqualTo(user.getLogin()); + assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("branch")).isEqualTo(branchName); } @Test diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest/email_with_issue_on_branch.txt b/server/sonar-server/src/test/resources/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest/email_with_issue_on_branch.txt new file mode 100644 index 00000000000..b9a5c6bee22 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest/email_with_issue_on_branch.txt @@ -0,0 +1,6 @@ +Action +Rule: Avoid Cycles +Message: Has 3 cycles + + +See it in SonarQube: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&issues=ABCDE&open=ABCDE&branch=feature1 diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest/email_with_issue_on_branch.txt b/server/sonar-server/src/test/resources/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest/email_with_issue_on_branch.txt new file mode 100644 index 00000000000..543e42ea417 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest/email_with_issue_on_branch.txt @@ -0,0 +1,8 @@ +Project: Struts + +32 new issues (new debt: 1d3h) + + Severity + Blocker: 0 Critical: 5 Major: 10 Minor: 3 Info: 1 + +See it in SonarQube: http://nemo.sonarsource.org/issues?projectUuids=ABCDE&assignees=lo.gin&branch=feature1&createdAt=2010-05-1 diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest/email_with_issue_on_branch.txt b/server/sonar-server/src/test/resources/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest/email_with_issue_on_branch.txt new file mode 100644 index 00000000000..bc0afd30a33 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest/email_with_issue_on_branch.txt @@ -0,0 +1,8 @@ +Project: Struts + +32 new issues (new debt: 1d3h) + + Severity + Blocker: 0 Critical: 5 Major: 10 Minor: 3 Info: 1 + +See it in SonarQube: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&branch=feature1&createdAt=2010-05-1