changeset 555:4f1c0ecc3371

Do not report duplicate changes
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Thu, 28 Feb 2013 19:13:52 +0400
parents 110de749f460
children e7788cecf48b
files mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OperationContext.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java
diffstat 3 files changed, 111 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Wed Feb 27 17:00:42 2013 +0400
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Thu Feb 28 19:13:52 2013 +0400
@@ -40,6 +40,7 @@
 import java.util.*;
 
 import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
 import static java.util.Collections.emptyMap;
 import static jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil.deleteDir;
 
@@ -475,7 +476,6 @@
                                                @NotNull RepositoryStateData fromState,
                                                @NotNull RepositoryStateData toState,
                                                @NotNull CheckoutRules rules) throws VcsException {
-    Set<String> reportedCsetIds = new HashSet<String>();
     List<ModificationData> changes = new ArrayList<ModificationData>();
     OperationContext ctx = new OperationContext(this, myRepoFactory);
     Set<String> prevStateRevisions = new HashSet<String>(fromState.getBranchRevisions().values());
@@ -491,10 +491,13 @@
       List<String> fromRevisions = getFromRevisionsForBranch(ctx, root, prevStateRevisions, fromRevision, toRevision);
       List<ModificationData> branchChanges = collectChanges(ctx, root, fromRevisions, toRevision, rules);
       for (ModificationData change : branchChanges) {
-        if (reportedCsetIds.add(change.getVersion()))
+        if (!ctx.isReportedModification(change)) {
           changes.add(change);
+          ctx.markAsReported(change);
+        }
       }
     }
+    changes.addAll(getSubrepoChanges(ctx, root, changes));
     return changes;
   }
 
@@ -592,7 +595,9 @@
 
   public List<ModificationData> collectChanges(@NotNull VcsRoot root, @NotNull String fromVersion, @Nullable String currentVersion, @NotNull CheckoutRules checkoutRules) throws VcsException {
     OperationContext ctx = new OperationContext(this, myRepoFactory);
-    return collectChanges(ctx, root, asList(fromVersion), currentVersion, checkoutRules);
+    List<ModificationData> changes = collectChanges(ctx, root, asList(fromVersion), currentVersion, checkoutRules);
+    changes.addAll(getSubrepoChanges(ctx, root, changes));
+    return changes;
   }
 
   private List<ModificationData> collectChanges(@NotNull OperationContext ctx,
@@ -606,15 +611,66 @@
     for (ChangeSet cset : getChangesets(ctx, hgRoot, fromVersion, currentVersion)) {
       result.add(createModificationData(ctx, cset, root, checkoutRules));
     }
+    return result;
+  }
 
