Skip to content
Permalink
Browse files
Merged #92: [JENKINS-39355] Adapt to SCM API 2.0 APIs.
  • Loading branch information
jglick committed Jan 13, 2017
2 parents fc28fbf + 0fda141 commit 6d67081720f6732ae4c0f176eabbc92e713dbdd3
20 pom.xml
@@ -7,7 +7,7 @@
<relativePath/>
</parent>
<artifactId>mercurial</artifactId>
<version>1.58-SNAPSHOT</version>
<version>1.58-beta-1-SNAPSHOT</version>
<packaging>hpi</packaging>
<name>Jenkins Mercurial plugin</name>
<description>Allows Jenkins to check out projects from the Mercurial SCM.</description>
@@ -16,6 +16,7 @@
<properties>
<jenkins.version>1.642.3</jenkins.version>
<no-test-jar>false</no-test-jar>
<scm-api.version>2.0.1-beta-3</scm-api.version>
</properties>

<developers>
@@ -81,12 +82,12 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>credentials</artifactId>
<version>1.9.4</version>
<version>2.1.10</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>scm-api</artifactId>
<version>1.1</version>
<version>${scm-api.version}</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
@@ -120,6 +121,19 @@
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>scm-api</artifactId>
<version>${scm-api.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>branch-api</artifactId>
<version>2.0.0-beta-4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-multibranch</artifactId>
@@ -0,0 +1,103 @@
/*
* The MIT License
*
* Copyright (c) 2016 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

package hudson.plugins.mercurial;

import java.io.Serializable;
import java.net.URI;
import javax.annotation.Nonnull;
import jenkins.scm.api.SCMHeadEvent;

/**
* Payload for a {@link SCMHeadEvent}
*
* @since 1.58-beta-1
*/
public class MercurialCommitPayload implements Serializable {
@Nonnull
private final URI url;
@Nonnull
private final String branch;
@Nonnull
private final String changesetId;

public MercurialCommitPayload(@Nonnull URI url, @Nonnull String branch, @Nonnull String commitId) {
this.url = url;
this.branch = branch;
this.changesetId = commitId;
}

@Nonnull
public URI getUrl() {
return url;
}

@Nonnull
public String getBranch() {
return branch;
}

@Nonnull
public String getChangesetId() {
return changesetId;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

MercurialCommitPayload that = (MercurialCommitPayload) o;

if (!url.equals(that.url)) {
return false;
}
if (!branch.equals(that.branch)) {
return false;
}
return changesetId.equals(that.changesetId);
}

@Override
public int hashCode() {
int result = url.hashCode();
result = 31 * result + branch.hashCode();
result = 31 * result + changesetId.hashCode();
return result;
}

@Override
public String toString() {
return "MercurialCommitPayload{" +
"url='" + url+ '\'' +
", branch='" + branch + '\'' +
", commitId='" + changesetId + '\'' +
'}';
}
}
@@ -0,0 +1,97 @@
/*
* The MIT License
*
* Copyright (c) 2016 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

package hudson.plugins.mercurial;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.scm.SCM;
import java.util.Collections;
import java.util.Map;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMHeadEvent;
import jenkins.scm.api.SCMNavigator;
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.SCMSource;
import org.apache.commons.io.FilenameUtils;

/**
* Implementation of {@link SCMHeadEvent} for {@link MercurialSCM} / {@link MercurialSCMSource}.
*
* @since 1.58-beta-1
*/
public class MercurialSCMHeadEvent extends SCMHeadEvent<MercurialCommitPayload> {
private final MercurialCommitPayload payload;

public MercurialSCMHeadEvent(Type type, MercurialCommitPayload payload) {
super(type, payload);
this.payload = payload;
}

@Override
public boolean isMatch(@NonNull SCMNavigator navigator) {
return false; // because we do not have a Mercurial SCM Navigator
}

@NonNull
@Override
public String getSourceName() {
// doesn't matter what we return here as we never match a navigator.
return FilenameUtils.getBaseName(payload.getUrl().getPath());
}

@NonNull
@Override
public Map<SCMHead, SCMRevision> heads(@NonNull SCMSource source) {
if (source instanceof MercurialSCMSource) {
MercurialSCMSource hg = (MercurialSCMSource) source;
String repository = hg.getSource();
if (repository != null) {
if (MercurialStatus.looselyMatches(payload.getUrl(), repository)) {
SCMHead head = new SCMHead(getPayload().getBranch());
SCMRevision revision = new MercurialSCMSource.MercurialRevision(
head, getPayload().getChangesetId()
);
return Collections.singletonMap(head, revision);
}
}
}
return Collections.emptyMap();
}

@Override
public boolean isMatch(@NonNull SCM scm) {
if (scm instanceof MercurialSCM) {
MercurialSCM hg = (MercurialSCM) scm;
String repository = hg.getSource();
if (repository != null) {
if (MercurialStatus.looselyMatches(payload.getUrl(), repository)) {
return hg.getRevisionType() == MercurialSCM.RevisionType.BRANCH
&& payload.getBranch().equals(hg.getRevision());
}
}
}
return false;
}
}
@@ -4,6 +4,7 @@
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
import com.cloudbees.plugins.credentials.common.StandardUsernameListBoxModel;
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressWarnings;
import hudson.EnvVars;
import hudson.Extension;
@@ -21,18 +22,25 @@
import hudson.util.ArgumentListBuilder;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import hudson.util.VersionNumber;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.annotation.CheckForNull;
import jenkins.model.Jenkins;
import jenkins.scm.api.SCMFile;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMHeadEvent;
import jenkins.scm.api.SCMHeadObserver;
import jenkins.scm.api.SCMProbe;
import jenkins.scm.api.SCMProbeStat;
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.SCMSource;
import jenkins.scm.api.SCMSourceCriteria;
import jenkins.scm.api.SCMSourceDescriptor;
import jenkins.scm.api.SCMSourceOwner;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
@@ -95,7 +103,10 @@ public boolean isClean() {
}

@Override
protected void retrieve(SCMHeadObserver observer, TaskListener listener) throws IOException, InterruptedException {
protected void retrieve(@edu.umd.cs.findbugs.annotations.CheckForNull SCMSourceCriteria criteria,
@NonNull SCMHeadObserver observer,
@edu.umd.cs.findbugs.annotations.CheckForNull SCMHeadEvent<?> event,
@NonNull final TaskListener listener) throws IOException, InterruptedException {
MercurialInstallation inst = MercurialSCM.findInstallation(installation);
if (inst == null) {
listener.error("No configured Mercurial installation");
@@ -112,27 +123,65 @@ protected void retrieve(SCMHeadObserver observer, TaskListener listener) throws
}
Launcher launcher = node.createLauncher(listener);
StandardUsernameCredentials credentials = getCredentials();
FilePath cache = Cache.fromURL(source, credentials).repositoryCache(inst, node, launcher, listener, true);
final FilePath cache = Cache.fromURL(source, credentials).repositoryCache(inst, node, launcher, listener, true);
if (cache == null) {
listener.error("Could not use caches, not fetching branch heads");
return;
}
HgExe hg = new HgExe(inst, credentials, launcher, node, listener, new EnvVars());
final HgExe hg = new HgExe(inst, credentials, launcher, node, listener, new EnvVars());
try {
String heads = hg.popen(cache, listener, true, new ArgumentListBuilder("heads", "--template", "{node} {branch}\\n"));
// TODO need to consider getCriteria() here as well
Pattern p = Pattern.compile(Util.fixNull(branchPattern).length() == 0 ? ".+" : branchPattern);
for (String line : heads.split("\r?\n")) {
String[] nodeBranch = line.split(" ", 2);
String name = nodeBranch[1];
if (p.matcher(name).matches()) {
listener.getLogger().println("Found branch " + name);
SCMHead branch = new SCMHead(name);
observer.observe(branch, new MercurialRevision(branch, nodeBranch[0]));
} else {
listener.getLogger().println("Ignoring branch " + name);
String heads = hg.popen(cache, listener, true, new ArgumentListBuilder("heads", "--template", "{node} {branch}\\n"));
Pattern p = Pattern.compile(Util.fixNull(branchPattern).length() == 0 ? ".+" : branchPattern);
for (String line : heads.split("\r?\n")) {
final String[] nodeBranch = line.split(" ", 2);
final String name = nodeBranch[1];
if (p.matcher(name).matches()) {
listener.getLogger().println("Found branch " + name);
SCMHead branch = new SCMHead(name);
if (criteria != null) {
SCMProbe probe = new SCMProbe() {
@NonNull
@Override
public SCMProbeStat stat(@NonNull String path) throws IOException {
try {
String files = hg.popen(cache, listener, true,
new ArgumentListBuilder("locate", "-r", nodeBranch[0], "-I", "path:" + path));
if (StringUtils.isBlank(files)) {
return SCMProbeStat.fromType(SCMFile.Type.NONEXISTENT);
}
return SCMProbeStat.fromType(SCMFile.Type.REGULAR_FILE);
} catch (InterruptedException e) {
throw new IOException(e);
}
}

@Override
public void close() throws IOException {

}

@Override
public String name() {
return name;
}

@Override
public long lastModified() {
return 0;
}
};
if (criteria.isHead(probe, listener)) {
listener.getLogger().println("Met criteria");
} else {
listener.getLogger().println("Does not meet criteria");
continue;
}
}
observer.observe(branch, new MercurialRevision(branch, nodeBranch[0]));
} else {
listener.getLogger().println("Ignoring branch " + name);
}
}
}
} finally {
hg.close();
}
@@ -189,7 +238,7 @@ public List<Descriptor<RepositoryBrowser<?>>> getBrowserDescriptors() {

}

private static final class MercurialRevision extends SCMRevision {
/*package*/ static final class MercurialRevision extends SCMRevision {
private final String hash;
MercurialRevision(SCMHead branch, String hash) {
super(branch);

0 comments on commit 6d67081

Please sign in to comment.