Bladeren bron

SONAR-9616 Support notifications on branches (#2413)

tags/6.6-RC1
Janos Gyerik 6 jaren geleden
bovenliggende
commit
0de8f0ee51
19 gewijzigde bestanden met toevoegingen van 213 en 30 verwijderingen
  1. 1
    0
      server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml
  2. 5
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java
  3. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SendIssueNotificationsStep.java
  4. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/issue/IssueUpdater.java
  5. 8
    2
      server/sonar-server/src/main/java/org/sonar/server/issue/notification/AbstractNewIssuesEmailTemplate.java
  6. 5
    4
      server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangeNotification.java
  7. 6
    2
      server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangesEmailTemplate.java
  8. 7
    3
      server/sonar-server/src/main/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplate.java
  9. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java
  10. 31
    1
      server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStepTest.java
  11. 20
    0
      server/sonar-server/src/test/java/org/sonar/server/issue/IssueUpdaterTest.java
  12. 11
    2
      server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangeNotificationTest.java
  13. 19
    2
      server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest.java
  14. 15
    4
      server/sonar-server/src/test/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest.java
  15. 26
    4
      server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest.java
  16. 32
    2
      server/sonar-server/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java
  17. 6
    0
      server/sonar-server/src/test/resources/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest/email_with_issue_on_branch.txt
  18. 8
    0
      server/sonar-server/src/test/resources/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest/email_with_issue_on_branch.txt
  19. 8
    0
      server/sonar-server/src/test/resources/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest/email_with_issue_on_branch.txt

+ 1
- 0
server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml Bestand weergeven

@@ -83,6 +83,7 @@
from projects p
where
p.enabled=${_true}
and p.main_branch_project_uuid is null
and p.kee in
<foreach collection="keys" open="(" close=")" item="key" separator=",">
#{key,jdbcType=VARCHAR}

+ 5
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java Bestand weergeven

@@ -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);
}


+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SendIssueNotificationsStep.java Bestand weergeven

@@ -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);
}


+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/issue/IssueUpdater.java Bestand weergeven

@@ -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;

+ 8
- 2
server/sonar-server/src/main/java/org/sonar/server/issue/notification/AbstractNewIssuesEmailTemplate.java Bestand weergeven

@@ -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)

+ 5
- 4
server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangeNotification.java Bestand weergeven

@@ -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;
}


+ 6
- 2
server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangesEmailTemplate.java Bestand weergeven

@@ -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);
}

+ 7
- 3
server/sonar-server/src/main/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplate.java Bestand weergeven

@@ -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);
}
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java Bestand weergeven

@@ -129,7 +129,7 @@ public abstract class AbstractUserSession implements UserSession {
protected List<ComponentDto> doKeepAuthorizedComponents(String permission, Collection<ComponentDto> 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());
}


+ 31
- 1
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStepTest.java Bestand weergeven

@@ -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<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
private ArgumentCaptor<Notification> 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);
}

}

+ 20
- 0
server/sonar-server/src/test/java/org/sonar/server/issue/IssueUpdaterTest.java Bestand weergeven

@@ -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));

+ 11
- 2
server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangeNotificationTest.java Bestand weergeven

@@ -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

+ 19
- 2
server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest.java Bestand weergeven

@@ -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");

+ 15
- 4
server/sonar-server/src/test/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest.java Bestand weergeven

@@ -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));
}


+ 26
- 4
server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest.java Bestand weergeven

@@ -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+", "");
}
}

+ 32
- 2
server/sonar-server/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java Bestand weergeven

@@ -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<IssueChangeNotification> 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<IssueChangeNotification> 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<IssueChangeNotification> 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

+ 6
- 0
server/sonar-server/src/test/resources/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest/email_with_issue_on_branch.txt Bestand weergeven

@@ -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

+ 8
- 0
server/sonar-server/src/test/resources/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest/email_with_issue_on_branch.txt Bestand weergeven

@@ -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

+ 8
- 0
server/sonar-server/src/test/resources/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest/email_with_issue_on_branch.txt Bestand weergeven

@@ -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

Laden…
Annuleren
Opslaan