package hudson.plugins.mercurial; import hudson.EnvVars; import hudson.FilePath; import hudson.Launcher; import hudson.model.Action; import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; import hudson.model.TaskListener; import hudson.scm.PollingResult; import hudson.util.ArgumentListBuilder; import hudson.util.StreamTaskListener; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Set; import java.util.TreeSet; import org.junit.Assume; import org.junit.internal.AssumptionViolatedException; import org.junit.rules.ExternalResource; import org.jvnet.hudson.test.JenkinsRule; import static org.junit.Assert.*; public final class MercurialRule extends ExternalResource { private TaskListener listener; private final JenkinsRule j; public MercurialRule(JenkinsRule j) { this.j = j; } @Override protected void before() throws Exception { listener = new StreamTaskListener(System.out, Charset.defaultCharset()); try { if (new ProcessBuilder("hg", "--version").start().waitFor() != 0) { throw new AssumptionViolatedException("hg --version signaled an error"); } } catch(IOException ioe) { String message = ioe.getMessage(); if(message.startsWith("Cannot run program \"hg\"") && message.endsWith("No such file or directory")) { throw new AssumptionViolatedException("hg is not available; please check that your PATH environment variable is properly configured"); } Assume.assumeNoException(ioe); // failed to check availability of hg } } private Launcher launcher() { return j.jenkins.createLauncher(listener); } private HgExe hgExe() throws Exception { return new HgExe(null, null, launcher(), j.jenkins, listener, new EnvVars()); } private HgExe hgExe(EnvVars env) throws Exception { return new HgExe(null, null, launcher(), j.jenkins, listener, env); } public void hg(String... args) throws Exception { HgExe hg = hgExe(); assertEquals(0, hg.launch(nobody(hg.seed(false)).add(args)).join()); } public void hg(File repo, String... args) throws Exception { HgExe hg = hgExe(); assertEquals(0, hg.launch(nobody(hg.seed(false)).add(args)).pwd(repo).join()); } public void hg(File repo, EnvVars env, String... args) throws Exception { HgExe hg = hgExe(env); assertEquals(0, hg.launch(nobody(hg.seed(false)).add(args)).envs( env ).pwd(new File(env.expand(repo.getPath()))).join()); } private static ArgumentListBuilder nobody(ArgumentListBuilder args) { return args.add("--config").add("ui.username=nobody@nowhere.net"); } public void touchAndCommit(File repo, String... names) throws Exception { for (String name : names) { FilePath toTouch = new FilePath(repo).child(name); if (!toTouch.exists()) { toTouch.getParent().mkdirs(); toTouch.touch(0); hg(repo, "add", name); } else { toTouch.write(toTouch.readToString() + "extra line\n", "UTF-8"); } } hg(repo, "commit", "--message", "added " + Arrays.toString(names)); } public String buildAndCheck(FreeStyleProject p, String name, Action... actions) throws Exception { FreeStyleBuild b = j.assertBuildStatusSuccess(p.scheduleBuild2(0, null, actions).get()); // for (String line : b.getLog(Integer.MAX_VALUE)) { // System.err.println(">> " + line); // } if (!b.getWorkspace().child(name).exists()) { Set<String> children = new TreeSet<String>(); for (FilePath child : b.getWorkspace().list()) { children.add(child.getName()); } fail("Could not find " + name + " among " + children); } assertNotNull(b.getAction(MercurialTagAction.class)); @SuppressWarnings("deprecation") String log = b.getLog(); return log; } public PollingResult pollSCMChanges(FreeStyleProject p) { return p.poll(new StreamTaskListener(System.out, Charset .defaultCharset())); } public String getLastChangesetId(File repo) throws Exception { return hgExe().popen(new FilePath(repo), listener, false, new ArgumentListBuilder("log", "-l1", "--template", "{node}")); } public long getLastChangesetUnixTimestamp(File repo) throws Exception { //hgdate returns the date as a pair of numbers: "1157407993 25200" (Unix timestamp, timezone offset). String date = hgExe().popen(new FilePath(repo), listener, false, new ArgumentListBuilder("log", "-l1", "--template", "{date|hgdate}")); return Long.valueOf(date.split(" ")[0]); } }