Skip to content

Commit

Permalink
[FIXED JENKINS-5396] Added supported option to update to a tag rather…
Browse files Browse the repository at this point in the history
… than a branch.
  • Loading branch information
jglick committed Dec 16, 2013
1 parent fadb4e6 commit a1d636a
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 43 deletions.
111 changes: 73 additions & 38 deletions src/main/java/hudson/plugins/mercurial/MercurialSCM.java
Expand Up @@ -5,7 +5,9 @@
import com.cloudbees.plugins.credentials.common.StandardUsernameListBoxModel;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
import static java.util.logging.Level.FINE;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressWarnings;
import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
Expand All @@ -19,12 +21,12 @@
import hudson.scm.ChangeLogParser;
import hudson.scm.PollingResult;
import hudson.scm.PollingResult.Change;
import hudson.scm.SCM;
import hudson.scm.SCMDescriptor;
import hudson.scm.SCMRevisionState;
import hudson.scm.SCM;
import hudson.util.ArgumentListBuilder;
import hudson.util.ForkOutputStream;

import hudson.util.ListBoxModel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
Expand All @@ -34,23 +36,18 @@
import java.io.Serializable;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static java.util.logging.Level.FINE;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sf.json.JSONObject;

import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.SuppressWarnings;
import hudson.util.ListBoxModel;
import java.util.List;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

/**
* Mercurial SCM.
Expand Down Expand Up @@ -81,10 +78,29 @@ public class MercurialSCM extends SCM implements Serializable {
// Same thing, but not parsed for jelly.
private final String modules;

public enum RevisionType {
BRANCH() {
@Override public String getDisplayName() {
return "Branch";
}
},
TAG() {
@Override public String getDisplayName() {
return "Tag";
}
};
public abstract String getDisplayName();
}

private RevisionType revisionType;

/**
* In-repository branch to follow. Null indicates "default".
* Revision to follow.
*/
private final String branch;
private String revision;

@Deprecated
private String branch;

/** Slash-separated subdirectory of the workspace in which the repository will be kept; null for top level. */
private final String subdir;
Expand All @@ -100,19 +116,20 @@ public MercurialSCM(String installation, String source, String branch, String mo
this(installation, source, branch, modules, subdir, browser, clean, null);
}

@DataBoundConstructor
@Deprecated
public MercurialSCM(String installation, String source, String branch, String modules, String subdir, HgBrowser browser, boolean clean, String credentialsId) {
this(installation, source, RevisionType.BRANCH, branch, modules, subdir, browser, clean, credentialsId);
}

@DataBoundConstructor public MercurialSCM(String installation, String source, @NonNull RevisionType revisionType, @NonNull String revision, String modules, String subdir, HgBrowser browser, boolean clean, String credentialsId) {
this.installation = installation;
this.source = Util.fixEmptyAndTrim(source);
this.modules = Util.fixNull(modules);
this.subdir = Util.fixEmptyAndTrim(subdir);
this.clean = clean;
parseModules();
branch = Util.fixEmpty(branch);
if (branch != null && branch.equals("default")) {
branch = null;
}
this.branch = branch;
this.revisionType = revisionType;
this.revision = Util.fixEmpty(revision) == null ? (revisionType == RevisionType.BRANCH ? "default" : "???") : revision;
this.browser = browser;
this.credentialsId = credentialsId;
}
Expand Down Expand Up @@ -141,6 +158,12 @@ private void parseModules() {
}

private Object readResolve() {
if (revisionType == null) {
revisionType = RevisionType.BRANCH;
assert revision == null;
revision = branch == null ? "default" : branch;
branch = null;
}
parseModules();
return this;
}
Expand Down Expand Up @@ -172,17 +195,26 @@ public String getCredentialsId() {
return null;
}

/**
* In-repository branch to follow. Never null.
*/
public @NonNull RevisionType getRevisionType() {
return revisionType;
}

public @NonNull String getRevision() {
return revision;
}

@Deprecated
public String getBranch() {
return branch == null ? "default" : branch;
if (revisionType != RevisionType.BRANCH) {
throw new IllegalStateException();
}
return revision;
}

/**
* Same as {@link #getBranch()} but with <em>default</em> values of parameters expanded.
* Same as {@link #getRevision()} but with <em>default</em> values of parameters expanded.
*/
private String getBranchExpanded(AbstractProject<?,?> project) {
private String getRevisionExpanded(AbstractProject<?,?> project) {
EnvVars env = new EnvVars();
ParametersDefinitionProperty params = project.getProperty(ParametersDefinitionProperty.class);
if (params != null) {
Expand All @@ -195,11 +227,11 @@ private String getBranchExpanded(AbstractProject<?,?> project) {
}
}
}
return getBranch(env);
return getRevision(env);
}

