changeset 44:1490e2981799

labeling/tagging support
author Pavel.Sher
date Fri, 05 Sep 2008 01:15:29 +0400
parents cdcf9a82116f
children 4059fcc5473e
files mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TagCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TipCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java mercurial-server/mercurial-server.iml mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialTestCase.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/LocalRepositoryUtil.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java mercurial-tests/testData/bin/Mercurial.ini mercurial-tests/testData/bin/library.zip mercurial.ipr
diffstat 21 files changed, 263 insertions(+), 168 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Fri Sep 05 01:15:29 2008 +0400
@@ -19,4 +19,5 @@
   String VCS_NAME = "mercurial";
   String REPOSITORY_PROP = "repositoryPath";
   String HG_COMMAND_PATH_PROP = "hgCommandPath";
+  String PUSH_URL = "pushUrl";
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -0,0 +1,39 @@
+package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
+
+import org.jetbrains.annotations.NotNull;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.util.StringUtil;
+import jetbrains.buildServer.vcs.VcsException;
+
+/**
+ * @author pavel
+ */
+public class BaseCommand {
+  private Settings mySettings;
+
+  public BaseCommand(@NotNull final Settings settings) {
+    mySettings = settings;
+  }
+
+  public Settings getSettings() {
+    return mySettings;
+  }
+
+  protected GeneralCommandLine createCommandLine() {
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setExePath(getSettings().getHgCommandPath());
+    cli.setWorkDirectory(getSettings().getWorkingDir().getAbsolutePath());
+    return cli;
+  }
+
+  protected ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException {
+    return CommandUtil.runCommand(cli);
+  }
+
+  protected void failIfNotEmptyStdErr(@NotNull GeneralCommandLine cli, @NotNull ExecResult res) throws VcsException {
+    if (!StringUtil.isEmpty(res.getStderr())) {
+      CommandUtil.commandFailed(cli.getCommandLineString(), res);
+    }
+  }
+}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -24,12 +24,11 @@
 import java.io.IOException;
 import java.util.List;
 
-public class CatCommand {
-  private Settings mySettings;
+public class CatCommand extends BaseCommand {
   private String myRevId;
 
   public CatCommand(@NotNull final Settings settings) {
-    mySettings = settings;
+    super(settings);
   }
 
   public void setRevId(final String revId) {
@@ -50,9 +49,7 @@
       }
     }
 
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    GeneralCommandLine cli = createCommandLine();
     cli.addParameter("cat");
     cli.addParameter("-o");
     cli.addParameter(tempDir.getAbsolutePath() + File.separator + "%p");
@@ -63,7 +60,7 @@
     for (String p: relPaths) {
       cli.addParameter(FileUtil.normalizeSeparator(p));
     }
-    CommandUtil.runCommand(cli);
+    runCommand(cli);
     return tempDir;
   }
 }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -21,14 +21,13 @@
 
 import java.io.File;
 
