changeset 645:4cf1ab3cd162

Merge in subrepos
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Tue, 17 Sep 2013 18:48:51 +0400
parents 96af0d63f80a
children 60425d39da84
files mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommitCommand.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CheckoutRepository.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialCollectChangesPolicy.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialMergeSupport.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeSupportSubreposTest.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeSupportTest.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ModificationDataMatcher.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigBuilder.java mercurial-tests/testData/merge/README mercurial-tests/testData/merge/subrepos/subrepo1/hg/00changelog.i mercurial-tests/testData/merge/subrepos/subrepo1/hg/branch mercurial-tests/testData/merge/subrepos/subrepo1/hg/cache/branchheads-served mercurial-tests/testData/merge/subrepos/subrepo1/hg/cache/tags mercurial-tests/testData/merge/subrepos/subrepo1/hg/dirstate mercurial-tests/testData/merge/subrepos/subrepo1/hg/last-message.txt mercurial-tests/testData/merge/subrepos/subrepo1/hg/requires mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/00changelog.i mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/00manifest.i mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/a.i mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/b/c.i mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/b/d.i mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/~2ehgsub.i mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/~2ehgsubstate.i mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/fncache mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/phaseroots mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/undo mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/undo.phaseroots mercurial-tests/testData/merge/subrepos/subrepo1/hg/undo.bookmarks mercurial-tests/testData/merge/subrepos/subrepo1/hg/undo.branch mercurial-tests/testData/merge/subrepos/subrepo1/hg/undo.desc mercurial-tests/testData/merge/subrepos/subrepo1/hg/undo.dirstate mercurial-tests/testData/merge/subrepos/subrepo2/hg/00changelog.i mercurial-tests/testData/merge/subrepos/subrepo2/hg/branch mercurial-tests/testData/merge/subrepos/subrepo2/hg/cache/branchheads-served mercurial-tests/testData/merge/subrepos/subrepo2/hg/cache/tags mercurial-tests/testData/merge/subrepos/subrepo2/hg/dirstate mercurial-tests/testData/merge/subrepos/subrepo2/hg/last-message.txt mercurial-tests/testData/merge/subrepos/subrepo2/hg/requires mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/00changelog.i mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/00manifest.i mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/data/a.i mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/data/b/c.i mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/data/b/d.i mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/fncache mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/phaseroots mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/undo mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/undo.phaseroots mercurial-tests/testData/merge/subrepos/subrepo2/hg/undo.bookmarks mercurial-tests/testData/merge/subrepos/subrepo2/hg/undo.branch mercurial-tests/testData/merge/subrepos/subrepo2/hg/undo.desc mercurial-tests/testData/merge/subrepos/subrepo2/hg/undo.dirstate
diffstat 50 files changed, 366 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java	Tue Sep 17 14:36:02 2013 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java	Tue Sep 17 18:48:51 2013 +0400
@@ -73,6 +73,14 @@
     return new BookmarksCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings);
   }
 
+  public Map<String, String> getBranchRevisions(boolean includeBookmarks) throws VcsException {
+    Map<String, String> revisions = new HashMap<String, String>();
+    if (includeBookmarks && version().call().isEqualsOrGreaterThan(BookmarksCommand.REQUIRED_HG_VERSION))
+      revisions.putAll(bookmarks().call());
+    revisions.putAll(branches().call());
+    return revisions;
+  }
+
   public StatusCommand status() {
     return new StatusCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings);
   }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommitCommand.java	Tue Sep 17 14:36:02 2013 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommitCommand.java	Tue Sep 17 18:48:51 2013 +0400