private String getBranch(EnvVars env) {
return branch == null ? "default" : env.expand(branch);
private String getRevision(EnvVars env) {
return env.expand(revision);
}

public String getSubdir() {
Expand Down Expand Up @@ -271,7 +303,7 @@ protected PollingResult compareRemoteRevisionWith(AbstractProject<?, ?> project,
Node node = project.getLastBuiltOn(); // JENKINS-5984: ugly but matches what AbstractProject.poll uses; though compare JENKINS-14247
FilePath repository = workspace2Repo(workspace);

pull(launcher, repository, listener, node, getBranchExpanded(project), credentials);
pull(launcher, repository, listener, node, getRevisionExpanded(project), credentials);

return compare(launcher, listener, baseline, output, node, repository, project);
} catch(IOException e) {
Expand Down Expand Up @@ -300,9 +332,9 @@ PollingResult compare(Launcher launcher, TaskListener listener, MercurialTagActi
}

HgExe hg = new HgExe(findInstallation(getInstallation()), getCredentials(project), launcher, node, listener, /*TODO*/new EnvVars());
String _branch = getBranchExpanded(project);
String remote = hg.tip(repository, _branch);
String rev = hg.tipNumber(repository, _branch);
String _revision = getRevisionExpanded(project);
String remote = hg.tip(repository, _revision);
String rev = hg.tipNumber(repository, _revision);

if (remote == null) {
throw new IOException("failed to find ID of branch head");
Expand All @@ -328,11 +360,13 @@ static Set<String> parseStatus(String status) {
return result;
}

private void pull(Launcher launcher, FilePath repository, TaskListener listener, Node node, String branch, StandardUsernameCredentials credentials) throws IOException, InterruptedException {
private void pull(Launcher launcher, FilePath repository, TaskListener listener, Node node, String revision, StandardUsernameCredentials credentials) throws IOException, InterruptedException {
HgExe hg = new HgExe(findInstallation(getInstallation()), credentials, launcher, node, listener, /* TODO */new EnvVars());
ArgumentListBuilder cmd = hg.seed(true);
cmd.add("pull");
cmd.add("--rev", branch);
if (revisionType == RevisionType.BRANCH) {
cmd.add("--rev", revision);
}
CachedRepo cachedSource = cachedSource(node, launcher, listener, true, credentials);
if (cachedSource != null) {
cmd.add(cachedSource.getRepoLocation());
Expand Down Expand Up @@ -565,7 +599,7 @@ private void update(AbstractBuild<?, ?> build, Launcher launcher, FilePath repos
}

private String getRevToBuild(AbstractBuild<?, ?> build, EnvVars env) {
String revToBuild = getBranch(env);
String revToBuild = getRevision(env);
if (build instanceof MatrixRun) {
MatrixRun matrixRun = (MatrixRun) build;
MercurialTagAction parentRevision = matrixRun.getParentBuild().getAction(MercurialTagAction.class);
Expand Down Expand Up @@ -601,13 +635,14 @@ private void clone(AbstractBuild<?, ?> build, Launcher launcher, FilePath reposi
args.add(cachedSource.getRepoLocation());
} else {
args.add("clone");
args.add("--rev", toRevision);
args.add("--noupdate");
args.add(cachedSource.getRepoLocation());
}
} else {
args.add("clone");
args.add("--rev", toRevision);
if (revisionType == RevisionType.BRANCH) {
args.add("--rev", toRevision);
}
args.add("--noupdate");
args.add(source);
}
Expand Down
Expand Up @@ -18,7 +18,10 @@
<f:entry field="credentialsId" title="${%Credentials}">
<c:select/>
</f:entry>
<f:entry field="branch" title="${%Branch}">
<f:entry field="revisionType" title="${%Revision Type}">
<f:enum>${it.displayName}</f:enum>
</f:entry>
<f:entry field="revision" title="${%Revision}">
<f:textbox/>
</f:entry>
<f:advanced>
Expand Down

This file was deleted.

@@ -0,0 +1,4 @@
<div>
Specify the branch or tag name you would like to track.
(If you do not type anything, the default value is the <code>default</code> branch.)
</div>
@@ -0,0 +1,3 @@
<div>
Specify the kind of revision you expect Jenkins to update your working copy to.
</div>
19 changes: 19 additions & 0 deletions src/test/java/hudson/plugins/mercurial/SCMTestBase.java
Expand Up @@ -640,6 +640,25 @@ public abstract class SCMTestBase {
}
}

@Bug(5396)
@Test public void tags() throws Exception {
m.hg(repo, "init");
m.touchAndCommit(repo, "f1");
m.touchAndCommit(repo, "f2");
m.hg(repo, "tag", "release");
m.touchAndCommit(repo, "f3");
FreeStyleProject p = j.createFreeStyleProject();
p.setScm(new MercurialSCM(hgInstallation(), repo.getPath(), MercurialSCM.RevisionType.TAG, "release", null, null, null, false, null));
FreeStyleBuild b = j.assertBuildStatusSuccess(p.scheduleBuild2(0));
FilePath ws = b.getWorkspace();
assertTrue(ws.child("f1").exists());
assertTrue(ws.child("f2").exists());
assertFalse(ws.child("f3").exists());
m.hg(repo, "tag", "--force", "release");
b = j.assertBuildStatusSuccess(p.scheduleBuild2(0));
assertTrue(JenkinsRule.getLog(b), ws.child("f3").exists());
}

private PretendSlave createNoopPretendSlave() throws Exception {
return j.createPretendSlave(new NoopFakeLauncher());
}
Expand Down

0 comments on commit a1d636a

Please sign in to comment.