-public class CloneCommand {
-  private Settings mySettings;
+public class CloneCommand extends BaseCommand{
   private String myDestDir;
   private String myToId;
   private boolean myUpdateWorkingDir = true;
 
   public CloneCommand(@NotNull final Settings settings) {
-    mySettings = settings;
+    super(settings);
   }
 
   public void setDestDir(@NotNull String destDir) {
@@ -45,8 +44,7 @@
 
   public void execute() throws VcsException {
     if (myDestDir == null) throw new IllegalStateException("Destination dir must be specified");
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
+    GeneralCommandLine cli = createCommandLine();
     File dir = new File(myDestDir);
     File parent = dir.getParentFile();
     cli.setWorkDirectory(parent.getAbsolutePath());
@@ -59,9 +57,9 @@
     if (!myUpdateWorkingDir) {
       cli.addParameter("-U");
     }
-    cli.addParameter(mySettings.getRepository());
+    cli.addParameter(getSettings().getRepository());
     cli.addParameter(dir.getName());
 
-    CommandUtil.runCommand(cli);
+    runCommand(cli);
   }
 }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -17,6 +17,7 @@
 
 import com.intellij.execution.configurations.GeneralCommandLine;
 import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.util.StringUtil;
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
 
@@ -24,22 +25,18 @@
  * @author Pavel.Sher
  *         Date: 16.07.2008
  */
-public class IdentifyCommand {
-  private Settings mySettings;
-
+public class IdentifyCommand extends BaseCommand {
   public IdentifyCommand(@NotNull final Settings settings) {
-    mySettings = settings;
+    super(settings);
   }
 
   public String execute() throws VcsException {
     GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
+    cli.setExePath(getSettings().getHgCommandPath());
     cli.addParameter("identify");
-    cli.addParameter(mySettings.getRepository());
-    ExecResult res = CommandUtil.runCommand(cli);
-    if (res.getStderr().length() > 0) {
-      CommandUtil.commandFailed(cli.getCommandLineString(), res);
-    }
+    cli.addParameter(getSettings().getRepository());
+    ExecResult res = runCommand(cli);
+    failIfNotEmptyStdErr(cli, res);
     return res.getStdout();
   }
 }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -28,11 +28,11 @@
 import java.util.List;
 import java.util.Locale;
 
-public class LogCommand {
+public class LogCommand extends BaseCommand {
   private final static Logger LOG = Logger.getInstance(LogCommand.class.getName());
   private String myFromId;
   private String myToId;
-  private Settings mySettings;
+  private ArrayList<String> myPaths;
   private static final String CHANGESET_PREFIX = "changeset:";
   private static final String USER_PREFIX = "user:";
   private static final String DATE_PREFIX = "date:";
@@ -40,7 +40,7 @@
   private static final String SUMMARY_PREFIX = "summary:";
 
   public LogCommand(@NotNull Settings settings) {
-    mySettings = settings;
+    super(settings);
   }
 
   public void setFromRevId(String id) {
@@ -51,19 +51,26 @@
     myToId = id;
   }
 
+  public void setPaths(final List<String> relPaths) {
+    myPaths = new ArrayList<String>(relPaths);
+  }
+
   public List<ChangeSet> execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    GeneralCommandLine cli = createCommandLine();
     cli.addParameter("log");
     cli.addParameter("-r");
     String from = myFromId;
     if (from == null) from = "0";
     String to = myToId;
-    if (to == null) to = "0";
+    if (to == null) to = "tip";
     cli.addParameter(from + ":" + to);
+    if (myPaths != null) {
+      for (String path: myPaths) {
+        cli.addParameter(path);
+      }
+    }
 
-    ExecResult res = CommandUtil.runCommand(cli);
+    ExecResult res = runCommand(cli);
     return parseChangeSets(res.getStdout());
   }
 
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -23,19 +23,15 @@
  * @author Pavel.Sher
  *         Date: 14.07.2008
  */
-public class PullCommand {
-  private Settings mySettings;
-
+public class PullCommand extends BaseCommand {
   public PullCommand(@NotNull final Settings settings) {
-    mySettings = settings;
+    super(settings);
   }
 
   public void execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    GeneralCommandLine cli = createCommandLine();
     cli.addParameter("pull");
-    cli.addParameter(mySettings.getRepository());
-    CommandUtil.runCommand(cli);
+    cli.addParameter(getSettings().getRepository());
+    runCommand(cli);
   }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -0,0 +1,23 @@
+package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
+
+import com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author pavel
+ */
+public class PushCommand extends BaseCommand {
+  public PushCommand(@NotNull final Settings settings) {
+    super(settings);
+  }
+
+  public void execute() throws VcsException {
+    GeneralCommandLine cli = createCommandLine();
+    cli.addParameter("push");
+    cli.addParameter(getSettings().getPushUrl());
+    ExecResult res = runCommand(cli);
+    failIfNotEmptyStdErr(cli, res);
+  }
+}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java	Fri Sep 05 01:15:29 2008 +0400
@@ -20,6 +20,7 @@
 import jetbrains.buildServer.vcs.VcsRoot;
 import jetbrains.buildServer.util.Hash;
 import jetbrains.buildServer.util.FileUtil;
+import jetbrains.buildServer.util.StringUtil;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.File;
@@ -32,11 +33,13 @@
   private String myHgCommandPath;
   private File myWorkingDir;
   private File myWorkFolderParentDir;
+  private String myPushUrl;
 
   public Settings(@NotNull File workFolderParentDir, @NotNull VcsRoot vcsRoot) {
     myWorkFolderParentDir = workFolderParentDir;
     setRepository(vcsRoot.getProperty(Constants.REPOSITORY_PROP));
     setHgCommandPath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP));
+    myPushUrl = vcsRoot.getProperty(Constants.PUSH_URL);
   }
 
   public Settings() {
@@ -64,6 +67,14 @@
     return myHgCommandPath;
   }
 
+  /**
+   * Returns URL to use for push command if it was specified or repository path otherwise
+   * @return URL to use for push command if it was specified or repository path otherwise
+   */
+  public String getPushUrl() {
+    return StringUtil.isEmpty(myPushUrl) ? getRepository() : myPushUrl;
+  }
+
   public void setHgCommandPath(@NotNull final String hgCommandPath) {
     myHgCommandPath = hgCommandPath;
   }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -23,13 +23,12 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class StatusCommand {
-  private Settings mySettings;
+public class StatusCommand extends BaseCommand {
   private String myFromId;
   private String myToId;
 
   public StatusCommand(@NotNull final Settings settings) {
-    mySettings = settings;
+    super(settings);
   }
 
   public void setFromRevId(final String fromId) {
@@ -41,9 +40,7 @@
   }
 
   public List<ModifiedFile> execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    GeneralCommandLine cli = createCommandLine();
     cli.addParameter("status");
     cli.addParameter("--rev");
     String from = myFromId;
@@ -51,7 +48,7 @@
     String to = myToId;
     if (to == null) to = "0";
     cli.addParameter(from + ":" + to);
-    ExecResult res = CommandUtil.runCommand(cli);
+    ExecResult res = runCommand(cli);
     return parseFiles(res.getStdout());
   }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TagCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -0,0 +1,31 @@
+package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
+
+import org.jetbrains.annotations.NotNull;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.vcs.VcsException;
+
+public class TagCommand extends BaseCommand {
+  private String myTag;
+  private String myRevId;
+
+  public TagCommand(@NotNull Settings settings) {
+    super(settings);
+  }
+
+  public void setTag(@NotNull final String tag) {
+    myTag = tag;
+  }
+
+  public void setRevId(@NotNull final String revId) {
+    myRevId = revId;
+  }
+
+  public void execute() throws VcsException {
+    GeneralCommandLine cli = createCommandLine();
+    cli.addParameter("tag");
+    cli.addParameter("-r");
+    cli.addParameter(myRevId);
+    cli.addParameter(myTag);
+    runCommand(cli);
+  }
+}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TipCommand.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TipCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -26,21 +26,16 @@
  * @author Pavel.Sher
  *         Date: 14.07.2008
  */
-public class TipCommand {
-  @NotNull
-  private Settings mySettings;
-
+public class TipCommand extends BaseCommand {
   public TipCommand(@NotNull final Settings settings) {
-    mySettings = settings;
+    super(settings);
   }
 
   @NotNull
   public ChangeSet execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
-    cli.setExePath(mySettings.getHgCommandPath());
+    GeneralCommandLine cli = createCommandLine();
     cli.addParameter("tip");
-    ExecResult res = CommandUtil.runCommand(cli);
+    ExecResult res = runCommand(cli);
     List<ChangeSet> changeSets = LogCommand.parseChangeSets(res.getStdout());
     if (changeSets.isEmpty()) {
       CommandUtil.commandFailed("hg tip", res);
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java	Fri Sep 05 01:15:29 2008 +0400
@@ -19,12 +19,11 @@
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
 
-public class UpdateCommand {
-  private Settings mySettings;
+public class UpdateCommand extends BaseCommand {
   private String myToId;
 
   public UpdateCommand(@NotNull final Settings settings) {
-    mySettings = settings;
+    super(settings);
   }
 
   public void setToId(final String toId) {
@@ -32,15 +31,13 @@
   }
 
   public void execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    GeneralCommandLine cli = createCommandLine();
     cli.addParameter("update");
     cli.addParameter("-C");
     if (myToId != null) {
       cli.addParameter("-r");
       cli.addParameter(myToId);
     }
-    CommandUtil.runCommand(cli);
+    runCommand(cli);
   }
 }
--- a/mercurial-server/mercurial-server.iml	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-server/mercurial-server.iml	Fri Sep 05 01:15:29 2008 +0400
@@ -1,16 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <module relativePaths="true" type="JAVA_MODULE" version="4">
-  <component name="FacetManager">
-    <facet type="Spring" name="Spring">
-      <configuration>
-        <options>
-          <option name="enableValidation" value="false" />
-          <option name="reportErrorsAsWarnings" value="true" />
-        </options>
-        <customNs />
-      </configuration>
-    </facet>
-  </component>
   <component name="NewModuleRootManager" inherit-compiler-output="false">
     <output url="file://$MODULE_DIR$/classes" />
     <exclude-output />
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Fri Sep 05 01:15:29 2008 +0400
@@ -53,7 +53,7 @@
  * <p>Personal builds (remote runs) are not yet supported, they require corresponding functionality from the IDE.
  * <p>Checkout on agent mode is not yet supported too.
  */
-public class MercurialVcsSupport extends VcsSupport implements CollectChangesByIncludeRule {
+public class MercurialVcsSupport extends VcsSupport implements CollectChangesByIncludeRule, LabelingSupport {
   private ConcurrentMap<String, Lock> myWorkDirLocks= new ConcurrentHashMap<String, Lock>();
   private static final int OLD_WORK_DIRS_CLEANUP_PERIOD = 600;
   private VcsManager myVcsManager;
@@ -76,7 +76,7 @@
                                                     @NotNull final String fromVersion,
                                                     @NotNull final String currentVersion,
                                                     final CheckoutRules checkoutRules) throws VcsException {
-    updateWorkingDirectory(root);
+    syncClonedRepository(root);
     return VcsSupportUtil.collectBuildChanges(root, fromVersion, currentVersion, checkoutRules, this);
   }
 
@@ -86,7 +86,7 @@
                                                     final IncludeRule includeRule) throws VcsException {
     // first obtain changes between specified versions
     List<ModificationData> result = new ArrayList<ModificationData>();
-    Settings settings = new Settings(myDefaultWorkFolderParent, root);
+    Settings settings = createSettings(root);
     LogCommand lc = new LogCommand(settings);
     lc.setFromRevId(new ChangeSet(fromVersion).getId());
     lc.setToRevId(new ChangeSet(currentVersion).getId());
@@ -146,15 +146,15 @@
                            final VcsChangeInfo change,
                            final VcsChangeInfo.ContentType contentType,
                            final VcsRoot vcsRoot) throws VcsException {
-    updateWorkingDirectory(vcsRoot);
+    syncClonedRepository(vcsRoot);
     String version = contentType == VcsChangeInfo.ContentType.AFTER_CHANGE ? change.getAfterChangeRevisionNumber() : change.getBeforeChangeRevisionNumber();
     return getContent(change.getRelativeFileName(), vcsRoot, version);
   }
 
   @NotNull
   public byte[] getContent(final String filePath, final VcsRoot vcsRoot, final String version) throws VcsException {
-    updateWorkingDirectory(vcsRoot);
-    Settings settings = new Settings(myDefaultWorkFolderParent, vcsRoot);
+    syncClonedRepository(vcsRoot);
+    Settings settings = createSettings(vcsRoot);
     CatCommand cc = new CatCommand(settings);
     ChangeSet cs = new ChangeSet(version);
     cc.setRevId(cs.getId());
@@ -208,8 +208,8 @@
   @NotNull
   public String getCurrentVersion(final VcsRoot root) throws VcsException {
     // we will return full version of the most recent change as current version
-    updateWorkingDirectory(root);
-    Settings settings = new Settings(myDefaultWorkFolderParent, root);
+    syncClonedRepository(root);
+    Settings settings = createSettings(root);
     TipCommand lc = new TipCommand(settings);
     ChangeSet changeSet = lc.execute();
     return changeSet.getFullVersion();
@@ -225,7 +225,7 @@
 
   @Nullable
   public String testConnection(final VcsRoot vcsRoot) throws VcsException {
-    Settings settings = new Settings(myDefaultWorkFolderParent, vcsRoot);
+    Settings settings = createSettings(vcsRoot);
     IdentifyCommand id = new IdentifyCommand(settings);
     StringBuilder res = new StringBuilder();
     res.append(quoteIfNeeded(settings.getHgCommandPath()));
@@ -273,8 +273,8 @@
                          @NotNull final String toVersion,
                          final PatchBuilder builder,
                          final CheckoutRules checkoutRules) throws IOException, VcsException {
-    updateWorkingDirectory(root);
-    Settings settings = new Settings(myDefaultWorkFolderParent, root);
+    syncClonedRepository(root);
+    Settings settings = createSettings(root);
     if (fromVersion == null) {
       buildFullPatch(settings, new ChangeSet(toVersion), builder);
     } else {
@@ -366,8 +366,8 @@
   }
 
   // updates current working copy of repository by pulling changes from the repository specified in VCS root
-  private void updateWorkingDirectory(final VcsRoot root) throws VcsException {
-    Settings settings = new Settings(myDefaultWorkFolderParent, root);
+  private void syncClonedRepository(final VcsRoot root) throws VcsException {
+    Settings settings = createSettings(root);
     File workDir = settings.getWorkingDir();
     lockWorkDir(workDir);
     try {
@@ -387,6 +387,11 @@
     }
   }
 
+  @Override
+  public LabelingSupport getLabelingSupport() {
+    return this;
+  }
+
   private void lockWorkDir(@NotNull File workDir) {
     getWorkDirLock(workDir).lock();
   }
@@ -433,7 +438,7 @@
 
     for (VcsRoot vcsRoot: myVcsManager.getAllRegisteredVcsRoots()) {
       if (getName().equals(vcsRoot.getVcsName())) {
-        Settings s = new Settings(myDefaultWorkFolderParent, vcsRoot);
+        Settings s = createSettings(vcsRoot);
         workDirs.remove(FileUtil.getCanonicalFile(s.getWorkingDir()));
       }
     }
@@ -447,4 +452,41 @@
       }
     }
   }
+
+  public String label(@NotNull String label, @NotNull String version, @NotNull VcsRoot root, @NotNull CheckoutRules checkoutRules) throws VcsException {
+    syncClonedRepository(root);
+
+    Settings settings = createSettings(root);
+
+    // I do not know why but hg tag does not work correctly if
+    // update command was not invoked for the current repo
+    // in such case if there were no tags before Mercurial attempts to
+    // create new head when tag is pushed to the parent repository
+    UpdateCommand uc = new UpdateCommand(settings);
+    uc.execute();
+
+    String fixedTagname = fixTagName(label);
+    TagCommand tc = new TagCommand(settings);
+    tc.setRevId(new ChangeSet(version).getId());
+    tc.setTag(fixedTagname);
+    tc.execute();
+
+    PushCommand pc = new PushCommand(settings);
+    pc.execute();
+    return fixedTagname;
+  }
+
+  private String fixTagName(final String label) {
+    // according to Mercurial documentation http://hgbook.red-bean.com/hgbookch8.html#x12-1570008
+    // tag name must not contain:
+    // Colon (ASCII 58, :)
+    // Carriage return (ASCII 13, \r)
+    // Newline (ASCII 10, \n)
+    // all these characters will be replaced with _ (underscore)
+    return label.replace(':', '_').replace('\r', '_').replace('\n', '_');
+  }
+
+  private Settings createSettings(final VcsRoot root) {
+    return new Settings(myDefaultWorkFolderParent, root);
+  }
 }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialTestCase.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialTestCase.java	Fri Sep 05 01:15:29 2008 +0400
@@ -37,8 +37,17 @@
   protected VcsRootImpl createVcsRoot() throws IOException {
     VcsRootImpl vcsRoot = new VcsRootImpl(1, Constants.VCS_NAME);
     vcsRoot.addProperty(Constants.HG_COMMAND_PATH_PROP, new File("mercurial-tests/testData/bin/hg.exe").getAbsolutePath());
-    File repository = LocalRepositoryUtil.prepareRepository(new File("mercurial-tests/testData/rep1").getAbsolutePath());
+    String repPath = getRepositoryPath();
+    File repository = LocalRepositoryUtil.prepareRepository(repPath);
     vcsRoot.addProperty(Constants.REPOSITORY_PROP, repository.getAbsolutePath());
     return vcsRoot;
   }
+
+  private String getRepositoryPath() {
+    return new File("mercurial-tests/testData/rep1").getAbsolutePath();
+  }
+
+  protected void cleanRepositoryAfterTest() {
+    LocalRepositoryUtil.forgetRepository(getRepositoryPath());
+  }
 }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/LocalRepositoryUtil.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/LocalRepositoryUtil.java	Fri Sep 05 01:15:29 2008 +0400
@@ -50,4 +50,8 @@
     myRepositories.put(repPath, tempDir);
     return tempDir;
   }
+
+  public static void forgetRepository(@NotNull String repPath) {
+    myRepositories.remove(repPath);
+  }
 }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Fri Sep 05 01:15:29 2008 +0400
@@ -15,6 +15,9 @@
  */
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
+import com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandUtil;
 import jetbrains.buildServer.serverSide.SBuildServer;
 import jetbrains.buildServer.serverSide.ServerPaths;
 import jetbrains.buildServer.vcs.*;
@@ -58,7 +61,7 @@
   public void testGetCurrentVersion() throws Exception {
     VcsRootImpl vcsRoot = createVcsRoot();
 
-    assertEquals("6:b9deb9a1c6f4", myVcs.getCurrentVersion(vcsRoot));
+    assertEquals(myVcs.getCurrentVersion(vcsRoot), "6:b9deb9a1c6f4");
   }
 
   public void testCollectChanges() throws Exception {
@@ -70,38 +73,38 @@
     ModificationData md1 = changes.get(0);
     ModificationData md2 = changes.get(1);
     ModificationData md3 = changes.get(2);
-    assertEquals("1:1d446e82d356", md1.getVersion());
-    assertEquals("new file added", md1.getDescription());
+    assertEquals(md1.getVersion(), "1:1d446e82d356");
+    assertEquals(md1.getDescription(), "new file added");
     List<VcsChange> files1 = md1.getChanges();
     assertEquals(1, files1.size());
     assertEquals(VcsChangeInfo.Type.ADDED, files1.get(0).getType());
-    assertEquals("dir1/file3.txt", normalizePath(files1.get(0).getRelativeFileName()));
+    assertEquals(normalizePath(files1.get(0).getRelativeFileName()), "dir1/file3.txt");
 
-    assertEquals("2:7209b1f1d793", md2.getVersion());
-    assertEquals("file4.txt added", md2.getDescription());
+    assertEquals(md2.getVersion(), "2:7209b1f1d793");
+    assertEquals(md2.getDescription(), "file4.txt added");
     List<VcsChange> files2 = md2.getChanges();
     assertEquals(1, files2.size());
-    assertEquals(VcsChangeInfo.Type.ADDED, files2.get(0).getType());
-    assertEquals("dir1/file4.txt", normalizePath(files2.get(0).getRelativeFileName()));
+    assertEquals(files2.get(0).getType(), VcsChangeInfo.Type.ADDED);
+    assertEquals(normalizePath(files2.get(0).getRelativeFileName()), "dir1/file4.txt");
 
-    assertEquals("3:9522278aa38d", md3.getVersion());
-    assertEquals("file removed", md3.getDescription());
+    assertEquals(md3.getVersion(), "3:9522278aa38d");
+    assertEquals(md3.getDescription(), "file removed");
     List<VcsChange> files3 = md3.getChanges();
     assertEquals(1, files3.size());
-    assertEquals(VcsChangeInfo.Type.REMOVED, files3.get(0).getType());
-    assertEquals("dir1/file4.txt", normalizePath(files3.get(0).getRelativeFileName()));
+    assertEquals(files3.get(0).getType(), VcsChangeInfo.Type.REMOVED);
+    assertEquals(normalizePath(files3.get(0).getRelativeFileName()), "dir1/file4.txt");
   }
 
   public void testCollectChangesWithCheckoutRules() throws Exception {
     VcsRootImpl vcsRoot = createVcsRoot();
 
     List<ModificationData> changes = myVcs.collectBuildChanges(vcsRoot, "0:9875b412a788", "3:9522278aa38d", new CheckoutRules("-:.\n+:dir1/subdir"));
-    assertEquals(0, changes.size());
+    assertEquals(changes.size(), 0);
 
     changes = myVcs.collectBuildChanges(vcsRoot, "0:9875b412a788", "5:1d2cc6f3bc29", new CheckoutRules("-:.\n+:dir1/subdir"));
-    assertEquals(1, changes.size());
+    assertEquals(changes.size(), 1);
     ModificationData md = changes.get(0);
-    assertEquals("modified in subdir", md.getDescription());
+    assertEquals(md.getDescription(), "modified in subdir");
   }
 
   public void testBuildFullPatch() throws IOException, VcsException {
@@ -147,9 +150,9 @@
     VcsRootImpl vcsRoot = createVcsRoot();
 
     byte[] content = myVcs.getContent("dir1/subdir/file2.txt", vcsRoot, "4:b06a290a363b");
-    assertEquals("bbb", new String(content));
+    assertEquals(new String(content), "bbb");
     content = myVcs.getContent("dir1/subdir/file2.txt", vcsRoot, "5:1d2cc6f3bc29");
-    assertEquals("modified\r\nbbb", new String(content));
+    assertEquals(new String(content), "modified\r\nbbb");
   }
 
   public void testTestConnection() throws IOException, VcsException {
@@ -165,6 +168,23 @@
     }
   }
 
+  public void testTagging() throws IOException, VcsException {
+    VcsRootImpl vcsRoot = createVcsRoot();
+    cleanRepositoryAfterTest(); 
+
+    String actualTag = myVcs.label("new:tag", "1:1d446e82d356", vcsRoot, new CheckoutRules(""));
+    assertEquals(actualTag, "new_tag");
+
+    // check the tag is pushed to the parent repository
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setExePath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP));
+    cli.setWorkDirectory(vcsRoot.getProperty(Constants.REPOSITORY_PROP));
+    cli.addParameter("tags");
+    ExecResult res = CommandUtil.runCommand(cli);
+    assertTrue(res.getStdout().contains("new_tag"));
+    assertTrue(res.getStdout().contains("1:1d446e82d356"));
+  }
+
   private Object normalizePath(final String path) {
     return path.replace(File.separatorChar, '/');
   }
--- a/mercurial-tests/testData/bin/Mercurial.ini	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial-tests/testData/bin/Mercurial.ini	Fri Sep 05 01:15:29 2008 +0400
@@ -37,6 +37,8 @@
 # Some default global settings for common merge tools
 
 [merge-tools]
+# Some default global settings for common merge tools
+
 kdiff3.args=--auto --L1 base --L2 local --L3 other $base $local $other -o $output
 kdiff3.regkey=Software\KDiff3
 kdiff3.regappend=\kdiff3.exe
Binary file mercurial-tests/testData/bin/library.zip has changed
--- a/mercurial.ipr	Fri Aug 22 20:21:48 2008 +0400
+++ b/mercurial.ipr	Fri Sep 05 01:15:29 2008 +0400
@@ -14,16 +14,6 @@
   <component name="BuildJarProjectSettings">
     <option name="BUILD_JARS_ON_MAKE" value="false" />
   </component>
-  <component name="CCaseConfig">
-    <option name="implementation" value="net.sourceforge.transparent.CommandLineClearCase" />
-    <option name="checkoutReserved" value="false" />
-    <option name="markExternalChangeAsUpToDate" value="true" />
-    <option name="checkInUseHijack" value="true" />
-    <option name="isOffline" value="false" />
-    <option name="lastScr" value="" />
-    <option name="scrTextFileName" value="" />
-    <option name="lastViewType" />
-  </component>
   <component name="ChangeBrowserSettings">
     <option name="MAIN_SPLITTER_PROPORTION" value="0.3" />
     <option name="MESSAGES_SPLITTER_PROPORTION" value="0.8" />
@@ -335,17 +325,6 @@
       <SplitterProportionsDataImpl />
     </option>
   </component>
-  <component name="StarteamConfiguration">
-    <option name="SERVER" value="" />
-    <option name="PORT" value="49201" />
-    <option name="USER" value="" />
-    <option name="PASSWORD" value="" />
-    <option name="PROJECT" value="" />
-    <option name="VIEW" value="" />
-    <option name="ALTERNATIVE_WORKING_PATH" value="" />
-    <option name="LOCK_ON_CHECKOUT" value="false" />
-    <option name="UNLOCK_ON_CHECKIN" value="false" />
-  </component>
   <component name="Struts Assistant">
     <option name="showInputs" value="true" />
     <option name="resources">
@@ -384,41 +363,7 @@
   <component name="VcsDirectoryMappings">
     <mapping directory="" vcs="Mercurial" />
   </component>
-  <component name="VssConfiguration">
-    <option name="CLIENT_PATH" value="" />
-    <option name="SRCSAFEINI_PATH" value="" />
-    <option name="USER_NAME" value="" />
-    <option name="PWD" value="" />
-    <option name="VSS_IS_INITIALIZED" value="false" />
-    <CheckoutOptions>
-      <option name="COMMENT" value="" />
-      <option name="DO_NOT_GET_LATEST_VERSION" value="false" />
-      <option name="REPLACE_WRITABLE" value="false" />
-      <option name="RECURSIVE" value="false" />
-    </CheckoutOptions>
-    <CheckinOptions>
-      <option name="COMMENT" value="" />
-      <option name="KEEP_CHECKED_OUT" value="false" />
-      <option name="RECURSIVE" value="false" />
-    </CheckinOptions>
-    <AddOptions>
-      <option name="STORE_ONLY_LATEST_VERSION" value="false" />
-      <option name="CHECK_OUT_IMMEDIATELY" value="false" />
-    </AddOptions>
-    <UndocheckoutOptions>
-      <option name="MAKE_WRITABLE" value="false" />
-      <option name="REPLACE_LOCAL_COPY" value="0" />
-      <option name="RECURSIVE" value="false" />
-    </UndocheckoutOptions>
-    <GetOptions>
-      <option name="REPLACE_WRITABLE" value="0" />
-      <option name="MAKE_WRITABLE" value="false" />
-      <option name="ANSWER_NEGATIVELY" value="false" />
-      <option name="ANSWER_POSITIVELY" value="false" />
-      <option name="RECURSIVE" value="false" />
-      <option name="VERSION" />
-    </GetOptions>
-  </component>
+  <component name="WebServicesPlugin" addRequiredLibraries="true" />
   <component name="com.intellij.ide.util.scopeChooser.ScopeChooserConfigurable" proportions="" version="1">
     <option name="myLastEditedConfigurable" />
   </component>
@@ -528,10 +473,5 @@
     <outputDirectory />
     <properties />
   </component>
-  <component name="uidesigner-configuration">
-    <option name="INSTRUMENT_CLASSES" value="true" />
-    <option name="COPY_FORMS_RUNTIME_TO_OUTPUT" value="true" />
-    <option name="DEFAULT_LAYOUT_MANAGER" value="GridLayoutManager" />
-  </component>
 </project>