@@ -23,6 +23,7 @@
   public void call() throws VcsException {
     MercurialCommandLine cmd = createCommandLine();
     cmd.addParameter("commit");
+    cmd.addParameter("-S");
     if (myCommitMessage != null)
       cmd.addParameters("-m", myCommitMessage);
     runCommand(cmd);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CheckoutRepository.java	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,175 @@
+package jetbrains.buildServer.buildTriggers.vcs.mercurial;
+
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Map;
+
+import static jetbrains.buildServer.util.FileUtil.delete;
+
+/**
+ * Repository checkout which uses mirrors (updates them first)
+ * and supports subrepos.
+ */
+public class CheckoutRepository {
+
+  private final MirrorManager myMirrorManager;
+  private final HgRepoFactory myHgRepoFactory;
+  private final int myPullTimeout;
+  private final HgVcsRoot myRoot;
+  private final File myWorkingDir;
+  private String myRevision;
+  private String myBranch;
+
+  CheckoutRepository(@NotNull MirrorManager mirrorManager,
+                     @NotNull HgRepoFactory hgRepoFactory,
+                     int pullTimeout,
+                     @NotNull HgVcsRoot root,
+                     @NotNull File workingDir) {
+    myMirrorManager = mirrorManager;
+    myHgRepoFactory = hgRepoFactory;
+    myPullTimeout = pullTimeout;
+    myRoot = root;
+    myWorkingDir = workingDir;
+  }
+
+  public CheckoutRepository setRevision(String revision) {
+    myRevision = revision;
+    return this;
+  }
+
+  public CheckoutRepository setBranch(String branch) {
+    myBranch = branch;
+    return this;
+  }
+
+  public void checkout() throws VcsException {
+    checkout(myRoot, myWorkingDir, myRevision);
+  }
+
+  private void checkout(@NotNull HgVcsRoot root,
+                        @NotNull File workingDir,
+                        @Nullable String revision) throws VcsException {
+    updateRepository(root, workingDir, revision);
+    if (revision == null && myBranch != null) {
+      HgRepo repo = myHgRepoFactory.createRepo(root, workingDir);
+      Map<String, String> revisions = repo.getBranchRevisions(true);
+      revision = revisions.get(myBranch);
+    }
+    if (revision == null)
+      return;
+    updateSubrepos(root, workingDir, revision);
+    updateWorkingDir(root, workingDir, revision);
+  }
+
+
+  private void updateRepository(@NotNull HgVcsRoot root,
+                                @NotNull File workingDir,
+                                @Nullable String revision) throws VcsException {
+    HgRepo repo = myHgRepoFactory.createRepo(root, workingDir);
+    if (revision != null && repo.containsRevision(revision))
+      return;
+
+    updateMirror(root, revision);
+    String mirrorUrl = getMirrorUrl(root);
+
+    if (repo.isValidRepository()) {
+      repo.pull().fromRepository(mirrorUrl)
+              .withTimeout(myPullTimeout)
+              .call();
+    } else {
+      repo.doClone().fromRepository(mirrorUrl)
+              .setUpdateWorkingDir(false)
+              .call();
+
+      repo.setDefaultPath(root.getRepository());
+    }
+  }
+
+
+  private void updateWorkingDir(@NotNull HgVcsRoot root,
+                                @NotNull File workingDir,
+                                @NotNull String revision) throws VcsException {
+    HgRepo repo = myHgRepoFactory.createRepo(root, workingDir);
+    repo.update().toRevision(revision).call();
+  }
+
+
+  private void updateSubrepos(@NotNull HgVcsRoot root,
+                              @NotNull File workingDir,
+                              @Nullable String revision) throws VcsException {
+    HgRepo repo = myHgRepoFactory.createRepo(root, workingDir);
+    if (!repo.hasSubreposAtRevision(revision))
+      return;
+
+    String workingDirRevision = repo.getWorkingDirRevision();
+    Map<String, SubRepo> workingDirSubrepos = repo.getSubrepositories(workingDirRevision);
+    Map<String, SubRepo> subrepos = repo.getSubrepositories(revision);
+    for (Map.Entry<String, SubRepo> entry : subrepos.entrySet()) {
+      String path = entry.getKey();
+      SubRepo subrepoConfig = entry.getValue();
+      SubRepo workingDirSubrepo = workingDirSubrepos.get(path);
+      if (workingDirSubrepo != null && subrepoConfig.hasDifferentUrlThan(workingDirSubrepo))
+        delete(subrepoConfigDir(repo, subrepoConfig));
+
+      File subrepoDir = new File(workingDir, subrepoConfig.path());
+      String subrepoUrl;
+      try {
+        subrepoUrl = subrepoConfig.resolveUrl(root.getRepository());
+        if (subrepoConfig.vcsType() == SubRepo.VcsType.hg && !isRelativeUrl(subrepoUrl)) {
+          HgVcsRoot subrepoRoot = root.withUrl(subrepoUrl);
+          updateRepository(subrepoRoot, subrepoDir, subrepoConfig.revision());
+        }
+      } catch (URISyntaxException e) {
+        subrepoUrl = subrepoConfig.url();
+      }
+
+      updateSubrepos(root.withUrl(subrepoUrl), subrepoDir, subrepoConfig.revision());
+    }
+  }
+
+
+  private boolean isRelativeUrl(@NotNull String url) {
+    return url.startsWith(".");
+  }
+
+
+  private File subrepoConfigDir(@NotNull HgRepo parentRepo, @NotNull SubRepo subrepo) {
+    return new File(parentRepo.getWorkingDir(), subrepo.path());
+  }
+
+
+  private void updateMirror(@NotNull HgVcsRoot root, @Nullable String revision) throws VcsException {
+    String url = root.getRepository();
+    File mirrorDir = myMirrorManager.getMirrorDir(url);
+    HgRepo repo = myHgRepoFactory.createRepo(root, mirrorDir);
+    if (revision != null && repo.containsRevision(revision)) {
+      return;
+    }
+
+    if (repo.isValidRepository()) {
+      repo.pull().fromRepository(root.getRepository())
+              .withTimeout(myPullTimeout)
+              .call();
+    } else {
+      repo.doClone().fromRepository(root.getRepository())
+              .setUpdateWorkingDir(false)
+              .useUncompressedTransfer(root.isUncompressedTransfer())
+              .call();
+      repo.setDefaultPath(root.getRepository());
+    }
+  }
+
+  private String getMirrorUrl(@NotNull HgVcsRoot root) throws VcsException {
+    try {
+      return myMirrorManager.getMirrorDir(root.getRepository()).getCanonicalPath();
+    } catch (IOException e) {
+      throw new VcsException(e);
+    }
+  }
+}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialCollectChangesPolicy.java	Tue Sep 17 14:36:02 2013 +0400
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialCollectChangesPolicy.java	Tue Sep 17 18:48:51 2013 +0400
@@ -43,9 +43,7 @@
   public RepositoryStateData getCurrentState(@NotNull VcsRoot root) throws VcsException {
     HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
     myVcs.syncRepository(hgRoot);
-    Map<String, String> revisions = new HashMap<String, String>();
-    revisions.putAll(getBookmarkRevisions(hgRoot));
-    revisions.putAll(getBranchesRevisions(hgRoot));
+    Map<String, String> revisions = myVcs.createRepo(hgRoot).getBranchRevisions(myConfig.bookmarksEnabled());
     String defaultBranchName = hgRoot.getBranchName();
     if (revisions.get(defaultBranchName) == null) {
       throw new VcsException("Cannot find revision of the default branch '" +
@@ -56,25 +54,6 @@
 
 
   @NotNull
-  private Map<String, String> getBranchesRevisions(@NotNull HgVcsRoot root) throws VcsException {
-    HgRepo repo = myVcs.createRepo(root);
-    return repo.branches().call();
-  }
-
-
-  @NotNull
-  private Map<String, String> getBookmarkRevisions(@NotNull HgVcsRoot root) throws VcsException {
-    ServerHgRepo repo = myVcs.createRepo(root);
-    if (!myConfig.bookmarksEnabled())
-      return emptyMap();
-    HgVersion version = repo.version().call();
-    if (!version.isEqualsOrGreaterThan(BookmarksCommand.REQUIRED_HG_VERSION))
-      return emptyMap();
-    return repo.bookmarks().call();
-  }
-
-
-  @NotNull
   public List<ModificationData> collectChanges(@NotNull VcsRoot fromRoot,
                                                @NotNull RepositoryStateData fromState,
                                                @NotNull VcsRoot toRoot,
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialMergeSupport.java	Tue Sep 17 14:36:02 2013 +0400
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialMergeSupport.java	Tue Sep 17 18:48:51 2013 +0400
@@ -1,11 +1,11 @@
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
+import com.intellij.openapi.diagnostic.Logger;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.MergeConflictException;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.MergeWithWorkingDirAncestor;
 import jetbrains.buildServer.vcs.*;
 import org.jetbrains.annotations.NotNull;
-import com.intellij.openapi.diagnostic.Logger;
 
 import java.io.File;
 import java.util.HashMap;
@@ -18,14 +18,21 @@
 
   private final static Logger LOG = Logger.getInstance(MercurialMergeSupport.class.getName());
 
-  private final MercurialVcsSupport myVcs;
+  private final MirrorManager myMirrorManager;
+  private final ServerPluginConfig myConfig;
   private final HgVcsRootFactory myHgVcsRootFactory;
+  private final HgRepoFactory myHgRepoFactory;
 
   public MercurialMergeSupport(@NotNull MercurialVcsSupport vcs,
-                               @NotNull HgVcsRootFactory vcsRootFactory) {
+                               @NotNull MirrorManager mirrorManager,
+                               @NotNull ServerPluginConfig config,
+                               @NotNull HgVcsRootFactory vcsRootFactory,
+                               @NotNull HgRepoFactory hgRepoFactory) {
     vcs.addExtension(this);
-    myVcs = vcs;
+    myMirrorManager = mirrorManager;
+    myConfig = config;
     myHgVcsRootFactory = vcsRootFactory;
+    myHgRepoFactory = hgRepoFactory;
   }
 
   @NotNull
@@ -34,20 +41,13 @@
     try {
       tmpDir = HgFileUtil.createTempDir();
       HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
-      myVcs.syncRepository(hgRoot);//sync in caches
-
-      HgVcsRoot tmpRoot = hgRoot.withUrl(myVcs.getWorkingDir(hgRoot).getAbsolutePath());
-      tmpRoot.setCustomWorkingDir(tmpDir);
-      myVcs.syncRepository(tmpRoot);//sync tmp repo
-
-      hgRoot.setCustomWorkingDir(tmpDir);
-      HgRepo repo = myVcs.createRepo(hgRoot);
-      repo.setDefaultPath(hgRoot.getRepository());
+      HgRepo repo = myHgRepoFactory.createRepo(hgRoot, tmpDir);
       Map<MergeTask, MergeResult> results = new HashMap<MergeTask, MergeResult>();
       for (MergeTask task : tasks) {
         MergeResult result = new MergeResult();
         try {
-          repo.update().toRevision(task.getDestinationRevision()).call();
+          new CheckoutRepository(myMirrorManager, myHgRepoFactory, myConfig.getPullTimeout(), hgRoot, tmpDir)
+                  .setRevision(task.getDestinationRevision()).checkout();
           repo.merge().revision(task.getSourceRevision()).call();
         } catch (MergeConflictException e) {
           List<String> conflicts = repo.resolve().call();
@@ -57,6 +57,8 @@
           //ignore
         } catch (VcsException e) {
           result.setSuccess(false);
+        } finally {
+          repo.update().toRevision(task.getDestinationRevision()).call();
         }
         results.put(task, result);
       }
@@ -70,6 +72,7 @@
     }
   }
 
+
   @NotNull
   public MergeResult merge(@NotNull VcsRoot root,
                            @NotNull String srcRevision,
@@ -81,11 +84,11 @@
     try {
       tmpDir = HgFileUtil.createTempDir();
       HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
-      hgRoot.setCustomWorkingDir(tmpDir);
-      myVcs.syncRepository(hgRoot);
-      HgRepo repo = myVcs.createRepo(hgRoot);
-      repo.update().branch(dstBranch).call();
 
+      new CheckoutRepository(myMirrorManager, myHgRepoFactory, myConfig.getPullTimeout(), hgRoot, tmpDir)
+              .setBranch(dstBranch).checkout();
+
+      HgRepo repo = myHgRepoFactory.createRepo(hgRoot, tmpDir);
       try {
         repo.merge().revision(srcRevision).call();
       } catch (MergeConflictException e) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeSupportSubreposTest.java	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,58 @@
+package jetbrains.buildServer.buildTriggers.vcs.mercurial;
+
+import jetbrains.buildServer.vcs.*;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.List;
+
+import static jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialSupportBuilder.mercurialSupport;
+import static jetbrains.buildServer.buildTriggers.vcs.mercurial.ModificationDataMatcher.modificationData;
+import static jetbrains.buildServer.buildTriggers.vcs.mercurial.Util.copyRepository;
+import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItem;
+
+@Test
+public class MergeSupportSubreposTest extends BaseMercurialTestCase {
+
+  private File mySubrepo1;
+  private File mySubrepo2;
+  private MercurialVcsSupport myVcs;
+  private MercurialMergeSupport myMergeSupport;
+
+  @BeforeMethod
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    File parentDir = myTempFiles.createTempDir();
+    mySubrepo1 = new File(parentDir, "subrepo1");
+    mySubrepo2 = new File(parentDir, "subrepo2");
+    mySubrepo1.mkdirs();
+    mySubrepo2.mkdirs();
+    copyRepository(new File("mercurial-tests/testData/merge/subrepos/subrepo1"), mySubrepo1);
+    copyRepository(new File("mercurial-tests/testData/merge/subrepos/subrepo2"), mySubrepo2);
+
+    ServerPluginConfig pluginConfig = new ServerPluginConfigBuilder()
+            .cachesDir(myTempFiles.createTempDir())
+            .build();
+    MercurialSupportBuilder mercurialBuilder = mercurialSupport().withConfig(pluginConfig);
+    myVcs = mercurialBuilder.build();
+    myMergeSupport = new MercurialMergeSupport(myVcs, myVcs.getMirrorManager(), pluginConfig,
+            mercurialBuilder.getHgRootFactory(), mercurialBuilder.getHgRepoFactory());
+  }
+
+
+  public void should_do_merge_in_subrepo_if_it_has_appropriate_branch() throws Exception {
+    VcsRoot root = vcsRoot().withUrl(mySubrepo1).withSubrepoChanges(true).build();
+    RepositoryStateData beforeMerge = myVcs.getCollectChangesPolicy().getCurrentState(root);
+    myMergeSupport.merge(root, "0bd1ae88632d", "default", "merge into default", new MergeOptions());
+    RepositoryStateData afterMerge = myVcs.getCollectChangesPolicy().getCurrentState(root);
+    List<ModificationData> ms = myVcs.getCollectChangesPolicy().collectChanges(root, beforeMerge, afterMerge, CheckoutRules.DEFAULT);
+    assertThat("Cannot find main repo merge commit", ms, hasItem(modificationData().withDescription("merge into default")
+            .withParentRevisions("eb211547efbe", "0bd1ae88632d")));
+    assertThat("Cannot find subrepo merge commit", ms, hasItem(modificationData().withDescription("merge into default")
+            .withParentRevisions("675fa105b184", "1532dee5d922")));
+  }
+}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeSupportTest.java	Tue Sep 17 14:36:02 2013 +0400
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeSupportTest.java	Tue Sep 17 18:48:51 2013 +0400
@@ -37,7 +37,7 @@
             .build();
     MercurialSupportBuilder mercurialBuilder = mercurialSupport().withConfig(pluginConfig);
     myVcs = mercurialBuilder.build();
-    myMergeSupport = new MercurialMergeSupport(myVcs, mercurialBuilder.getHgRootFactory());
+    myMergeSupport = new MercurialMergeSupport(myVcs, myVcs.getMirrorManager(), pluginConfig, mercurialBuilder.getHgRootFactory(), mercurialBuilder.getHgRepoFactory());
     myRemoteRepo = myTempFiles.createTempDir();
     copyRepository(new File("mercurial-tests/testData/merge/no.subrepos"), myRemoteRepo);
   }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ModificationDataMatcher.java	Tue Sep 17 14:36:02 2013 +0400
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ModificationDataMatcher.java	Tue Sep 17 18:48:51 2013 +0400
@@ -6,14 +6,18 @@
 import org.jetbrains.annotations.NotNull;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+import static java.util.Arrays.asList;
+
 public class ModificationDataMatcher extends TypeSafeMatcher<ModificationData> {
 
   private String myVersion;
   private String myDescription;
   private Map<String, String> myVcsRootProperties = new HashMap<String, String>();
   private Map<String, String> myAttributes = new HashMap<String, String>();
+  private List<String> myParentRevisions;
 
   @Override
   public boolean matchesSafely(ModificationData m) {
@@ -25,6 +29,8 @@
       return false;
     if (!myAttributes.isEmpty() && !containsAllAttributes(m.getAttributes()))
       return false;
+    if (myParentRevisions != null && !m.getParentRevisions().equals(myParentRevisions))
+      return false;
     return true;
   }
 
@@ -38,6 +44,8 @@
       description.appendText(" with vcs root properties ").appendValue(myVcsRootProperties);
     if (!myAttributes.isEmpty())
       description.appendText(" with attributes ").appendValue(myAttributes);
+    if (myParentRevisions != null)
+      description.appendText(" with parent revisions ").appendValue(myParentRevisions);
   }
 
   public static ModificationDataMatcher modificationData() {
@@ -64,6 +72,11 @@
     return this;
   }
 
+  public ModificationDataMatcher withParentRevisions(String... parentRevisions) {
+    myParentRevisions = asList(parentRevisions);
+    return this;
+  }
+
   private boolean containsAllAttributes(@NotNull Map<String, String> attributes) {
     for (Map.Entry<String, String> e : myAttributes.entrySet()) {
       String expectedValue = e.getValue();
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigBuilder.java	Tue Sep 17 14:36:02 2013 +0400
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigBuilder.java	Tue Sep 17 18:48:51 2013 +0400
@@ -15,7 +15,7 @@
   private String myHgPath;
   private File myCachesDir;
   private boolean myDontUseRevsets = false;
-  private boolean myDetectSubrepoChanges = false;
+  private boolean myDetectSubrepoChanges = true;
   private long myMirrorExpirationTimeout;
 
   @NotNull
--- a/mercurial-tests/testData/merge/README	Tue Sep 17 14:36:02 2013 +0400
+++ b/mercurial-tests/testData/merge/README	Tue Sep 17 18:48:51 2013 +0400
@@ -1,11 +1,45 @@
 no.subrepos
 
-o    changeset:   4:79d836707416 topic2
+o    4:79d836707416 topic2
 |
-| o  changeset:   3:2742914d19b2 topic1
+| o  3:2742914d19b2 topic1
 |/
-| o  changeset:   2:09dd527b77ec
+| o  2:09dd527b77ec
 |/
-o    changeset:   1:6370ce18689a
+o    1:6370ce18689a
 |
-o    changeset:   0:7e3988f0f412
+o    0:7e3988f0f412
+
+
+
+subrepo1
+
+o      6:eb211547efbe         ~> subrepo2 675fa105b184
+|
+| o    5:a3db56ba38d3 topic3  ~> subrepo2 085a6376bbce
+| |
+| | o  4:3e43f76179ed topic2  ~> subrepo2 085a6376bbce
+| |/
+| | o  3:0bd1ae88632d topic1  ~> subrepo2 1532dee5d922
+| |/
+o |    2:111ee5cb00c8         ~> subrepo2 627ca21f914a
+|/
+o      1:a4bb39f3d42b         ~> subrepo2 627ca21f914a
+|
+o      0:f43f3725e922
+
+
+subrepo2
+
+o    4:085a6376bbce topic2
+|
+| o  3:1532dee5d922 topic1
+|/
+| o  2:675fa105b184
+|/
+o    1:627ca21f914a
+|
+o    0:5a88c102487e
+
+
+
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/00changelog.i has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/branch	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/cache/branchheads-served	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,5 @@
+eb211547efbe93ab842d97263d645fcf77c01b8e 6
+eb211547efbe93ab842d97263d645fcf77c01b8e default
+0bd1ae88632d2694bdb227b76c4e7f7346bd1718 topic1
+3e43f76179edacde228056f906d16bdbd8b3ba30 topic2
+a3db56ba38d345e814abca5a0555243b4db809fd topic3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/cache/tags	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,5 @@
+5 a3db56ba38d345e814abca5a0555243b4db809fd
+4 3e43f76179edacde228056f906d16bdbd8b3ba30
+3 0bd1ae88632d2694bdb227b76c4e7f7346bd1718
+2 111ee5cb00c83258c9fd13e402e20741bb575510
+
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/dirstate has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/last-message.txt	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+track last subrepo1 commit in default
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/requires	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,4 @@
+dotencode
+fncache
+revlogv1
+store
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/00changelog.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/00manifest.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/a.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/b/c.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/b/d.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/~2ehgsub.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/data/~2ehgsubstate.i has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/fncache	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,5 @@
+data/b/c.i
+data/.hgsubstate.i
+data/b/d.i
+data/.hgsub.i
+data/a.i
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/phaseroots	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+1 f43f3725e92209f5e82118524ac8075a62326151
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/undo has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/store/undo.phaseroots	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+1 f43f3725e92209f5e82118524ac8075a62326151
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/undo.branch	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+default
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo1/hg/undo.desc	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,2 @@
+6
+commit
Binary file mercurial-tests/testData/merge/subrepos/subrepo1/hg/undo.dirstate has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo2/hg/00changelog.i has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/branch	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+topic2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/cache/branchheads-served	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,4 @@
+085a6376bbceaefcdaa2c9c7a8ae3ea9ec91d2c3 4
+675fa105b184f695b11cbf31d08cda09f1114cc2 default
+1532dee5d922539bb47ae13c3d1eadd126dad426 topic1
+085a6376bbceaefcdaa2c9c7a8ae3ea9ec91d2c3 topic2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/cache/tags	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,4 @@
+4 085a6376bbceaefcdaa2c9c7a8ae3ea9ec91d2c3
+3 1532dee5d922539bb47ae13c3d1eadd126dad426
+2 675fa105b184f695b11cbf31d08cda09f1114cc2
+
Binary file mercurial-tests/testData/merge/subrepos/subrepo2/hg/dirstate has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/last-message.txt	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+create b/c conflicting with default
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/requires	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,4 @@
+dotencode
+fncache
+revlogv1
+store
Binary file mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/00changelog.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/00manifest.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/data/a.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/data/b/c.i has changed
Binary file mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/data/b/d.i has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/fncache	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,3 @@
+data/b/c.i
+data/b/d.i
+data/a.i
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/phaseroots	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+1 5a88c102487e07f4413e3574357303a38e483ac0
Binary file mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/undo has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/store/undo.phaseroots	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+1 5a88c102487e07f4413e3574357303a38e483ac0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/undo.branch	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,1 @@
+topic2
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/merge/subrepos/subrepo2/hg/undo.desc	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,2 @@
+4
+commit
Binary file mercurial-tests/testData/merge/subrepos/subrepo2/hg/undo.dirstate has changed