Mercurial > hg > mercurial
changeset 312:8deb526363f5
TW-17882 report changes from the merged named branches
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesCommand.java Thu Sep 15 10:06:59 2011 +0400 @@ -0,0 +1,17 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ChangeSet; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author dmitry.neverov + */ +public interface CollectChangesCommand { + + @NotNull + public List<ChangeSet> execute(@NotNull String fromCommit, @NotNull String toCommit) throws VcsException; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesNoRevsets.java Thu Sep 15 10:06:59 2011 +0400 @@ -0,0 +1,82 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.util.Pair; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.util.graph.DAG; +import jetbrains.buildServer.util.graph.DAGIterator; +import jetbrains.buildServer.util.graph.DAGs; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.*; + +/** + * @author dmitry.neverov + */ +public class CollectChangesNoRevsets implements CollectChangesCommand { + + private final Settings mySettings; + private final File myWorkingDir; + private final File myTemplate; + + public CollectChangesNoRevsets(@NotNull final Settings settings, + @NotNull final File workingDir, + @NotNull final File template) { + mySettings = settings; + myWorkingDir = workingDir; + myTemplate = template; + } + + + @NotNull + public List<ChangeSet> execute(@NotNull final String fromCommit, @NotNull final String toCommit) throws VcsException { + List<ChangeSet> csets = getRevisionsReachableFrom(toCommit); + Map<String, ChangeSet> csetsMap = getChangesetMap(csets); + if (csetsMap.containsKey(fromCommit)) { + DAG<String> dag = DAGs.createFromEdges(getEdges(csets)); + DAGIterator<String> iter = dag.iterator(toCommit); + iter.markUninteresting(fromCommit); + List<ChangeSet> result = new ArrayList<ChangeSet>(); + while (iter.hasNext()) { + String commit = iter.next(); + ChangeSet cset = csetsMap.get(commit); + if (cset == null) + throw new IllegalStateException("Cannot find cset for id " + commit + ", csets map: " + csetsMap); + result.add(cset); + } + return result; + } else { + return Collections.emptyList(); + } + } + + + private Map<String, ChangeSet> getChangesetMap(@NotNull final List<ChangeSet> csets) { + Map<String, ChangeSet> result = new HashMap<String, ChangeSet>(); + for (ChangeSet cset : csets) { + result.put(cset.getId(), cset); + } + return result; + } + + + private List<ChangeSet> getRevisionsReachableFrom(@NotNull final String revision) throws VcsException { + LogCommand log = new LogCommand(mySettings, myWorkingDir, myTemplate); + log.setFromRevId(new ChangeSetRevision(revision).getId()); + log.showCommitsFromAllBranches(); + log.setToRevId("0"); + return log.execute(); + } + + + private List<Pair<String, String>> getEdges(List<ChangeSet> csets) { + List<Pair<String, String>> result = new ArrayList<Pair<String, String>>(); + for (ChangeSet cset : csets) { + for (ChangeSetRevision parent : cset.getParents()) { + result.add(Pair.create(cset.getId(), parent.getId())); + } + } + return result; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesWithRevsets.java Thu Sep 15 10:06:59 2011 +0400 @@ -0,0 +1,34 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ChangeSet; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.LogCommand; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; + +/** + * @author dmitry.neverov + */ +public class CollectChangesWithRevsets implements CollectChangesCommand { + + private final Settings mySettings; + private final File myWorkingDir; + private final File myTemplate; + + public CollectChangesWithRevsets(@NotNull final Settings settings, @NotNull final File workingDir, @NotNull final File template) { + mySettings = settings; + myWorkingDir = workingDir; + myTemplate = template; + } + + @NotNull + public List<ChangeSet> execute(@NotNull final String fromCommit, @NotNull final String toCommit) throws VcsException { + LogCommand log = new LogCommand(mySettings, myWorkingDir, myTemplate); + log.showCommitsFromAllBranches(); + log.setRevsets("ancestors(" + toCommit + ") - ancestors(" + fromCommit + ")"); + return log.execute(); + } +}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CommandFactory.java Wed Sep 14 18:49:59 2011 +0400 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CommandFactory.java Thu Sep 15 10:06:59 2011 +0400 @@ -32,8 +32,7 @@ @NotNull public MergeBaseCommand createMergeBase(@NotNull Settings settings, @NotNull File workingDir) throws VcsException { - VersionCommand versionCommand = new VersionCommand(settings, myDefaultWorkingDir); - HgVersion hgVersion = versionCommand.execute(); + HgVersion hgVersion = getHgVersion(settings); if (hgVersion.isEqualsOrGreaterThan(REVSET_HG_VERSION)) return new MergeBaseWithRevsets(settings, workingDir, this); else @@ -46,6 +45,15 @@ return new LogCommand(settings, workingDir, myLogTemplate); } + @NotNull + public CollectChangesCommand getCollectChangesCommand(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { + HgVersion hgVersion = getHgVersion(settings); + if (hgVersion.isEqualsOrGreaterThan(REVSET_HG_VERSION)) { + return new CollectChangesWithRevsets(settings, workingDir, myLogTemplate); + } else { + return new CollectChangesNoRevsets(settings, workingDir, myLogTemplate); + } + } private File createLogTemplate(@NotNull final File templateFileDir) throws IOException { File template = new File(templateFileDir, LOG_TEMPLATE_NAME); @@ -54,4 +62,9 @@ } return template; } + + private HgVersion getHgVersion(@NotNull final Settings settings) throws VcsException { + VersionCommand versionCommand = new VersionCommand(settings, myDefaultWorkingDir); + return versionCommand.execute(); + } }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Wed Sep 14 18:49:59 2011 +0400 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Thu Sep 15 10:06:59 2011 +0400 @@ -541,25 +541,30 @@ String toRevision = toRootRevision != null ? toRootRevision : getCurrentVersion(toRoot); String mergeBase = getMergeBase(settings, fromRootRevision, toRevision); if (mergeBase == null) - mergeBase = getMinusNthCommit(settings, 10); + return Collections.emptyList(); return collectChanges(toRoot, mergeBase, toRootRevision, checkoutRules); } @Nullable private String getMergeBase(@NotNull Settings settings, @NotNull String revision1, @NotNull String revision2) throws VcsException { - return myCommandFactory.createMergeBase(settings, getWorkingDir(settings)).execute(revision1, revision2); + String result = myCommandFactory.createMergeBase(settings, getWorkingDir(settings)).execute(revision1, revision2); + if (result == null) + result = getMinusNthCommit(settings, 10); + return result; } - @NotNull + @Nullable private String getMinusNthCommit(@NotNull Settings settings, int n) throws VcsException { LogCommand log = myCommandFactory.createLog(settings, getWorkingDir(settings)); - log.setFromRevId(settings.getBranchName()); + log.setToRevId(settings.getBranchName()); if (n > 0) log.setLimit(n); List<ChangeSet> changeSets = log.execute(); - return changeSets.get(changeSets.size() - 1).getId(); + if (changeSets.isEmpty()) + return null; + return changeSets.get(0).getId(); } @@ -571,43 +576,49 @@ public List<ModificationData> collectChanges(@NotNull VcsRoot root, @NotNull String fromVersion, @Nullable String currentVersion, @NotNull CheckoutRules checkoutRules) throws VcsException { Settings settings = createSettings(root); syncRepository(settings); - - // first obtain changes between specified versions List<ModificationData> result = new ArrayList<ModificationData>(); - if (currentVersion == null) - return result; + for (ChangeSet cset : getChangesets(settings, fromVersion, currentVersion)) { + result.add(createModificationData(cset, root, checkoutRules)); + } + return result; + } - File workingDir = getWorkingDir(settings); - LogCommand lc = myCommandFactory.createLog(settings, workingDir); - String fromId = new ChangeSetRevision(fromVersion).getId(); - lc.setFromRevId(fromId); - lc.setToRevId(new ChangeSetRevision(currentVersion).getId()); - List<ChangeSet> changeSets = lc.execute(); - if (changeSets.isEmpty()) { - return result; - } - ChangeSet prev = new ChangeSet(fromVersion); - for (ChangeSet cur : changeSets) { - if (cur.getId().equals(fromId)) - continue; // skip already reported changeset - - List<ChangeSetRevision> curParents = cur.getParents(); - boolean mergeCommit = curParents.size() > 1; - List<ModifiedFile> modifiedFiles = cur.getModifiedFiles(); - List<VcsChange> files = toVcsChanges(modifiedFiles, prev.getFullVersion(), cur.getFullVersion(), checkoutRules); - if (files.isEmpty() && !mergeCommit) - continue; - ModificationData md = new ModificationData(cur.getTimestamp(), files, cur.getDescription(), cur.getUser(), root, cur.getFullVersion(), cur.getId()); - if (mergeCommit) - md.setCanBeIgnored(false); - result.add(md); - prev = cur; + private ModificationData createModificationData(@NotNull final ChangeSet cset, @NotNull final VcsRoot root, @NotNull final CheckoutRules checkoutRules) { + List<ChangeSetRevision> parents = cset.getParents(); + if (parents.isEmpty()) + throw new IllegalStateException("Commit " + cset.getId() + " has no parents"); + List<VcsChange> files = toVcsChanges(cset.getModifiedFiles(), parents.get(0).getFullVersion(), cset.getFullVersion(), checkoutRules); + final ModificationData result = new ModificationData(cset.getTimestamp(), files, cset.getDescription(), cset.getUser(), root, cset.getFullVersion(), cset.getId()); + for (ChangeSetRevision parent : parents) { + result.addParentRevision(parent.getId()); } - + if (result.getParentRevisions().size() > 1) + result.setCanBeIgnored(false); return result; } + + @NotNull + private List<ChangeSet> getChangesets(@NotNull final Settings settings, @NotNull final String fromVersion, @Nullable final String toVersion) throws VcsException { + if (toVersion == null) + return Collections.emptyList(); + String fromCommit = new ChangeSetRevision(fromVersion).getId(); + String toCommit = new ChangeSetRevision(toVersion).getId(); + File workingDir = getWorkingDir(settings); + CollectChangesCommand log = myCommandFactory.getCollectChangesCommand(settings, workingDir); + List<ChangeSet> changesets = log.execute(fromCommit, toCommit); + Iterator<ChangeSet> iter = changesets.iterator(); + while (iter.hasNext()) { + ChangeSet cset = iter.next(); + if (cset.getId().equals(fromCommit)) + iter.remove();//skip already reported changes + } + return changesets; + } + + + @NotNull public BuildPatchPolicy getBuildPatchPolicy() { return new BuildPatchByCheckoutRules() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/DagFeaturesTest.java Thu Sep 15 10:06:59 2011 +0400 @@ -0,0 +1,76 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.TempFiles; +import jetbrains.buildServer.log.Log4jFactory; +import jetbrains.buildServer.vcs.CheckoutRules; +import jetbrains.buildServer.vcs.ModificationData; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import org.jmock.Mockery; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.File; +import java.util.List; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; + +/** + * @author dmitry.neverov + */ +@Test +public class DagFeaturesTest { + + static { + Logger.setFactory(new Log4jFactory()); + } + + private TempFiles myTempFiles = new TempFiles(); + private MercurialVcsSupport myHg; + private String myRepository; + + @BeforeMethod + public void setUp() throws Exception { + ServerPluginConfig config = new ServerPluginConfigBuilder() + .cachesDir(myTempFiles.createTempDir()) + .pluginDataDir(myTempFiles.createTempDir()) + .build(); + myHg = Util.createMercurialServerSupport(new Mockery(), config); + + File original = new File("mercurial-tests/testData/rep2"); + File copy = new File(myTempFiles.createTempDir(), "rep2"); + LocalRepositoryUtil.copyRepository(original, copy); + myRepository = copy.getAbsolutePath(); + } + + public void tearDown() { + myTempFiles.cleanup(); + } + + + //TW-17882 + public void should_detect_changes_from_named_branches() throws Exception { + VcsRootImpl root = new VcsRootBuilder().repository(myRepository).hgPath("/home/nd/sandbox/3rdparty/mercurial/hg").build(); + + List<ModificationData> changes = myHg.collectChanges(root, "8:b6e2d176fe8e", "12:1e620196c4b6", CheckoutRules.DEFAULT); + assertEquals(4, changes.size()); + for (ModificationData change : changes) { + assertFalse(change.getParentRevisions().isEmpty()); + } + + changes = myHg.collectChanges(root, "12:1e620196c4b6", "18:df04faa7575a", CheckoutRules.DEFAULT); + assertEquals(6, changes.size()); + for (ModificationData change : changes) { + assertFalse(change.getParentRevisions().isEmpty()); + } + } + + + //TW-17882 + public void should_report_changes_only_from_merged_named_branches() throws Exception { + VcsRootImpl root = new VcsRootBuilder().repository(myRepository).hgPath("/home/nd/sandbox/3rdparty/mercurial/hg").build(); + List<ModificationData> changes = myHg.collectChanges(root, "1e620196c4b6", "505c5b9d01e6", CheckoutRules.DEFAULT); + assertEquals(2, changes.size()); + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/LocalRepositoryUtil.java Wed Sep 14 18:49:59 2011 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/LocalRepositoryUtil.java Thu Sep 15 10:06:59 2011 +0400 @@ -43,10 +43,7 @@ File repository = myRepositories.get(repPath); if (repository != null) return repository; final File tempDir = myTempFiles.createTempDir(); - FileUtil.copyDir(new File(repPath), tempDir); - if (new File(tempDir, "hg").isDirectory()) { - FileUtil.rename(new File(tempDir, "hg"), new File(tempDir, ".hg")); - } + copyRepository(new File(repPath), tempDir); myRepositories.put(repPath, tempDir); return tempDir; } @@ -54,4 +51,11 @@ public static void forgetRepository(@NotNull String repPath) { myRepositories.remove(repPath); } + + + public static void copyRepository(File src, File dst) throws IOException { + FileUtil.copyDir(src, dst); + if (new File(dst, "hg").isDirectory()) + FileUtil.rename(new File(dst, "hg"), new File(dst, ".hg")); + } }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Wed Sep 14 18:49:59 2011 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Thu Sep 15 10:06:59 2011 +0400 @@ -398,10 +398,10 @@ VcsRootImpl vcsRoot = createVcsRoot(mergeCommittsRepo()); List<ModificationData> changes = collectChanges(vcsRoot, "8:b6e2d176fe8e", "12:1e620196c4b6", CheckoutRules.DEFAULT); - assertEquals(changes.size(), 2); + assertEquals(changes.size(), 4); - assertFiles(Arrays.asList("A dir6/file6.txt"), changes.get(0)); - assertFiles(Arrays.asList("M dir6/file6.txt", "A dir5/file5.txt"), changes.get(1)); + assertFiles(Arrays.asList("A dir6/file6.txt"), changes.get(2)); + assertFiles(Arrays.asList("M dir6/file6.txt", "A dir5/file5.txt"), changes.get(3)); } //TW-17530
--- a/mercurial-tests/src/testng.xml Wed Sep 14 18:49:59 2011 +0400 +++ b/mercurial-tests/src/testng.xml Thu Sep 15 10:06:59 2011 +0400 @@ -16,6 +16,7 @@ <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersionTest"/> <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.VersionCommandTest"/> <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerHgPathProviderTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.DagFeaturesTest"/> </classes> </test> </suite>