import org.sonar.api.utils.log.Loggers;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
import org.sonar.server.computation.analysis.AnalysisMetadataHolder;
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.scm.ScmInfo;
import org.sonar.api.issue.Issue;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
import org.sonar.server.issue.workflow.IssueWorkflow;
import org.sonar.core.util.Uuids;
import org.sonar.server.computation.analysis.AnalysisMetadataHolder;
import org.apache.commons.lang.time.DateUtils;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.FieldDiffs;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
import org.sonar.db.issue.IssueChangeDto;
import org.sonar.server.computation.period.Period;
import org.sonar.api.issue.condition.IsUnResolved;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.api.server.rule.RuleTagFormat;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
import java.util.Collection;
import org.sonar.api.server.ServerSide;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.server.properties.ProjectSettingsFactory;
import com.google.common.collect.Sets;
import org.sonar.api.server.ServerSide;
-import org.sonar.core.issue.IssueUpdater;
import java.util.Collection;
import java.util.Set;
import org.sonar.api.user.User;
import org.sonar.api.user.UserFinder;
import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
@ServerSide
import org.sonar.api.issue.Issue;
import org.sonar.api.server.ServerSide;
import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
@ServerSide
import org.sonar.core.issue.FieldDiffs;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
import static com.google.common.collect.Lists.newArrayList;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.issue.IssueComment;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.DefaultIssueComment;
import org.sonar.core.issue.IssueChangeContext;
import org.sonar.api.utils.System2;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.db.issue.IssueChangeDto;
import org.sonar.db.DbSession;
import org.sonar.db.DbClient;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.DefaultIssueBuilder;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.issue.workflow.IssueWorkflow;
import org.sonar.server.issue.workflow.Transition;
import org.sonar.db.DbClient;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.issue;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Set;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.time.DateUtils;
+import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.server.rule.RuleTagFormat;
+import org.sonar.api.user.User;
+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 static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+/**
+ * Updates issue fields and chooses if changes must be kept in history.
+ */
+@ServerSide
+public class IssueUpdater {
+
+ public static final String UNUSED = "";
+ public static final String SEVERITY = "severity";
+ public static final String ASSIGNEE = "assignee";
+ public static final String RESOLUTION = "resolution";
+ public static final String STATUS = "status";
+ public static final String AUTHOR = "author";
+ public static final String ACTION_PLAN = "actionPlan";
+ public static final String TECHNICAL_DEBT = "technicalDebt";
+ public static final String TAGS = "tags";
+
+ private static final Joiner CHANGELOG_TAG_JOINER = Joiner.on(" ").skipNulls();
+
+ public boolean setSeverity(DefaultIssue issue, String severity, IssueChangeContext context) {
+ if (issue.manualSeverity()) {
+ throw new IllegalStateException("Severity can't be changed");
+ }
+ if (!Objects.equal(severity, issue.severity())) {
+ issue.setFieldChange(context, SEVERITY, issue.severity(), severity);
+ issue.setSeverity(severity);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setPastSeverity(DefaultIssue issue, @Nullable String previousSeverity, IssueChangeContext context) {
+ String currentSeverity = issue.severity();
+ issue.setSeverity(previousSeverity);
+ return setSeverity(issue, currentSeverity, context);
+ }
+
+ public boolean setManualSeverity(DefaultIssue issue, String severity, IssueChangeContext context) {
+ if (!issue.manualSeverity() || !Objects.equal(severity, issue.severity())) {
+ issue.setFieldChange(context, SEVERITY, issue.severity(), severity);
+ issue.setSeverity(severity);
+ issue.setManualSeverity(true);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ issue.setSendNotifications(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean assign(DefaultIssue issue, @Nullable User user, IssueChangeContext context) {
+ String sanitizedAssignee = null;
+ if (user != null) {
+ sanitizedAssignee = StringUtils.defaultIfBlank(user.login(), null);
+ }
+ if (!Objects.equal(sanitizedAssignee, issue.assignee())) {
+ String newAssigneeName = user != null ? user.name() : null;
+ issue.setFieldChange(context, ASSIGNEE, UNUSED, newAssigneeName);
+ issue.setAssignee(sanitizedAssignee);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ issue.setSendNotifications(true);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Used to set the assignee when it was null
+ */
+ public boolean setNewAssignee(DefaultIssue issue, @Nullable String newAssignee, IssueChangeContext context) {
+ if (newAssignee == null) {
+ return false;
+ }
+ checkState(issue.assignee() == null, "It's not possible to update the assignee with this method, please use assign()");
+ issue.setFieldChange(context, ASSIGNEE, UNUSED, newAssignee);
+ issue.setAssignee(newAssignee);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ issue.setSendNotifications(true);
+ return true;
+ }
+
+ public boolean setLine(DefaultIssue issue, @Nullable Integer line) {
+ if (!Objects.equal(line, issue.line())) {
+ issue.setLine(line);
+ issue.setChanged(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setPastLine(DefaultIssue issue, @Nullable Integer previousLine) {
+ Integer currentLine = issue.line();
+ issue.setLine(previousLine);
+ return setLine(issue, currentLine);
+ }
+
+ public boolean setLocations(DefaultIssue issue, @Nullable Object locations) {
+ if (!Objects.equal(locations, issue.getLocations())) {
+ issue.setLocations(locations);
+ issue.setChanged(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setPastLocations(DefaultIssue issue, @Nullable Object previousLocations) {
+ Object currentLocations = issue.getLocations();
+ issue.setLocations(previousLocations);
+ return setLocations(issue, currentLocations);
+
+ }
+
+ public boolean setResolution(DefaultIssue issue, @Nullable String resolution, IssueChangeContext context) {
+ if (!Objects.equal(resolution, issue.resolution())) {
+ issue.setFieldChange(context, RESOLUTION, issue.resolution(), resolution);
+ issue.setResolution(resolution);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ issue.setSendNotifications(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setStatus(DefaultIssue issue, String status, IssueChangeContext context) {
+ if (!Objects.equal(status, issue.status())) {
+ issue.setFieldChange(context, STATUS, issue.status(), status);
+ issue.setStatus(status);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ issue.setSendNotifications(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setAuthorLogin(DefaultIssue issue, @Nullable String authorLogin, IssueChangeContext context) {
+ if (!Objects.equal(authorLogin, issue.authorLogin())) {
+ issue.setFieldChange(context, AUTHOR, issue.authorLogin(), authorLogin);
+ issue.setAuthorLogin(authorLogin);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ // do not send notifications to prevent spam when installing the developer cockpit plugin
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Used to set the author when it was null
+ */
+ public boolean setNewAuthor(DefaultIssue issue, @Nullable String newAuthorLogin, IssueChangeContext context) {
+ if (isNullOrEmpty(newAuthorLogin)) {
+ return false;
+ }
+ checkState(issue.authorLogin() == null, "It's not possible to update the author with this method, please use setAuthorLogin()");
+ issue.setFieldChange(context, AUTHOR, null, newAuthorLogin);
+ issue.setAuthorLogin(newAuthorLogin);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ // do not send notifications to prevent spam when installing the developer cockpit plugin
+ return true;
+ }
+
+ public boolean setMessage(DefaultIssue issue, @Nullable String s, IssueChangeContext context) {
+ if (!Objects.equal(s, issue.message())) {
+ issue.setMessage(s);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setPastMessage(DefaultIssue issue, @Nullable String previousMessage, IssueChangeContext context) {
+ String currentMessage = issue.message();
+ issue.setMessage(previousMessage);
+ return setMessage(issue, currentMessage, context);
+ }
+
+ public void addComment(DefaultIssue issue, String text, IssueChangeContext context) {
+ issue.addComment(DefaultIssueComment.create(issue.key(), context.login(), text));
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ }
+
+ public void setCloseDate(DefaultIssue issue, @Nullable Date d, IssueChangeContext context) {
+ Date dateWithoutMilliseconds = d == null ? null : DateUtils.truncate(d, Calendar.SECOND);
+ if (!Objects.equal(dateWithoutMilliseconds, issue.closeDate())) {
+ issue.setCloseDate(d);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ }
+ }
+
+ public boolean setEffortToFix(DefaultIssue issue, @Nullable Double d, IssueChangeContext context) {
+ if (!Objects.equal(d, issue.effortToFix())) {
+ issue.setEffortToFix(d);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ // Do not send notifications to prevent spam when installing the SQALE plugin,
+ // and do not complete the changelog (for the moment)
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setPastEffortToFix(DefaultIssue issue, @Nullable Double previousEffort, IssueChangeContext context) {
+ Double currentEffort = issue.effortToFix();
+ issue.setEffortToFix(previousEffort);
+ return setEffortToFix(issue, currentEffort, context);
+ }
+
+ public boolean setTechnicalDebt(DefaultIssue issue, @Nullable Duration value, IssueChangeContext context) {
+ Duration oldValue = issue.debt();
+ if (!Objects.equal(value, oldValue)) {
+ issue.setDebt(value != null ? value : null);
+ issue.setFieldChange(context, TECHNICAL_DEBT, oldValue != null ? oldValue.toMinutes() : null, value != null ? value.toMinutes() : null);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setPastTechnicalDebt(DefaultIssue issue, @Nullable Duration previousTechnicalDebt, IssueChangeContext context) {
+ Duration currentTechnicalDebt = issue.debt();
+ issue.setDebt(previousTechnicalDebt);
+ return setTechnicalDebt(issue, currentTechnicalDebt, context);
+ }
+
+ public boolean setAttribute(DefaultIssue issue, String key, @Nullable String value, IssueChangeContext context) {
+ String oldValue = issue.attribute(key);
+ if (!Objects.equal(oldValue, value)) {
+ issue.setFieldChange(context, key, oldValue, value);
+ issue.setAttribute(key, value);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean plan(DefaultIssue issue, @Nullable ActionPlan actionPlan, IssueChangeContext context) {
+ String sanitizedActionPlanKey = null;
+ if (actionPlan != null) {
+ sanitizedActionPlanKey = StringUtils.defaultIfBlank(actionPlan.key(), null);
+ }
+ if (!Objects.equal(sanitizedActionPlanKey, issue.actionPlanKey())) {
+ String newActionPlanName = actionPlan != null ? actionPlan.name() : null;
+ issue.setFieldChange(context, ACTION_PLAN, UNUSED, newActionPlanName);
+ issue.setActionPlanKey(sanitizedActionPlanKey);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ issue.setSendNotifications(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setProject(DefaultIssue issue, String projectKey, IssueChangeContext context) {
+ if (!Objects.equal(projectKey, issue.projectKey())) {
+ issue.setProjectKey(projectKey);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setPastProject(DefaultIssue issue, String previousKey, IssueChangeContext context) {
+ String currentProjectKey = issue.projectKey();
+ issue.setProjectKey(previousKey);
+ return setProject(issue, currentProjectKey, context);
+ }
+
+ public boolean setTags(DefaultIssue issue, Collection<String> tags, IssueChangeContext context) {
+ Set<String> newTags = Sets.newHashSet(Collections2.transform(
+ Collections2.filter(tags, new Predicate<String>() {
+ @Override
+ public boolean apply(@Nullable String tag) {
+ return tag != null && !tag.isEmpty();
+ }
+ }), new Function<String, String>() {
+ @Override
+ public String apply(String tag) {
+ String lowerCaseTag = tag.toLowerCase();
+ RuleTagFormat.validate(lowerCaseTag);
+ return lowerCaseTag;
+ }
+ }));
+
+ Set<String> oldTags = Sets.newHashSet(issue.tags());
+
+ if (!oldTags.equals(newTags)) {
+ issue.setFieldChange(context, TAGS,
+ oldTags.isEmpty() ? null : CHANGELOG_TAG_JOINER.join(oldTags),
+ newTags.isEmpty() ? null : CHANGELOG_TAG_JOINER.join(newTags));
+ issue.setTags(newTags);
+ issue.setUpdateDate(context.date());
+ issue.setChanged(true);
+ issue.setSendNotifications(true);
+ return true;
+ }
+ return false;
+ }
+
+}
import org.sonar.api.issue.condition.IsUnResolved;
import org.sonar.api.server.ServerSide;
import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.issue.actionplan.ActionPlanService;
import org.sonar.server.user.UserSession;
import com.google.common.collect.Sets;
import org.sonar.api.server.ServerSide;
-import org.sonar.core.issue.IssueUpdater;
import java.util.Collection;
import java.util.Set;
import org.sonar.api.server.ServerSide;
import org.sonar.api.web.UserRole;
import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
@ServerSide
import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ResourceDao;
import org.sonar.api.user.User;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
@ServerSide
public class FunctionExecutor {
import org.sonar.api.web.UserRole;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
@ServerSide
public class IssueWorkflow implements Startable {
import org.sonar.api.rules.XMLRuleParser;
import org.sonar.api.server.rule.RulesDefinitionXmlLoader;
import org.sonar.core.component.DefaultResourceTypes;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
import org.sonar.server.issue.workflow.FunctionExecutor;
import org.sonar.server.issue.workflow.IssueWorkflow;
import org.sonar.core.timemachine.Periods;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
import org.sonar.server.computation.analysis.AnalysisMetadataHolderRule;
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.scm.Changeset;
import org.sonar.api.utils.Duration;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
import org.sonar.server.issue.workflow.IssueWorkflow;
import org.sonar.db.protobuf.DbCommons;
import org.sonar.db.protobuf.DbIssues;
import org.sonar.api.issue.condition.Condition;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.mockito.Matchers;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
import java.util.Collection;
import java.util.Map;
import org.sonar.core.issue.IssueChangeContext;
import org.sonar.api.user.User;
import org.sonar.api.user.UserFinder;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.core.user.DefaultUser;
import org.sonar.server.user.ThreadLocalUserSession;
import org.sonar.api.issue.Issue;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.tester.AnonymousMockUserSession;
import static com.google.common.collect.Maps.newHashMap;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.DefaultIssueComment;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.issue;
+
+import java.util.Date;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.user.User;
+import org.sonar.api.utils.Duration;
+import org.sonar.core.issue.DefaultActionPlan;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.FieldDiffs;
+import org.sonar.core.issue.IssueChangeContext;
+import org.sonar.core.user.DefaultUser;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.issue.IssueUpdater.ACTION_PLAN;
+import static org.sonar.server.issue.IssueUpdater.ASSIGNEE;
+import static org.sonar.server.issue.IssueUpdater.RESOLUTION;
+import static org.sonar.server.issue.IssueUpdater.SEVERITY;
+import static org.sonar.server.issue.IssueUpdater.STATUS;
+import static org.sonar.server.issue.IssueUpdater.TECHNICAL_DEBT;
+import static org.sonar.server.issue.IssueUpdater.UNUSED;
+
+public class IssueUpdaterTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ DefaultIssue issue = new DefaultIssue();
+ IssueChangeContext context = IssueChangeContext.createUser(new Date(), "emmerik");
+
+ IssueUpdater updater;
+
+ @Before
+ public void setUp() {
+ updater = new IssueUpdater();
+ }
+
+ @Test
+ public void assign() {
+ User user = new DefaultUser().setLogin("emmerik").setName("Emmerik");
+
+ boolean updated = updater.assign(issue, user, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.assignee()).isEqualTo("emmerik");
+ assertThat(issue.mustSendNotifications()).isTrue();
+ FieldDiffs.Diff diff = issue.currentChange().get(ASSIGNEE);
+ assertThat(diff.oldValue()).isEqualTo(UNUSED);
+ assertThat(diff.newValue()).isEqualTo("Emmerik");
+ }
+
+ @Test
+ public void unassign() {
+ issue.setAssignee("morgan");
+ boolean updated = updater.assign(issue, null, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.assignee()).isNull();
+ assertThat(issue.mustSendNotifications()).isTrue();
+ FieldDiffs.Diff diff = issue.currentChange().get(ASSIGNEE);
+ assertThat(diff.oldValue()).isEqualTo(UNUSED);
+ assertThat(diff.newValue()).isNull();
+ }
+
+ @Test
+ public void change_assignee() {
+ User user = new DefaultUser().setLogin("emmerik").setName("Emmerik");
+
+ issue.setAssignee("morgan");
+ boolean updated = updater.assign(issue, user, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.assignee()).isEqualTo("emmerik");
+ assertThat(issue.mustSendNotifications()).isTrue();
+ FieldDiffs.Diff diff = issue.currentChange().get(ASSIGNEE);
+ assertThat(diff.oldValue()).isEqualTo(UNUSED);
+ assertThat(diff.newValue()).isEqualTo("Emmerik");
+ }
+
+ @Test
+ public void not_change_assignee() {
+ User user = new DefaultUser().setLogin("morgan").setName("Morgan");
+
+ issue.setAssignee("morgan");
+ boolean updated = updater.assign(issue, user, context);
+ assertThat(updated).isFalse();
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_new_assignee() throws Exception {
+ boolean updated = updater.setNewAssignee(issue, "simon", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.assignee()).isEqualTo("simon");
+ assertThat(issue.mustSendNotifications()).isTrue();
+ FieldDiffs.Diff diff = issue.currentChange().get(ASSIGNEE);
+ assertThat(diff.oldValue()).isEqualTo(UNUSED);
+ assertThat(diff.newValue()).isEqualTo("simon");
+ }
+
+ @Test
+ public void not_set_new_assignee_if_new_assignee_is_null() throws Exception {
+ boolean updated = updater.setNewAssignee(issue, null, context);
+ assertThat(updated).isFalse();
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void fail_with_ISE_when_setting_new_assignee_on_already_assigned_issue() throws Exception {
+ issue.setAssignee("simon");
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("It's not possible to update the assignee with this method, please use assign()");
+ updater.setNewAssignee(issue, "julien", context);
+ }
+
+ @Test
+ public void set_severity() {
+ boolean updated = updater.setSeverity(issue, "BLOCKER", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.severity()).isEqualTo("BLOCKER");
+ assertThat(issue.manualSeverity()).isFalse();
+ assertThat(issue.mustSendNotifications()).isFalse();
+
+ FieldDiffs.Diff diff = issue.currentChange().get(SEVERITY);
+ assertThat(diff.oldValue()).isNull();
+ assertThat(diff.newValue()).isEqualTo("BLOCKER");
+ }
+
+ @Test
+ public void set_past_severity() {
+ issue.setSeverity("BLOCKER");
+ boolean updated = updater.setPastSeverity(issue, "INFO", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.severity()).isEqualTo("BLOCKER");
+ assertThat(issue.mustSendNotifications()).isFalse();
+
+ FieldDiffs.Diff diff = issue.currentChange().get(SEVERITY);
+ assertThat(diff.oldValue()).isEqualTo("INFO");
+ assertThat(diff.newValue()).isEqualTo("BLOCKER");
+ }
+
+ @Test
+ public void update_severity() {
+ issue.setSeverity("BLOCKER");
+ boolean updated = updater.setSeverity(issue, "MINOR", context);
+
+ assertThat(updated).isTrue();
+ assertThat(issue.severity()).isEqualTo("MINOR");
+ assertThat(issue.mustSendNotifications()).isFalse();
+ FieldDiffs.Diff diff = issue.currentChange().get(SEVERITY);
+ assertThat(diff.oldValue()).isEqualTo("BLOCKER");
+ assertThat(diff.newValue()).isEqualTo("MINOR");
+ }
+
+ @Test
+ public void not_change_severity() {
+ issue.setSeverity("MINOR");
+ boolean updated = updater.setSeverity(issue, "MINOR", context);
+ assertThat(updated).isFalse();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ assertThat(issue.currentChange()).isNull();
+ }
+
+ @Test
+ public void not_revert_manual_severity() {
+ issue.setSeverity("MINOR").setManualSeverity(true);
+ try {
+ updater.setSeverity(issue, "MAJOR", context);
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("Severity can't be changed");
+ }
+ }
+
+ @Test
+ public void set_manual_severity() {
+ issue.setSeverity("BLOCKER");
+ boolean updated = updater.setManualSeverity(issue, "MINOR", context);
+
+ assertThat(updated).isTrue();
+ assertThat(issue.severity()).isEqualTo("MINOR");
+ assertThat(issue.manualSeverity()).isTrue();
+ assertThat(issue.mustSendNotifications()).isTrue();
+ FieldDiffs.Diff diff = issue.currentChange().get(SEVERITY);
+ assertThat(diff.oldValue()).isEqualTo("BLOCKER");
+ assertThat(diff.newValue()).isEqualTo("MINOR");
+ }
+
+ @Test
+ public void not_change_manual_severity() {
+ issue.setSeverity("MINOR").setManualSeverity(true);
+ boolean updated = updater.setManualSeverity(issue, "MINOR", context);
+ assertThat(updated).isFalse();
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_line() {
+ boolean updated = updater.setLine(issue, 123);
+ assertThat(updated).isTrue();
+ assertThat(issue.line()).isEqualTo(123);
+ assertThat(issue.mustSendNotifications()).isFalse();
+ // do not save change
+ assertThat(issue.currentChange()).isNull();
+ }
+
+ @Test
+ public void set_past_line() {
+ issue.setLine(42);
+ boolean updated = updater.setPastLine(issue, 123);
+ assertThat(updated).isTrue();
+ assertThat(issue.line()).isEqualTo(42);
+ assertThat(issue.mustSendNotifications()).isFalse();
+
+ // do not save change
+ assertThat(issue.currentChange()).isNull();
+ }
+
+ @Test
+ public void line_is_not_changed() {
+ issue.setLine(123);
+ boolean updated = updater.setLine(issue, 123);
+ assertThat(updated).isFalse();
+ assertThat(issue.line()).isEqualTo(123);
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void change_locations() {
+ issue.setLocations("[1-3]");
+ boolean updated = updater.setLocations(issue, "[1-4]");
+ assertThat(updated).isTrue();
+ assertThat(issue.getLocations()).isEqualTo("[1-4]");
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void do_not_change_locations() {
+ issue.setLocations("[1-3]");
+ boolean updated = updater.setLocations(issue, "[1-3]");
+ assertThat(updated).isFalse();
+ assertThat(issue.getLocations()).isEqualTo("[1-3]");
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_locations_for_the_first_time() {
+ issue.setLocations(null);
+ boolean updated = updater.setLocations(issue, "[1-4]");
+ assertThat(updated).isTrue();
+ assertThat(issue.getLocations()).isEqualTo("[1-4]");
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_resolution() {
+ boolean updated = updater.setResolution(issue, "OPEN", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.resolution()).isEqualTo("OPEN");
+
+ FieldDiffs.Diff diff = issue.currentChange().get(RESOLUTION);
+ assertThat(diff.oldValue()).isNull();
+ assertThat(diff.newValue()).isEqualTo("OPEN");
+ assertThat(issue.mustSendNotifications()).isTrue();
+ }
+
+ @Test
+ public void not_change_resolution() {
+ issue.setResolution("FIXED");
+ boolean updated = updater.setResolution(issue, "FIXED", context);
+ assertThat(updated).isFalse();
+ assertThat(issue.resolution()).isEqualTo("FIXED");
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_status() {
+ boolean updated = updater.setStatus(issue, "OPEN", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.status()).isEqualTo("OPEN");
+
+ FieldDiffs.Diff diff = issue.currentChange().get(STATUS);
+ assertThat(diff.oldValue()).isNull();
+ assertThat(diff.newValue()).isEqualTo("OPEN");
+ assertThat(issue.mustSendNotifications()).isTrue();
+ }
+
+ @Test
+ public void not_change_status() {
+ issue.setStatus("CLOSED");
+ boolean updated = updater.setStatus(issue, "CLOSED", context);
+ assertThat(updated).isFalse();
+ assertThat(issue.status()).isEqualTo("CLOSED");
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_new_attribute_value() {
+ boolean updated = updater.setAttribute(issue, "JIRA", "FOO-123", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.attribute("JIRA")).isEqualTo("FOO-123");
+ assertThat(issue.currentChange().diffs()).hasSize(1);
+ assertThat(issue.currentChange().get("JIRA").oldValue()).isNull();
+ assertThat(issue.currentChange().get("JIRA").newValue()).isEqualTo("FOO-123");
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void unset_attribute() {
+ issue.setAttribute("JIRA", "FOO-123");
+ boolean updated = updater.setAttribute(issue, "JIRA", null, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.attribute("JIRA")).isNull();
+ assertThat(issue.currentChange().diffs()).hasSize(1);
+ assertThat(issue.currentChange().get("JIRA").oldValue()).isEqualTo("FOO-123");
+ assertThat(issue.currentChange().get("JIRA").newValue()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void not_update_attribute() {
+ issue.setAttribute("JIRA", "FOO-123");
+ boolean updated = updater.setAttribute(issue, "JIRA", "FOO-123", context);
+ assertThat(updated).isFalse();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void plan_with_no_existing_plan() {
+ ActionPlan newActionPlan = DefaultActionPlan.create("newName");
+
+ boolean updated = updater.plan(issue, newActionPlan, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.actionPlanKey()).isEqualTo(newActionPlan.key());
+
+ FieldDiffs.Diff diff = issue.currentChange().get(ACTION_PLAN);
+ assertThat(diff.oldValue()).isEqualTo(UNUSED);
+ assertThat(diff.newValue()).isEqualTo("newName");
+ assertThat(issue.mustSendNotifications()).isTrue();
+ }
+
+ @Test
+ public void plan_with_existing_plan() {
+ issue.setActionPlanKey("formerActionPlan");
+
+ ActionPlan newActionPlan = DefaultActionPlan.create("newName").setKey("newKey");
+
+ boolean updated = updater.plan(issue, newActionPlan, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.actionPlanKey()).isEqualTo(newActionPlan.key());
+
+ FieldDiffs.Diff diff = issue.currentChange().get(ACTION_PLAN);
+ assertThat(diff.oldValue()).isEqualTo(UNUSED);
+ assertThat(diff.newValue()).isEqualTo("newName");
+ assertThat(issue.mustSendNotifications()).isTrue();
+ }
+
+ @Test
+ public void unplan() {
+ issue.setActionPlanKey("formerActionPlan");
+
+ boolean updated = updater.plan(issue, null, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.actionPlanKey()).isNull();
+
+ FieldDiffs.Diff diff = issue.currentChange().get(ACTION_PLAN);
+ assertThat(diff.oldValue()).isEqualTo(UNUSED);
+ assertThat(diff.newValue()).isNull();
+ assertThat(issue.mustSendNotifications()).isTrue();
+ }
+
+ @Test
+ public void not_plan_again() {
+ issue.setActionPlanKey("existingActionPlan");
+
+ ActionPlan newActionPlan = DefaultActionPlan.create("existingActionPlan").setKey("existingActionPlan");
+
+ boolean updated = updater.plan(issue, newActionPlan, context);
+ assertThat(updated).isFalse();
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_effort_to_fix() {
+ boolean updated = updater.setEffortToFix(issue, 3.14, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.isChanged()).isTrue();
+ assertThat(issue.effortToFix()).isEqualTo(3.14);
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void not_set_effort_to_fix_if_unchanged() {
+ issue.setEffortToFix(3.14);
+ boolean updated = updater.setEffortToFix(issue, 3.14, context);
+ assertThat(updated).isFalse();
+ assertThat(issue.isChanged()).isFalse();
+ assertThat(issue.effortToFix()).isEqualTo(3.14);
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_past_effort() {
+ issue.setEffortToFix(3.14);
+ boolean updated = updater.setPastEffortToFix(issue, 1.0, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.effortToFix()).isEqualTo(3.14);
+
+ // do not save change
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_past_technical_debt() {
+ Duration newDebt = Duration.create(15 * 8 * 60);
+ Duration previousDebt = Duration.create(10 * 8 * 60);
+ issue.setDebt(newDebt);
+ boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.debt()).isEqualTo(newDebt);
+ assertThat(issue.mustSendNotifications()).isFalse();
+
+ FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
+ assertThat(diff.oldValue()).isEqualTo(10L * 8 * 60);
+ assertThat(diff.newValue()).isEqualTo(15L * 8 * 60);
+ }
+
+ @Test
+ public void set_past_technical_debt_without_previous_value() {
+ Duration newDebt = Duration.create(15 * 8 * 60);
+ issue.setDebt(newDebt);
+ boolean updated = updater.setPastTechnicalDebt(issue, null, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.debt()).isEqualTo(newDebt);
+ assertThat(issue.mustSendNotifications()).isFalse();
+
+ FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
+ assertThat(diff.oldValue()).isNull();
+ assertThat(diff.newValue()).isEqualTo(15L * 8 * 60);
+ }
+
+ @Test
+ public void set_past_technical_debt_with_null_new_value() {
+ issue.setDebt(null);
+ Duration previousDebt = Duration.create(10 * 8 * 60);
+ boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context);
+ assertThat(updated).isTrue();
+ assertThat(issue.debt()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+
+ FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
+ assertThat(diff.oldValue()).isEqualTo(10L * 8 * 60);
+ assertThat(diff.newValue()).isNull();
+ }
+
+ @Test
+ public void set_message() {
+ boolean updated = updater.setMessage(issue, "the message", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.isChanged()).isTrue();
+ assertThat(issue.message()).isEqualTo("the message");
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_past_message() {
+ issue.setMessage("new message");
+ boolean updated = updater.setPastMessage(issue, "past message", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.message()).isEqualTo("new message");
+
+ // do not save change
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_author() {
+ boolean updated = updater.setAuthorLogin(issue, "eric", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.authorLogin()).isEqualTo("eric");
+
+ FieldDiffs.Diff diff = issue.currentChange().get("author");
+ assertThat(diff.oldValue()).isNull();
+ assertThat(diff.newValue()).isEqualTo("eric");
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_new_author() throws Exception {
+ boolean updated = updater.setNewAuthor(issue, "simon", context);
+ assertThat(updated).isTrue();
+
+ FieldDiffs.Diff diff = issue.currentChange().get("author");
+ assertThat(diff.oldValue()).isNull();
+ assertThat(diff.newValue()).isEqualTo("simon");
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void not_set_new_author_if_new_author_is_null() throws Exception {
+ boolean updated = updater.setNewAuthor(issue, null, context);
+ assertThat(updated).isFalse();
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void fail_with_ISE_when_setting_new_author_on_issue() throws Exception {
+ issue.setAuthorLogin("simon");
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("It's not possible to update the author with this method, please use setAuthorLogin()");
+ updater.setNewAuthor(issue, "julien", context);
+ }
+
+ @Test
+ public void set_project() {
+ boolean updated = updater.setProject(issue, "sample", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.projectKey()).isEqualTo("sample");
+
+ // do not save change
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void set_past_project() {
+ issue.setProjectKey("new project key");
+ boolean updated = updater.setPastProject(issue, "past project key", context);
+ assertThat(updated).isTrue();
+ assertThat(issue.projectKey()).isEqualTo("new project key");
+
+ // do not save change
+ assertThat(issue.currentChange()).isNull();
+ assertThat(issue.mustSendNotifications()).isFalse();
+ }
+
+ @Test
+ public void not_set_past_project_if_no_change() {
+ issue.setProjectKey("key");
+ boolean updated = updater.setPastProject(issue, "key", context);
+ assertThat(updated).isFalse();
+ assertThat(issue.projectKey()).isEqualTo("key");
+ }
+
+}
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
import org.sonar.core.issue.DefaultActionPlan;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.issue.actionplan.ActionPlanService;
import org.sonar.server.user.ThreadLocalUserSession;
import org.mockito.Matchers;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
import java.util.Collection;
import java.util.Map;
import org.sonar.api.web.UserRole;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.tester.AnonymousMockUserSession;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.UserSession;
import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ResourceDao;
import org.sonar.api.rule.RuleKey;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.issue.IssueUpdater;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.core.issue;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Sets;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Set;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.time.DateUtils;
-import org.sonar.api.issue.ActionPlan;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.server.rule.RuleTagFormat;
-import org.sonar.api.user.User;
-import org.sonar.api.utils.Duration;
-
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Strings.isNullOrEmpty;
-
-/**
- * Updates issue fields and chooses if changes must be kept in history.
- */
-@ServerSide
-public class IssueUpdater {
-
- public static final String UNUSED = "";
- public static final String SEVERITY = "severity";
- public static final String ASSIGNEE = "assignee";
- public static final String RESOLUTION = "resolution";
- public static final String STATUS = "status";
- public static final String AUTHOR = "author";
- public static final String ACTION_PLAN = "actionPlan";
- public static final String TECHNICAL_DEBT = "technicalDebt";
- public static final String TAGS = "tags";
-
- private static final Joiner CHANGELOG_TAG_JOINER = Joiner.on(" ").skipNulls();
-
- public boolean setSeverity(DefaultIssue issue, String severity, IssueChangeContext context) {
- if (issue.manualSeverity()) {
- throw new IllegalStateException("Severity can't be changed");
- }
- if (!Objects.equal(severity, issue.severity())) {
- issue.setFieldChange(context, SEVERITY, issue.severity(), severity);
- issue.setSeverity(severity);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- return true;
- }
- return false;
- }
-
- public boolean setPastSeverity(DefaultIssue issue, @Nullable String previousSeverity, IssueChangeContext context) {
- String currentSeverity = issue.severity();
- issue.setSeverity(previousSeverity);
- return setSeverity(issue, currentSeverity, context);
- }
-
- public boolean setManualSeverity(DefaultIssue issue, String severity, IssueChangeContext context) {
- if (!issue.manualSeverity() || !Objects.equal(severity, issue.severity())) {
- issue.setFieldChange(context, SEVERITY, issue.severity(), severity);
- issue.setSeverity(severity);
- issue.setManualSeverity(true);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- issue.setSendNotifications(true);
- return true;
- }
- return false;
- }
-
- public boolean assign(DefaultIssue issue, @Nullable User user, IssueChangeContext context) {
- String sanitizedAssignee = null;
- if (user != null) {
- sanitizedAssignee = StringUtils.defaultIfBlank(user.login(), null);
- }
- if (!Objects.equal(sanitizedAssignee, issue.assignee())) {
- String newAssigneeName = user != null ? user.name() : null;
- issue.setFieldChange(context, ASSIGNEE, UNUSED, newAssigneeName);
- issue.setAssignee(sanitizedAssignee);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- issue.setSendNotifications(true);
- return true;
- }
- return false;
- }
-
- /**
- * Used to set the assignee when it was null
- */
- public boolean setNewAssignee(DefaultIssue issue, @Nullable String newAssignee, IssueChangeContext context) {
- if (newAssignee == null) {
- return false;
- }
- checkState(issue.assignee() == null, "It's not possible to update the assignee with this method, please use assign()");
- issue.setFieldChange(context, ASSIGNEE, UNUSED, newAssignee);
- issue.setAssignee(newAssignee);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- issue.setSendNotifications(true);
- return true;
- }
-
- public boolean setLine(DefaultIssue issue, @Nullable Integer line) {
- if (!Objects.equal(line, issue.line())) {
- issue.setLine(line);
- issue.setChanged(true);
- return true;
- }
- return false;
- }
-
- public boolean setPastLine(DefaultIssue issue, @Nullable Integer previousLine) {
- Integer currentLine = issue.line();
- issue.setLine(previousLine);
- return setLine(issue, currentLine);
- }
-
- public boolean setLocations(DefaultIssue issue, @Nullable Object locations) {
- if (!Objects.equal(locations, issue.getLocations())) {
- issue.setLocations(locations);
- issue.setChanged(true);
- return true;
- }
- return false;
- }
-
- public boolean setPastLocations(DefaultIssue issue, @Nullable Object previousLocations) {
- Object currentLocations = issue.getLocations();
- issue.setLocations(previousLocations);
- return setLocations(issue, currentLocations);
-
- }
-
- public boolean setResolution(DefaultIssue issue, @Nullable String resolution, IssueChangeContext context) {
- if (!Objects.equal(resolution, issue.resolution())) {
- issue.setFieldChange(context, RESOLUTION, issue.resolution(), resolution);
- issue.setResolution(resolution);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- issue.setSendNotifications(true);
- return true;
- }
- return false;
- }
-
- public boolean setStatus(DefaultIssue issue, String status, IssueChangeContext context) {
- if (!Objects.equal(status, issue.status())) {
- issue.setFieldChange(context, STATUS, issue.status(), status);
- issue.setStatus(status);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- issue.setSendNotifications(true);
- return true;
- }
- return false;
- }
-
- public boolean setAuthorLogin(DefaultIssue issue, @Nullable String authorLogin, IssueChangeContext context) {
- if (!Objects.equal(authorLogin, issue.authorLogin())) {
- issue.setFieldChange(context, AUTHOR, issue.authorLogin(), authorLogin);
- issue.setAuthorLogin(authorLogin);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- // do not send notifications to prevent spam when installing the developer cockpit plugin
- return true;
- }
- return false;
- }
-
- /**
- * Used to set the author when it was null
- */
- public boolean setNewAuthor(DefaultIssue issue, @Nullable String newAuthorLogin, IssueChangeContext context) {
- if (isNullOrEmpty(newAuthorLogin)) {
- return false;
- }
- checkState(issue.authorLogin() == null, "It's not possible to update the author with this method, please use setAuthorLogin()");
- issue.setFieldChange(context, AUTHOR, null, newAuthorLogin);
- issue.setAuthorLogin(newAuthorLogin);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- // do not send notifications to prevent spam when installing the developer cockpit plugin
- return true;
- }
-
- public boolean setMessage(DefaultIssue issue, @Nullable String s, IssueChangeContext context) {
- if (!Objects.equal(s, issue.message())) {
- issue.setMessage(s);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- return true;
- }
- return false;
- }
-
- public boolean setPastMessage(DefaultIssue issue, @Nullable String previousMessage, IssueChangeContext context) {
- String currentMessage = issue.message();
- issue.setMessage(previousMessage);
- return setMessage(issue, currentMessage, context);
- }
-
- public void addComment(DefaultIssue issue, String text, IssueChangeContext context) {
- issue.addComment(DefaultIssueComment.create(issue.key(), context.login(), text));
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- }
-
- public void setCloseDate(DefaultIssue issue, @Nullable Date d, IssueChangeContext context) {
- Date dateWithoutMilliseconds = d == null ? null : DateUtils.truncate(d, Calendar.SECOND);
- if (!Objects.equal(dateWithoutMilliseconds, issue.closeDate())) {
- issue.setCloseDate(d);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- }
- }
-
- public boolean setEffortToFix(DefaultIssue issue, @Nullable Double d, IssueChangeContext context) {
- if (!Objects.equal(d, issue.effortToFix())) {
- issue.setEffortToFix(d);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- // Do not send notifications to prevent spam when installing the SQALE plugin,
- // and do not complete the changelog (for the moment)
- return true;
- }
- return false;
- }
-
- public boolean setPastEffortToFix(DefaultIssue issue, @Nullable Double previousEffort, IssueChangeContext context) {
- Double currentEffort = issue.effortToFix();
- issue.setEffortToFix(previousEffort);
- return setEffortToFix(issue, currentEffort, context);
- }
-
- public boolean setTechnicalDebt(DefaultIssue issue, @Nullable Duration value, IssueChangeContext context) {
- Duration oldValue = issue.debt();
- if (!Objects.equal(value, oldValue)) {
- issue.setDebt(value != null ? value : null);
- issue.setFieldChange(context, TECHNICAL_DEBT, oldValue != null ? oldValue.toMinutes() : null, value != null ? value.toMinutes() : null);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- return true;
- }
- return false;
- }
-
- public boolean setPastTechnicalDebt(DefaultIssue issue, @Nullable Duration previousTechnicalDebt, IssueChangeContext context) {
- Duration currentTechnicalDebt = issue.debt();
- issue.setDebt(previousTechnicalDebt);
- return setTechnicalDebt(issue, currentTechnicalDebt, context);
- }
-
- public boolean setAttribute(DefaultIssue issue, String key, @Nullable String value, IssueChangeContext context) {
- String oldValue = issue.attribute(key);
- if (!Objects.equal(oldValue, value)) {
- issue.setFieldChange(context, key, oldValue, value);
- issue.setAttribute(key, value);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- return true;
- }
- return false;
- }
-
- public boolean plan(DefaultIssue issue, @Nullable ActionPlan actionPlan, IssueChangeContext context) {
- String sanitizedActionPlanKey = null;
- if (actionPlan != null) {
- sanitizedActionPlanKey = StringUtils.defaultIfBlank(actionPlan.key(), null);
- }
- if (!Objects.equal(sanitizedActionPlanKey, issue.actionPlanKey())) {
- String newActionPlanName = actionPlan != null ? actionPlan.name() : null;
- issue.setFieldChange(context, ACTION_PLAN, UNUSED, newActionPlanName);
- issue.setActionPlanKey(sanitizedActionPlanKey);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- issue.setSendNotifications(true);
- return true;
- }
- return false;
- }
-
- public boolean setProject(DefaultIssue issue, String projectKey, IssueChangeContext context) {
- if (!Objects.equal(projectKey, issue.projectKey())) {
- issue.setProjectKey(projectKey);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- return true;
- }
- return false;
- }
-
- public boolean setPastProject(DefaultIssue issue, String previousKey, IssueChangeContext context) {
- String currentProjectKey = issue.projectKey();
- issue.setProjectKey(previousKey);
- return setProject(issue, currentProjectKey, context);
- }
-
- public boolean setTags(DefaultIssue issue, Collection<String> tags, IssueChangeContext context) {
- Set<String> newTags = Sets.newHashSet(Collections2.transform(
- Collections2.filter(tags, new Predicate<String>() {
- @Override
- public boolean apply(@Nullable String tag) {
- return tag != null && !tag.isEmpty();
- }
- }), new Function<String, String>() {
- @Override
- public String apply(String tag) {
- String lowerCaseTag = tag.toLowerCase();
- RuleTagFormat.validate(lowerCaseTag);
- return lowerCaseTag;
- }
- }));
-
- Set<String> oldTags = Sets.newHashSet(issue.tags());
-
- if (!oldTags.equals(newTags)) {
- issue.setFieldChange(context, TAGS,
- oldTags.isEmpty() ? null : CHANGELOG_TAG_JOINER.join(oldTags),
- newTags.isEmpty() ? null : CHANGELOG_TAG_JOINER.join(newTags));
- issue.setTags(newTags);
- issue.setUpdateDate(context.date());
- issue.setChanged(true);
- issue.setSendNotifications(true);
- return true;
- }
- return false;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.core.issue;
-
-import java.util.Date;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.issue.ActionPlan;
-import org.sonar.api.user.User;
-import org.sonar.api.utils.Duration;
-import org.sonar.core.user.DefaultUser;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.issue.IssueUpdater.ACTION_PLAN;
-import static org.sonar.core.issue.IssueUpdater.ASSIGNEE;
-import static org.sonar.core.issue.IssueUpdater.RESOLUTION;
-import static org.sonar.core.issue.IssueUpdater.SEVERITY;
-import static org.sonar.core.issue.IssueUpdater.STATUS;
-import static org.sonar.core.issue.IssueUpdater.TECHNICAL_DEBT;
-import static org.sonar.core.issue.IssueUpdater.UNUSED;
-
-public class IssueUpdaterTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- DefaultIssue issue = new DefaultIssue();
- IssueChangeContext context = IssueChangeContext.createUser(new Date(), "emmerik");
-
- IssueUpdater updater;
-
- @Before
- public void setUp() {
- updater = new IssueUpdater();
- }
-
- @Test
- public void assign() {
- User user = new DefaultUser().setLogin("emmerik").setName("Emmerik");
-
- boolean updated = updater.assign(issue, user, context);
- assertThat(updated).isTrue();
- assertThat(issue.assignee()).isEqualTo("emmerik");
- assertThat(issue.mustSendNotifications()).isTrue();
- FieldDiffs.Diff diff = issue.currentChange().get(ASSIGNEE);
- assertThat(diff.oldValue()).isEqualTo(UNUSED);
- assertThat(diff.newValue()).isEqualTo("Emmerik");
- }
-
- @Test
- public void unassign() {
- issue.setAssignee("morgan");
- boolean updated = updater.assign(issue, null, context);
- assertThat(updated).isTrue();
- assertThat(issue.assignee()).isNull();
- assertThat(issue.mustSendNotifications()).isTrue();
- FieldDiffs.Diff diff = issue.currentChange().get(ASSIGNEE);
- assertThat(diff.oldValue()).isEqualTo(UNUSED);
- assertThat(diff.newValue()).isNull();
- }
-
- @Test
- public void change_assignee() {
- User user = new DefaultUser().setLogin("emmerik").setName("Emmerik");
-
- issue.setAssignee("morgan");
- boolean updated = updater.assign(issue, user, context);
- assertThat(updated).isTrue();
- assertThat(issue.assignee()).isEqualTo("emmerik");
- assertThat(issue.mustSendNotifications()).isTrue();
- FieldDiffs.Diff diff = issue.currentChange().get(ASSIGNEE);
- assertThat(diff.oldValue()).isEqualTo(UNUSED);
- assertThat(diff.newValue()).isEqualTo("Emmerik");
- }
-
- @Test
- public void not_change_assignee() {
- User user = new DefaultUser().setLogin("morgan").setName("Morgan");
-
- issue.setAssignee("morgan");
- boolean updated = updater.assign(issue, user, context);
- assertThat(updated).isFalse();
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_new_assignee() throws Exception {
- boolean updated = updater.setNewAssignee(issue, "simon", context);
- assertThat(updated).isTrue();
- assertThat(issue.assignee()).isEqualTo("simon");
- assertThat(issue.mustSendNotifications()).isTrue();
- FieldDiffs.Diff diff = issue.currentChange().get(ASSIGNEE);
- assertThat(diff.oldValue()).isEqualTo(UNUSED);
- assertThat(diff.newValue()).isEqualTo("simon");
- }
-
- @Test
- public void not_set_new_assignee_if_new_assignee_is_null() throws Exception {
- boolean updated = updater.setNewAssignee(issue, null, context);
- assertThat(updated).isFalse();
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void fail_with_ISE_when_setting_new_assignee_on_already_assigned_issue() throws Exception {
- issue.setAssignee("simon");
-
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("It's not possible to update the assignee with this method, please use assign()");
- updater.setNewAssignee(issue, "julien", context);
- }
-
- @Test
- public void set_severity() {
- boolean updated = updater.setSeverity(issue, "BLOCKER", context);
- assertThat(updated).isTrue();
- assertThat(issue.severity()).isEqualTo("BLOCKER");
- assertThat(issue.manualSeverity()).isFalse();
- assertThat(issue.mustSendNotifications()).isFalse();
-
- FieldDiffs.Diff diff = issue.currentChange().get(SEVERITY);
- assertThat(diff.oldValue()).isNull();
- assertThat(diff.newValue()).isEqualTo("BLOCKER");
- }
-
- @Test
- public void set_past_severity() {
- issue.setSeverity("BLOCKER");
- boolean updated = updater.setPastSeverity(issue, "INFO", context);
- assertThat(updated).isTrue();
- assertThat(issue.severity()).isEqualTo("BLOCKER");
- assertThat(issue.mustSendNotifications()).isFalse();
-
- FieldDiffs.Diff diff = issue.currentChange().get(SEVERITY);
- assertThat(diff.oldValue()).isEqualTo("INFO");
- assertThat(diff.newValue()).isEqualTo("BLOCKER");
- }
-
- @Test
- public void update_severity() {
- issue.setSeverity("BLOCKER");
- boolean updated = updater.setSeverity(issue, "MINOR", context);
-
- assertThat(updated).isTrue();
- assertThat(issue.severity()).isEqualTo("MINOR");
- assertThat(issue.mustSendNotifications()).isFalse();
- FieldDiffs.Diff diff = issue.currentChange().get(SEVERITY);
- assertThat(diff.oldValue()).isEqualTo("BLOCKER");
- assertThat(diff.newValue()).isEqualTo("MINOR");
- }
-
- @Test
- public void not_change_severity() {
- issue.setSeverity("MINOR");
- boolean updated = updater.setSeverity(issue, "MINOR", context);
- assertThat(updated).isFalse();
- assertThat(issue.mustSendNotifications()).isFalse();
- assertThat(issue.currentChange()).isNull();
- }
-
- @Test
- public void not_revert_manual_severity() {
- issue.setSeverity("MINOR").setManualSeverity(true);
- try {
- updater.setSeverity(issue, "MAJOR", context);
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("Severity can't be changed");
- }
- }
-
- @Test
- public void set_manual_severity() {
- issue.setSeverity("BLOCKER");
- boolean updated = updater.setManualSeverity(issue, "MINOR", context);
-
- assertThat(updated).isTrue();
- assertThat(issue.severity()).isEqualTo("MINOR");
- assertThat(issue.manualSeverity()).isTrue();
- assertThat(issue.mustSendNotifications()).isTrue();
- FieldDiffs.Diff diff = issue.currentChange().get(SEVERITY);
- assertThat(diff.oldValue()).isEqualTo("BLOCKER");
- assertThat(diff.newValue()).isEqualTo("MINOR");
- }
-
- @Test
- public void not_change_manual_severity() {
- issue.setSeverity("MINOR").setManualSeverity(true);
- boolean updated = updater.setManualSeverity(issue, "MINOR", context);
- assertThat(updated).isFalse();
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_line() {
- boolean updated = updater.setLine(issue, 123);
- assertThat(updated).isTrue();
- assertThat(issue.line()).isEqualTo(123);
- assertThat(issue.mustSendNotifications()).isFalse();
- // do not save change
- assertThat(issue.currentChange()).isNull();
- }
-
- @Test
- public void set_past_line() {
- issue.setLine(42);
- boolean updated = updater.setPastLine(issue, 123);
- assertThat(updated).isTrue();
- assertThat(issue.line()).isEqualTo(42);
- assertThat(issue.mustSendNotifications()).isFalse();
-
- // do not save change
- assertThat(issue.currentChange()).isNull();
- }
-
- @Test
- public void line_is_not_changed() {
- issue.setLine(123);
- boolean updated = updater.setLine(issue, 123);
- assertThat(updated).isFalse();
- assertThat(issue.line()).isEqualTo(123);
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void change_locations() {
- issue.setLocations("[1-3]");
- boolean updated = updater.setLocations(issue, "[1-4]");
- assertThat(updated).isTrue();
- assertThat(issue.getLocations()).isEqualTo("[1-4]");
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void do_not_change_locations() {
- issue.setLocations("[1-3]");
- boolean updated = updater.setLocations(issue, "[1-3]");
- assertThat(updated).isFalse();
- assertThat(issue.getLocations()).isEqualTo("[1-3]");
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_locations_for_the_first_time() {
- issue.setLocations(null);
- boolean updated = updater.setLocations(issue, "[1-4]");
- assertThat(updated).isTrue();
- assertThat(issue.getLocations()).isEqualTo("[1-4]");
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_resolution() {
- boolean updated = updater.setResolution(issue, "OPEN", context);
- assertThat(updated).isTrue();
- assertThat(issue.resolution()).isEqualTo("OPEN");
-
- FieldDiffs.Diff diff = issue.currentChange().get(RESOLUTION);
- assertThat(diff.oldValue()).isNull();
- assertThat(diff.newValue()).isEqualTo("OPEN");
- assertThat(issue.mustSendNotifications()).isTrue();
- }
-
- @Test
- public void not_change_resolution() {
- issue.setResolution("FIXED");
- boolean updated = updater.setResolution(issue, "FIXED", context);
- assertThat(updated).isFalse();
- assertThat(issue.resolution()).isEqualTo("FIXED");
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_status() {
- boolean updated = updater.setStatus(issue, "OPEN", context);
- assertThat(updated).isTrue();
- assertThat(issue.status()).isEqualTo("OPEN");
-
- FieldDiffs.Diff diff = issue.currentChange().get(STATUS);
- assertThat(diff.oldValue()).isNull();
- assertThat(diff.newValue()).isEqualTo("OPEN");
- assertThat(issue.mustSendNotifications()).isTrue();
- }
-
- @Test
- public void not_change_status() {
- issue.setStatus("CLOSED");
- boolean updated = updater.setStatus(issue, "CLOSED", context);
- assertThat(updated).isFalse();
- assertThat(issue.status()).isEqualTo("CLOSED");
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_new_attribute_value() {
- boolean updated = updater.setAttribute(issue, "JIRA", "FOO-123", context);
- assertThat(updated).isTrue();
- assertThat(issue.attribute("JIRA")).isEqualTo("FOO-123");
- assertThat(issue.currentChange().diffs()).hasSize(1);
- assertThat(issue.currentChange().get("JIRA").oldValue()).isNull();
- assertThat(issue.currentChange().get("JIRA").newValue()).isEqualTo("FOO-123");
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void unset_attribute() {
- issue.setAttribute("JIRA", "FOO-123");
- boolean updated = updater.setAttribute(issue, "JIRA", null, context);
- assertThat(updated).isTrue();
- assertThat(issue.attribute("JIRA")).isNull();
- assertThat(issue.currentChange().diffs()).hasSize(1);
- assertThat(issue.currentChange().get("JIRA").oldValue()).isEqualTo("FOO-123");
- assertThat(issue.currentChange().get("JIRA").newValue()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void not_update_attribute() {
- issue.setAttribute("JIRA", "FOO-123");
- boolean updated = updater.setAttribute(issue, "JIRA", "FOO-123", context);
- assertThat(updated).isFalse();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void plan_with_no_existing_plan() {
- ActionPlan newActionPlan = DefaultActionPlan.create("newName");
-
- boolean updated = updater.plan(issue, newActionPlan, context);
- assertThat(updated).isTrue();
- assertThat(issue.actionPlanKey()).isEqualTo(newActionPlan.key());
-
- FieldDiffs.Diff diff = issue.currentChange().get(ACTION_PLAN);
- assertThat(diff.oldValue()).isEqualTo(UNUSED);
- assertThat(diff.newValue()).isEqualTo("newName");
- assertThat(issue.mustSendNotifications()).isTrue();
- }
-
- @Test
- public void plan_with_existing_plan() {
- issue.setActionPlanKey("formerActionPlan");
-
- ActionPlan newActionPlan = DefaultActionPlan.create("newName").setKey("newKey");
-
- boolean updated = updater.plan(issue, newActionPlan, context);
- assertThat(updated).isTrue();
- assertThat(issue.actionPlanKey()).isEqualTo(newActionPlan.key());
-
- FieldDiffs.Diff diff = issue.currentChange().get(ACTION_PLAN);
- assertThat(diff.oldValue()).isEqualTo(UNUSED);
- assertThat(diff.newValue()).isEqualTo("newName");
- assertThat(issue.mustSendNotifications()).isTrue();
- }
-
- @Test
- public void unplan() {
- issue.setActionPlanKey("formerActionPlan");
-
- boolean updated = updater.plan(issue, null, context);
- assertThat(updated).isTrue();
- assertThat(issue.actionPlanKey()).isNull();
-
- FieldDiffs.Diff diff = issue.currentChange().get(ACTION_PLAN);
- assertThat(diff.oldValue()).isEqualTo(UNUSED);
- assertThat(diff.newValue()).isNull();
- assertThat(issue.mustSendNotifications()).isTrue();
- }
-
- @Test
- public void not_plan_again() {
- issue.setActionPlanKey("existingActionPlan");
-
- ActionPlan newActionPlan = DefaultActionPlan.create("existingActionPlan").setKey("existingActionPlan");
-
- boolean updated = updater.plan(issue, newActionPlan, context);
- assertThat(updated).isFalse();
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_effort_to_fix() {
- boolean updated = updater.setEffortToFix(issue, 3.14, context);
- assertThat(updated).isTrue();
- assertThat(issue.isChanged()).isTrue();
- assertThat(issue.effortToFix()).isEqualTo(3.14);
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void not_set_effort_to_fix_if_unchanged() {
- issue.setEffortToFix(3.14);
- boolean updated = updater.setEffortToFix(issue, 3.14, context);
- assertThat(updated).isFalse();
- assertThat(issue.isChanged()).isFalse();
- assertThat(issue.effortToFix()).isEqualTo(3.14);
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_past_effort() {
- issue.setEffortToFix(3.14);
- boolean updated = updater.setPastEffortToFix(issue, 1.0, context);
- assertThat(updated).isTrue();
- assertThat(issue.effortToFix()).isEqualTo(3.14);
-
- // do not save change
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_past_technical_debt() {
- Duration newDebt = Duration.create(15 * 8 * 60);
- Duration previousDebt = Duration.create(10 * 8 * 60);
- issue.setDebt(newDebt);
- boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context);
- assertThat(updated).isTrue();
- assertThat(issue.debt()).isEqualTo(newDebt);
- assertThat(issue.mustSendNotifications()).isFalse();
-
- FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
- assertThat(diff.oldValue()).isEqualTo(10L * 8 * 60);
- assertThat(diff.newValue()).isEqualTo(15L * 8 * 60);
- }
-
- @Test
- public void set_past_technical_debt_without_previous_value() {
- Duration newDebt = Duration.create(15 * 8 * 60);
- issue.setDebt(newDebt);
- boolean updated = updater.setPastTechnicalDebt(issue, null, context);
- assertThat(updated).isTrue();
- assertThat(issue.debt()).isEqualTo(newDebt);
- assertThat(issue.mustSendNotifications()).isFalse();
-
- FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
- assertThat(diff.oldValue()).isNull();
- assertThat(diff.newValue()).isEqualTo(15L * 8 * 60);
- }
-
- @Test
- public void set_past_technical_debt_with_null_new_value() {
- issue.setDebt(null);
- Duration previousDebt = Duration.create(10 * 8 * 60);
- boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context);
- assertThat(updated).isTrue();
- assertThat(issue.debt()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
-
- FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
- assertThat(diff.oldValue()).isEqualTo(10L * 8 * 60);
- assertThat(diff.newValue()).isNull();
- }
-
- @Test
- public void set_message() {
- boolean updated = updater.setMessage(issue, "the message", context);
- assertThat(updated).isTrue();
- assertThat(issue.isChanged()).isTrue();
- assertThat(issue.message()).isEqualTo("the message");
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_past_message() {
- issue.setMessage("new message");
- boolean updated = updater.setPastMessage(issue, "past message", context);
- assertThat(updated).isTrue();
- assertThat(issue.message()).isEqualTo("new message");
-
- // do not save change
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_author() {
- boolean updated = updater.setAuthorLogin(issue, "eric", context);
- assertThat(updated).isTrue();
- assertThat(issue.authorLogin()).isEqualTo("eric");
-
- FieldDiffs.Diff diff = issue.currentChange().get("author");
- assertThat(diff.oldValue()).isNull();
- assertThat(diff.newValue()).isEqualTo("eric");
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_new_author() throws Exception {
- boolean updated = updater.setNewAuthor(issue, "simon", context);
- assertThat(updated).isTrue();
-
- FieldDiffs.Diff diff = issue.currentChange().get("author");
- assertThat(diff.oldValue()).isNull();
- assertThat(diff.newValue()).isEqualTo("simon");
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void not_set_new_author_if_new_author_is_null() throws Exception {
- boolean updated = updater.setNewAuthor(issue, null, context);
- assertThat(updated).isFalse();
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void fail_with_ISE_when_setting_new_author_on_issue() throws Exception {
- issue.setAuthorLogin("simon");
-
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("It's not possible to update the author with this method, please use setAuthorLogin()");
- updater.setNewAuthor(issue, "julien", context);
- }
-
- @Test
- public void set_project() {
- boolean updated = updater.setProject(issue, "sample", context);
- assertThat(updated).isTrue();
- assertThat(issue.projectKey()).isEqualTo("sample");
-
- // do not save change
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void set_past_project() {
- issue.setProjectKey("new project key");
- boolean updated = updater.setPastProject(issue, "past project key", context);
- assertThat(updated).isTrue();
- assertThat(issue.projectKey()).isEqualTo("new project key");
-
- // do not save change
- assertThat(issue.currentChange()).isNull();
- assertThat(issue.mustSendNotifications()).isFalse();
- }
-
- @Test
- public void not_set_past_project_if_no_change() {
- issue.setProjectKey("key");
- boolean updated = updater.setPastProject(issue, "key", context);
- assertThat(updated).isFalse();
- assertThat(issue.projectKey()).isEqualTo("key");
- }
-
-}