-    if (myConfig.detectSubrepoChanges() && hgRoot.detectSubrepoChanges()) {
-      List<ModificationData> subrepoChanges = new ArrayList<ModificationData>();
-      for (ModificationData m : result) {
-        subrepoChanges.addAll(getSubrepoChanges(ctx, m));
+
+  @NotNull
+  private List<ModificationData> getSubrepoChanges(@NotNull OperationContext ctx, @NotNull VcsRoot root, @NotNull List<ModificationData> changes) throws VcsException {
+    if (changes.isEmpty())
+      return emptyList();
+
+    HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
+    if (!detectSubrepoChanges(hgRoot))
+      return emptyList();
+
+    List<SubrepoConfigChange> subrepoConfigChanges = getSubrepoConfigChanges(changes);
+    List<ModificationData> subrepoChanges = new ArrayList<ModificationData>();
+
+    for (SubrepoConfigChange configChange : subrepoConfigChanges) {
+      VcsRootImpl subrepo = new VcsRootImpl(root.getId(), configChange.getSubrepoRootParams());
+      if (ctx.isProcessedSubrepoChanges(subrepo, configChange.getPreviousSubrepoRevisions(), configChange.getCurrentSubrepoRevision()))
+        continue;
+      List<ModificationData> subChanges = collectChanges(ctx, subrepo, configChange.getPreviousSubrepoRevisions(), configChange.getCurrentSubrepoRevision(), CheckoutRules.DEFAULT);
+      for (ModificationData m : subChanges) {
+        if (!ctx.isReportedModification(m)) {
+          subrepoChanges.add(m);
+          ctx.markAsReported(m);
+        }
       }
-      result.addAll(subrepoChanges);
+      ctx.markProcessedSubrepoChanges(subrepo, configChange.getPreviousSubrepoRevisions(), configChange.getCurrentSubrepoRevision());
     }
-    return result;
+
+    List<ModificationData> subSubrepoChanges = getSubrepoChanges(ctx, root, subrepoChanges);
+    subrepoChanges.addAll(subSubrepoChanges);
+    return subrepoChanges;
+  }
+
+
+  private boolean detectSubrepoChanges(@NotNull HgVcsRoot root) {
+    return myConfig.detectSubrepoChanges() && root.detectSubrepoChanges();
+  }
+
+
+  private List<SubrepoConfigChange> getSubrepoConfigChanges(@NotNull List<ModificationData> mainRootChanges) {
+    List<SubrepoConfigChange> subrepoConfigChanges = new ArrayList<SubrepoConfigChange>();
+    for (ModificationData m : mainRootChanges) {
+      subrepoConfigChanges.addAll(getSubrepoConfigChanges(m));
+    }
+    return subrepoConfigChanges;
+  }
+
+
+  private List<SubrepoConfigChange> getSubrepoConfigChanges(@NotNull ModificationData m) {
+    List<SubrepoConfigChange> configChanges = new ArrayList<SubrepoConfigChange>();
+    for (SubrepoConfigChange configChange : SubrepoConfigChangesAttributes.readSubrepoConfigChanges(m.getAttributes())) {
+      if (configChange.getSubrepoRootParams().isEmpty())
+        continue;
+      if (configChange.getPreviousSubrepoRevisions().isEmpty())
+        continue;
+      configChanges.add(configChange);
+    }
+    return configChanges;
   }
 
 
@@ -669,7 +725,7 @@
   private Map<String, String> getAttributes(@NotNull OperationContext ctx, @NotNull VcsRoot mainRoot, @NotNull ChangeSet cset) throws VcsException {
     Map<String, String> attributes = new HashMap<String, String>();
     HgVcsRoot root = myHgVcsRootFactory.createHgRoot(mainRoot);
-    if (myConfig.detectSubrepoChanges() && root.detectSubrepoChanges()) {
+    if (detectSubrepoChanges(root)) {
       try {
         ServerHgRepo repo = createRepo(ctx, root);
         SubrepoConfigChangesAttributes builder = new SubrepoConfigChangesAttributes();
@@ -706,23 +762,6 @@
   }
 
   @NotNull
-  private List<ModificationData> getSubrepoChanges(@NotNull OperationContext ctx, @NotNull ModificationData m) throws VcsException {
-    List<ModificationData> subrepoChanges = new ArrayList<ModificationData>();
-    for (SubrepoConfigChange configChange : SubrepoConfigChangesAttributes.readSubrepoConfigChanges(m.getAttributes())) {
-      if (configChange.getSubrepoRootParams().isEmpty())
-        continue;
-      if (configChange.getPreviousSubrepoRevisions().isEmpty())
-        continue;
-      VcsRootImpl subrepo = new VcsRootImpl(m.getVcsRootObject().getId(), configChange.getSubrepoRootParams());
-      if (ctx.isProcessedSubrepoChanges(subrepo, configChange.getPreviousSubrepoRevisions(), configChange.getCurrentSubrepoRevision()))
-        continue;
-      subrepoChanges.addAll(collectChanges(ctx, subrepo, configChange.getPreviousSubrepoRevisions(), configChange.getCurrentSubrepoRevision(), CheckoutRules.DEFAULT));
-      ctx.markProcessedSubrepoChanges(subrepo, configChange.getPreviousSubrepoRevisions(), configChange.getCurrentSubrepoRevision());
-    }
-    return subrepoChanges;
-  }
-
-  @NotNull
   public BuildPatchPolicy getBuildPatchPolicy() {
     return this;
   }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OperationContext.java	Wed Feb 27 17:00:42 2013 +0400
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OperationContext.java	Thu Feb 28 19:13:52 2013 +0400
@@ -3,9 +3,11 @@
 import com.intellij.openapi.util.Pair;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
+import jetbrains.buildServer.vcs.ModificationData;
 import jetbrains.buildServer.vcs.VcsException;
 import jetbrains.buildServer.vcs.VcsRoot;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
 import java.util.*;
@@ -16,7 +18,8 @@
   private final RepoFactory myRepoFactory;
   private Set<File> mySyncedDirs = new HashSet<File>();
   private Map<String, HgVersion> myHgVersions = new HashMap<String, HgVersion>();
-  private Map<String, Set<SubrepoChangesInterval>> myProcessedSubrepoChanges = new HashMap<String, Set<SubrepoChangesInterval>>();
+  private Map<String, Set<SubrepoChangesInterval>> myProcessedSubrepoChanges = new HashMap<String, Set<SubrepoChangesInterval>>();//subrepo url -> processed changes intervals
+  private Map<VcsRootKey, Set<String>> myRevisionsPerRoot = new HashMap<VcsRootKey, Set<String>>();
   private Map<File, ServerHgRepo> myRepos = new HashMap<File, ServerHgRepo>();
 
   public OperationContext(@NotNull MercurialVcsSupport vcs,
@@ -74,9 +77,40 @@
     return repo;
   }
 
+  public boolean isReportedModification(@NotNull ModificationData m) {
+    Set<String> revisions = getReportedRootRevisions(m);
+    return revisions.contains(m.getVersion());
+  }
+
+  public void markAsReported(@NotNull ModificationData m) {
+    Set<String> revisions = getReportedRootRevisions(m);
+    revisions.add(m.getVersion());
+  }
+
+  @NotNull
+  private Set<String> getReportedRootRevisions(@NotNull ModificationData m) {
+    VcsRootKey key = VcsRootKey.create(m.getVcsRoot());
+    Set<String> revisions = myRevisionsPerRoot.get(key);
+    if (revisions == null) {
+      revisions = new HashSet<String>();
+      myRevisionsPerRoot.put(key, revisions);
+    }
+    return revisions;
+  }
+
   private final static class SubrepoChangesInterval extends Pair<List<String>, String> {
     private SubrepoChangesInterval(@NotNull List<String> prevRevisions, @NotNull String currentRevision) {
       super(prevRevisions, currentRevision);
     }
   }
+
+  private final static class VcsRootKey extends Pair<String, String> {
+    private VcsRootKey(@NotNull String repositoryUrl, @Nullable String subrepoPath) {
+      super(repositoryUrl, subrepoPath);
+    }
+
+    private static VcsRootKey create(@NotNull VcsRoot root) {
+      return new VcsRootKey(root.getProperty(Constants.REPOSITORY_PROP), root.getProperty("teamcity.internal.subrepo.path"));
+    }
+  }
 }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Wed Feb 27 17:00:42 2013 +0400
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Thu Feb 28 19:13:52 2013 +0400
@@ -603,6 +603,16 @@
   }
 
 
+  public void should_not_report_duplicate_changes() throws Exception {
+    VcsRootImpl root = createVcsRoot(myRep2Path);
+    List<ModificationData> changes = myVcs.collectChanges(root,
+            RepositoryStateData.createVersionState("default", map("default", "505c5b9d01e6", "personal-branch", "96b78d73081d")),
+            RepositoryStateData.createVersionState("default", map("default", "df04faa7575a", "personal-branch", "9ec402c74298")),
+            CheckoutRules.DEFAULT);
+    assertEquals(changes.size(), 4);
+  }
+
+
   private void assertFiles(final List<String> expectedFiles, final ModificationData modificationData) {
     Set<String> actualFiles = new HashSet<String>();
     for (VcsChange vc: modificationData.getChanges()) {