]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4310 set updated_at only on changes
authorSimon Brandhof <simon.brandhof@gmail.com>
Mon, 20 May 2013 21:37:48 +0000 (23:37 +0200)
committerSimon Brandhof <simon.brandhof@gmail.com>
Mon, 20 May 2013 21:37:48 +0000 (23:37 +0200)
13 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueHandlers.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java
sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueStorage.java
sonar-core/src/main/java/org/sonar/core/issue/workflow/FunctionExecutor.java
sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueStorageTest.java
sonar-server/src/main/webapp/WEB-INF/app/models/issue.rb

index 36b88fd29c41d001fdfb8cd34de159de69d66d2b..035f0d05958f873c11f3fda3655a533f8b132c09 100644 (file)
@@ -97,7 +97,7 @@ public class IssueHandlers implements BatchExtension {
 
     @Override
     public IssueHandler.Context setAuthorLogin(@Nullable String login) {
-      updater.setAuthorLogin(issue, login);
+      updater.setAuthorLogin(issue, login, changeContext);
       return this;
     }
 
index 0738bd5ca1fc2c85291c69af8ca5d2f4ac3b0022..1a02b7fe8005b2830c4e5f4c370748726e5cbd2f 100644 (file)
@@ -42,16 +42,6 @@ import java.util.*;
 
 public class IssueTracking implements BatchExtension {
 
-  private static final Comparator<LinePair> LINE_PAIR_COMPARATOR = new Comparator<LinePair>() {
-    public int compare(LinePair o1, LinePair o2) {
-      int weightDiff = o2.weight - o1.weight;
-      if (weightDiff != 0) {
-        return weightDiff;
-      } else {
-        return Math.abs(o1.lineA - o1.lineB) - Math.abs(o2.lineA - o2.lineB);
-      }
-    }
-  };
   private final LastSnapshots lastSnapshots;
   private final SonarIndex index;
 
@@ -60,9 +50,6 @@ public class IssueTracking implements BatchExtension {
     this.index = index;
   }
 
-  /**
-   * @return untracked issues
-   */
   public IssueTrackingResult track(Resource resource, Collection<IssueDto> dbIssues, Collection<DefaultIssue> newIssues) {
     IssueTrackingResult result = new IssueTrackingResult();
 
@@ -334,7 +321,7 @@ public class IssueTracking implements BatchExtension {
     return getClass().getSimpleName();
   }
 
-  static class LinePair {
+  private static class LinePair {
     int lineA;
     int lineB;
     int weight;
@@ -346,11 +333,22 @@ public class IssueTracking implements BatchExtension {
     }
   }
 
-  static class HashOccurrence {
+  private static class HashOccurrence {
     int lineA;
     int lineB;
     int countA;
     int countB;
   }
 
+  private static final Comparator<LinePair> LINE_PAIR_COMPARATOR = new Comparator<LinePair>() {
+    public int compare(LinePair o1, LinePair o2) {
+      int weightDiff = o2.weight - o1.weight;
+      if (weightDiff != 0) {
+        return weightDiff;
+      } else {
+        return Math.abs(o1.lineA - o1.lineB) - Math.abs(o2.lineA - o2.lineB);
+      }
+    }
+  };
+
 }
index 0bc6875731fe34b7d98af3cf5234ad7c6e4b73af..08ad1dd65e94d8078cd9cdfa68ae4429a5e0689e 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.plugins.core.issue;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import org.sonar.api.batch.Decorator;
@@ -39,6 +38,7 @@ import org.sonar.api.utils.KeyValueFormat;
 import org.sonar.batch.issue.IssueCache;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.IssueChangeContext;
+import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.db.IssueDto;
 import org.sonar.core.issue.workflow.IssueWorkflow;
 
@@ -53,12 +53,14 @@ public class IssueTrackingDecorator implements Decorator {
   private final IssueFilters filters;
   private final IssueHandlers handlers;
   private final IssueWorkflow workflow;
+  private final IssueUpdater updater;
   private final IssueChangeContext changeContext;
   private final ResourcePerspectives perspectives;
   private final RuleFinder ruleFinder;
 
   public IssueTrackingDecorator(IssueCache issueCache, InitialOpenIssuesStack initialOpenIssues, IssueTracking tracking,
                                 IssueFilters filters, IssueHandlers handlers, IssueWorkflow workflow,
+                                IssueUpdater updater,
                                 Project project, ResourcePerspectives perspectives,
                                 RuleFinder ruleFinder) {
     this.issueCache = issueCache;
@@ -67,6 +69,7 @@ public class IssueTrackingDecorator implements Decorator {
     this.filters = filters;
     this.handlers = handlers;
     this.workflow = workflow;
+    this.updater = updater;
     this.changeContext = IssueChangeContext.createScan(project.getAnalysisDate());
     this.perspectives = perspectives;
     this.ruleFinder = ruleFinder;
@@ -122,12 +125,6 @@ public class IssueTrackingDecorator implements Decorator {
       IssueDto ref = result.matching(issue);
 
       issue.setKey(ref.getKee());
-      if (ref.isManualSeverity()) {
-        issue.setManualSeverity(true);
-        issue.setSeverity(ref.getSeverity());
-      } else if (!Objects.equal(ref.getSeverity(), issue.severity())) {
-        // TODO register diff
-      }
       issue.setResolution(ref.getResolution());
       issue.setStatus(ref.getStatus());
       issue.setNew(false);
@@ -136,16 +133,25 @@ public class IssueTrackingDecorator implements Decorator {
       issue.setAuthorLogin(ref.getAuthorLogin());
       issue.setAssignee(ref.getAssignee());
       if (ref.getAttributes() != null) {
-        //FIXME do not override new attributes
         issue.setAttributes(KeyValueFormat.parse(ref.getAttributes()));
       }
-      issue.setTechnicalCreationDate(ref.getCreatedAt());
-      issue.setTechnicalUpdateDate(ref.getUpdatedAt());
       issue.setCreationDate(ref.getIssueCreationDate());
-      // FIXME issue.setUpdateDate(project.getAnalysisDate());
+
+      // must be done before the change of severity
+      issue.setUpdateDate(ref.getIssueUpdateDate());
 
       // should be null
       issue.setCloseDate(ref.getIssueCloseDate());
+
+      if (ref.isManualSeverity()) {
+        issue.setManualSeverity(true);
+        issue.setSeverity(ref.getSeverity());
+      } else {
+        // Emulate change of severity in the current scan.
+        String severity = issue.severity();
+        issue.setSeverity(ref.getSeverity());
+        updater.setSeverity(issue, severity, changeContext);
+      }
     }
   }
 
@@ -156,7 +162,7 @@ public class IssueTrackingDecorator implements Decorator {
 
       Rule rule = ruleFinder.findByKey(unmatched.ruleKey());
       boolean manualIssue = !Strings.isNullOrEmpty(unmatched.reporter());
-      boolean onExistingRule = rule != null && !Rule.STATUS_REMOVED.equals(rule.getStatus());
+      boolean onExistingRule = (rule != null && !Rule.STATUS_REMOVED.equals(rule.getStatus()));
       unmatched.setAlive(manualIssue && onExistingRule);
 
       issues.add(unmatched);
index dba4a9c613309ce454ec997c9a70a231dcdd87a5..8df79fd5c3abca389679b030bca0970b1ffd55c1 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.api.rules.RuleFinder;
 import org.sonar.batch.issue.IssueCache;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.IssueChangeContext;
+import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.db.IssueDto;
 import org.sonar.core.issue.workflow.IssueWorkflow;
 import org.sonar.core.persistence.AbstractDaoTestCase;
@@ -50,6 +51,7 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
   IssueFilters filters = mock(IssueFilters.class);
   IssueHandlers handlers = mock(IssueHandlers.class);
   IssueWorkflow workflow = mock(IssueWorkflow.class);
+  IssueUpdater updater = mock(IssueUpdater.class);
   ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
   Date loadedDate = new Date();
   RuleFinder ruleFinder = mock(RuleFinder.class);
@@ -61,7 +63,9 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
       issueCache,
       initialOpenIssues,
       tracking,
-      filters, handlers, workflow,
+      filters, handlers,
+      workflow,
+      updater,
       mock(Project.class),
       perspectives,
       ruleFinder);
index a2f64c12efb72ac3c80e92bbd9e62b405712880f..5f2ba2f22f89864e6e9cf524a094b9bf88858ef4 100644 (file)
@@ -35,7 +35,6 @@ import org.sonar.api.rule.Severity;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
-
 import java.io.Serializable;
 import java.util.Collections;
 import java.util.Date;
@@ -57,8 +56,6 @@ public class DefaultIssue implements Issue {
   private String reporter;
   private String assignee;
   private String checksum;
-  private boolean isNew = true;
-  private boolean isAlive = true;
   private Map<String, String> attributes = null;
   private String authorLogin = null;
   private FieldDiffs diffs = null;
@@ -70,9 +67,17 @@ public class DefaultIssue implements Issue {
   private Date updateDate;
   private Date closeDate;
 
-  // technical dates
-  private Date technicalCreationDate;
-  private Date technicalUpdateDate;
+  // The following states are used only during scan.
+
+  // true if the the issue did not exist in the previous scan.
+  private boolean isNew = true;
+
+  // true if the the issue did exist in the previous scan but not in the current one. That means
+  // that this issue should be closed.
+  private boolean isAlive = true;
+
+  // true if some fields have been changed since the previous scan
+  private boolean isChanged = false;
 
   public String key() {
     return key;
@@ -222,33 +227,6 @@ public class DefaultIssue implements Issue {
   }
 
 
-  /**
-   * The date when issue was physically created
-   */
-  public DefaultIssue setTechnicalCreationDate(@Nullable Date d) {
-    this.technicalCreationDate = d;
-    return this;
-  }
-
-  @CheckForNull
-  public Date technicalCreationDate() {
-    return technicalCreationDate;
-  }
-
-  /**
-   * The date when issue was physically updated for the last time
-   */
-
-  public DefaultIssue setTechnicalUpdateDate(@Nullable Date d) {
-    this.technicalUpdateDate = d;
-    return this;
-  }
-
-  @CheckForNull
-  public Date technicalUpdateDate() {
-    return technicalUpdateDate;
-  }
-
   @CheckForNull
   public String getChecksum() {
     return checksum;
@@ -277,6 +255,15 @@ public class DefaultIssue implements Issue {
     return this;
   }
 
+  public boolean isChanged() {
+    return isChanged;
+  }
+
+  public DefaultIssue setChanged(boolean b) {
+    isChanged = b;
+    return this;
+  }
+
   @CheckForNull
   public String attribute(String key) {
     return attributes == null ? null : attributes.get(key);
index 95d62e0d048dfbf048c626174ca72c54e3c084c0..88847d97804fa39dfd7af8139185d5ed590d8cfe 100644 (file)
@@ -116,8 +116,6 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder {
 
     Date now = new Date();
     Date date = Objects.firstNonNull(createdDate, now);
-    issue.setTechnicalCreationDate(now);
-    issue.setTechnicalUpdateDate(now);
     issue.setCreationDate(date);
     issue.setUpdateDate(date);
     issue.setComponentKey(componentKey);
@@ -129,8 +127,6 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder {
     issue.setManualSeverity(false);
     issue.setReporter(reporter);
     issue.setAttributes(attributes);
-    issue.setNew(true);
-    issue.setAlive(true);
     issue.setResolution(null);
     issue.setStatus(Issue.STATUS_OPEN);
     return issue;
index d01c8f5ffb13ea3086c91e7a59cee14321289066..0c9daf6538b8c60f0fdd8be77b3074ff8db365a1 100644 (file)
@@ -23,10 +23,8 @@ import com.google.common.base.Objects;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.BatchComponent;
 import org.sonar.api.ServerComponent;
-import org.sonar.api.issue.IssueComment;
 
 import javax.annotation.Nullable;
-
 import java.util.Date;
 
 /**
@@ -42,6 +40,7 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
       issue.setFieldDiff(context, "severity", issue.severity(), severity);
       issue.setSeverity(severity);
       issue.setUpdateDate(context.date());
+      issue.setChanged(true);
       return true;
     }
     return false;
@@ -53,6 +52,7 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
       issue.setSeverity(severity);
       issue.setManualSeverity(true);
       issue.setUpdateDate(context.date());
+      issue.setChanged(true);
       return true;
     }
     return false;
@@ -64,6 +64,7 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
       issue.setFieldDiff(context, "assignee", issue.assignee(), sanitizedAssignee);
       issue.setAssignee(sanitizedAssignee);
       issue.setUpdateDate(context.date());
+      issue.setChanged(true);
       return true;
     }
     return false;
@@ -72,6 +73,7 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
   public boolean setLine(DefaultIssue issue, @Nullable Integer line) {
     if (!Objects.equal(line, issue.line())) {
       issue.setLine(line);
+      issue.setChanged(true);
       return true;
     }
     return false;
@@ -82,6 +84,7 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
       issue.setFieldDiff(context, "resolution", issue.resolution(), resolution);
       issue.setResolution(resolution);
       issue.setUpdateDate(context.date());
+      issue.setChanged(true);
       return true;
     }
     return false;
@@ -92,32 +95,50 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
       issue.setFieldDiff(context, "status", issue.status(), status);
       issue.setStatus(status);
       issue.setUpdateDate(context.date());
+      issue.setChanged(true);
       return true;
     }
     return false;
   }
 
-  public void setAuthorLogin(DefaultIssue issue, @Nullable String authorLogin) {
-    issue.setAuthorLogin(authorLogin);
+  public void setAuthorLogin(DefaultIssue issue, @Nullable String authorLogin, IssueChangeContext context) {
+    if (!Objects.equal(authorLogin, issue.authorLogin())) {
+      issue.setFieldDiff(context, "author", issue.authorLogin(), authorLogin);
+      issue.setAuthorLogin(authorLogin);
+      issue.setUpdateDate(context.date());
+      issue.setChanged(true);
+    }
   }
 
   public void setMessage(DefaultIssue issue, @Nullable String s, IssueChangeContext context) {
-    issue.setMessage(s);
-    issue.setUpdateDate(context.date());
+    if (!Objects.equal(s, issue.message())) {
+      issue.setFieldDiff(context, "message", issue.message(), s);
+      issue.setMessage(s);
+      issue.setUpdateDate(context.date());
+      issue.setChanged(true);
+    }
   }
 
   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) {
-    issue.setCloseDate(d);
+  public void setCloseDate(DefaultIssue issue, @Nullable Date d, IssueChangeContext context) {
+    if (!Objects.equal(d, issue.closeDate())) {
+      issue.setCloseDate(d);
+      issue.setUpdateDate(context.date());
+      issue.setChanged(true);
+    }
   }
 
   public void setEffortToFix(DefaultIssue issue, @Nullable Double d, IssueChangeContext context) {
-    issue.setEffortToFix(d);
-    issue.setUpdateDate(context.date());
+    if (!Objects.equal(d, issue.closeDate())) {
+      issue.setEffortToFix(d);
+      issue.setUpdateDate(context.date());
+      issue.setChanged(true);
+    }
   }
 
   public boolean setAttribute(DefaultIssue issue, String key, @Nullable String value, IssueChangeContext context) {
@@ -126,6 +147,7 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
       issue.setFieldDiff(context, key, oldValue, value);
       issue.setAttribute(key, value);
       issue.setUpdateDate(context.date());
+      issue.setChanged(true);
       return true;
     }
     return false;
@@ -137,6 +159,7 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
       issue.setFieldDiff(context, "actionPlanKey", issue.actionPlanKey(), sanitizedActionPlanKey);
       issue.setActionPlanKey(sanitizedActionPlanKey);
       issue.setUpdateDate(context.date());
+      issue.setChanged(true);
       return true;
     }
     return false;
index e7bf13f7e5ad33b500818fbf831b4fc5c1874d06..de545172be55b88a41645fb5fadd77e43ec361e4 100644 (file)
@@ -310,7 +310,7 @@ public final class IssueDto {
     return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
   }
 
-  public static IssueDto toDtoForInsert(DefaultIssue issue, Integer componentId, Integer ruleId) {
+  public static IssueDto toDtoForInsert(DefaultIssue issue, Integer componentId, Integer ruleId, Date now) {
     return new IssueDto()
       .setKee(issue.key())
       .setLine(issue.line())
@@ -328,14 +328,15 @@ public final class IssueDto {
       .setActionPlanKey(issue.actionPlanKey())
       .setAttributes(issue.attributes() != null ? KeyValueFormat.format(issue.attributes()) : "")
       .setAuthorLogin(issue.authorLogin())
-      .setCreatedAt(issue.technicalCreationDate())
-      .setUpdatedAt(issue.technicalUpdateDate())
       .setIssueCreationDate(issue.creationDate())
       .setIssueCloseDate(issue.closeDate())
-      .setIssueUpdateDate(issue.updateDate());
+      .setIssueUpdateDate(issue.updateDate())
+
+      .setCreatedAt(now)
+      .setUpdatedAt(now);
   }
 
-  public static IssueDto toDtoForUpdate(DefaultIssue issue) {
+  public static IssueDto toDtoForUpdate(DefaultIssue issue, Date now) {
     // Invariant fields, like key and rule, can't be updated
     return new IssueDto()
       .setKee(issue.key())
@@ -352,10 +353,10 @@ public final class IssueDto {
       .setActionPlanKey(issue.actionPlanKey())
       .setAttributes(issue.attributes() != null ? KeyValueFormat.format(issue.attributes()) : "")
       .setAuthorLogin(issue.authorLogin())
-      .setUpdatedAt(issue.technicalUpdateDate())
       .setIssueCreationDate(issue.creationDate())
       .setIssueCloseDate(issue.closeDate())
-      .setIssueUpdateDate(issue.updateDate());
+      .setIssueUpdateDate(issue.updateDate())
+      .setUpdatedAt(now);
   }
 
   public DefaultIssue toDefaultIssue() {
@@ -376,8 +377,6 @@ public final class IssueDto {
     issue.setActionPlanKey(actionPlanKey);
     issue.setAuthorLogin(authorLogin);
     issue.setNew(false);
-    issue.setTechnicalCreationDate(createdAt);
-    issue.setTechnicalUpdateDate(updatedAt);
     issue.setCreationDate(issueCreationDate);
     issue.setCloseDate(issueCloseDate);
     issue.setUpdateDate(issueUpdateDate);
index 8064e7502c3b2fb9c633c08739ee99be14b0c364..1b2af6e383ecef42324a59a3a5e28d1f3a317123 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.core.issue.DefaultIssueComment;
 import org.sonar.core.persistence.MyBatis;
 
 import java.util.Arrays;
+import java.util.Date;
 import java.util.List;
 
 public abstract class IssueStorage {
@@ -50,19 +51,18 @@ public abstract class IssueStorage {
     SqlSession session = mybatis.openBatchSession();
     IssueMapper issueMapper = session.getMapper(IssueMapper.class);
     IssueChangeMapper issueChangeMapper = session.getMapper(IssueChangeMapper.class);
+    Date now = new Date();
     try {
       List<DefaultIssue> conflicts = Lists.newArrayList();
-
       for (DefaultIssue issue : issues) {
         if (issue.isNew()) {
           int componentId = componentId(issue);
           int ruleId = ruleId(issue);
-          IssueDto dto = IssueDto.toDtoForInsert(issue, componentId, ruleId);
+          IssueDto dto = IssueDto.toDtoForInsert(issue, componentId, ruleId, now);
           issueMapper.insert(dto);
 
-        } else /* TODO if hasChanges */ {
-          // TODO manage condition on update date
-          IssueDto dto = IssueDto.toDtoForUpdate(issue);
+        } else if (issue.isChanged()) {
+          IssueDto dto = IssueDto.toDtoForUpdate(issue, now);
           int count = issueMapper.update(dto);
           if (count < 1) {
             conflicts.add(issue);
index eaa3b7dc32a84cafd35dac07000874dd95aa0528..c2d974e3defd5c8839ffe7c5c3ea9be1748f39d8 100644 (file)
@@ -67,7 +67,7 @@ public class FunctionExecutor implements BatchComponent, ServerComponent {
 
     @Override
     public Function.Context setCloseDate(boolean b) {
-      updater.setCloseDate(issue, b ? changeContext.date() : null);
+      updater.setCloseDate(issue, b ? changeContext.date() : null, changeContext);
       return null;
     }
   }
index 5bdfdf1bee57c8f09ba98f9fb3a4821b0e0965c8..e56a212c99c57d82daad606245d3a06b51bbbd56 100644 (file)
@@ -51,8 +51,6 @@ public class DefaultIssueBuilderTest {
     assertThat(issue.ruleKey().repository()).isEqualTo("squid");
     assertThat(issue.ruleKey().rule()).isEqualTo("NullDereference");
     assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
-    assertThat(issue.technicalCreationDate()).isNotNull();
-    assertThat(issue.technicalUpdateDate()).isNotNull();
     assertThat(issue.assignee()).isNull();
     assertThat(issue.isNew()).isTrue();
     assertThat(issue.resolution()).isNull();
index 193c259d0d259b99e2a5f3d4d9ad9682af9b39ae..fd7f8f58b1e5119cd0260b8104c670a85c533add 100644 (file)
@@ -47,18 +47,21 @@ public class IssueStorageTest extends AbstractDaoTestCase {
     comment.setKey("FGHIJ");
 
     Date date = DateUtils.parseDate("2013-05-18");
-    DefaultIssue issue = new DefaultIssue();
-    issue.setKey("ABCDE");
-    issue.setRuleKey(RuleKey.of("squid", "AvoidCycle"));
-    issue.setLine(5000);
-    issue.setNew(true);
-    issue.setReporter("emmerik");
-    issue.setResolution("OPEN").setStatus("OPEN").setSeverity("BLOCKER");
-    issue.setAttribute("foo", "bar");
-    issue.addComment(comment);
-    issue.setCreationDate(date);
-    issue.setUpdateDate(date);
-    issue.setCloseDate(date);
+    DefaultIssue issue = new DefaultIssue()
+      .setKey("ABCDE")
+      .setNew(true)
+
+      .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
+      .setLine(5000)
+      .setReporter("emmerik")
+      .setResolution("OPEN")
+      .setStatus("OPEN")
+      .setSeverity("BLOCKER")
+      .setAttribute("foo", "bar")
+      .addComment(comment)
+      .setCreationDate(date)
+      .setUpdateDate(date)
+      .setCloseDate(date);
 
     saver.save(issue);
 
@@ -76,22 +79,30 @@ public class IssueStorageTest extends AbstractDaoTestCase {
     comment.setKey("FGHIJ");
 
     Date date = DateUtils.parseDate("2013-05-18");
-    DefaultIssue issue = new DefaultIssue();
-    issue.setKey("ABCDE");
-    issue.setRuleKey(RuleKey.of("squid", "AvoidCycle"));
-    issue.setLine(5000);
-    issue.setNew(false);
-    issue.setChecksum("FFFFF");
-    issue.setAuthorLogin("simon");
-    issue.setAssignee("loic");
-    issue.setFieldDiff(context, "severity", "INFO", "BLOCKER");
-    issue.setReporter("emmerik");
-    issue.setResolution("FIXED").setStatus("RESOLVED").setSeverity("BLOCKER");
-    issue.setAttribute("foo", "bar");
-    issue.addComment(comment);
-    issue.setCreationDate(date);
-    issue.setUpdateDate(date);
-    issue.setCloseDate(date);
+    DefaultIssue issue = new DefaultIssue()
+      .setKey("ABCDE")
+      .setNew(false)
+      .setChanged(true)
+
+        // updated fields
+      .setLine(5000)
+      .setChecksum("FFFFF")
+      .setAuthorLogin("simon")
+      .setAssignee("loic")
+      .setFieldDiff(context, "severity", "INFO", "BLOCKER")
+      .setReporter("emmerik")
+      .setResolution("FIXED")
+      .setStatus("RESOLVED")
+      .setSeverity("BLOCKER")
+      .setAttribute("foo", "bar")
+      .addComment(comment)
+      .setCreationDate(date)
+      .setUpdateDate(date)
+      .setCloseDate(date)
+
+        // unmodifiable fields
+      .setRuleKey(RuleKey.of("xxx", "unknown"))
+      .setComponentKey("not:a:component");
 
     saver.save(issue);
 
index ec614f6c39b7142e3b75a6a1d356905cdf140c66..eba1a27714d83678804c4a5613df7f6b6856edd7 100644 (file)
@@ -26,7 +26,6 @@ class Issue
       :rule => issue.ruleKey.toString(),
       :status => issue.status
     }
-    hash[:actionPlan] = issue.actionPlanKey if issue.actionPlanKey
     hash[:resolution] = issue.resolution if issue.resolution
     hash[:severity] = issue.severity if issue.severity
     hash[:message] = issue.message if issue.message
@@ -34,6 +33,7 @@ class Issue
     hash[:effortToFix] = issue.effortToFix.to_f if issue.effortToFix
     hash[:reporter] = issue.reporter if issue.reporter
     hash[:assignee] = issue.assignee if issue.assignee
+    hash[:actionPlan] = issue.actionPlanKey if issue.actionPlanKey
     hash[:creationDate] = Api::Utils.format_datetime(issue.creationDate) if issue.creationDate
     hash[:updateDate] = Api::Utils.format_datetime(issue.updateDate) if issue.updateDate
     hash[:closeDate] = Api::Utils.format_datetime(issue.closeDate) if issue.closeDate