Skip to content
Permalink
Browse files
Merge pull request #454 from jenkinsci/jenkins-39355-follow-up
2.6.x branch [JENKINS-39355 follow up][JENKINS-40382] Pick up SCM API 2.x
  • Loading branch information
stephenc committed Dec 16, 2016
2 parents d9e1f81 + 9452935 commit 3002ad11b13183d3118ec68cc1738206e3088808
@@ -15,7 +15,7 @@
</licenses>

<artifactId>git</artifactId>
<version>2.6.2-SNAPSHOT</version>
<version>2.6.2-beta-1-SNAPSHOT</version>
<packaging>hpi</packaging>
<name>Jenkins Git plugin</name>
<description>Integrates Jenkins with GIT SCM</description>
@@ -173,7 +173,7 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>scm-api</artifactId>
<version>1.3</version>
<version>2.0.1-beta-1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
@@ -56,13 +56,18 @@
import hudson.scm.SCM;
import hudson.security.ACL;
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.SCMSourceOwner;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -255,7 +260,7 @@ private static void _close(@NonNull Object walk) {
* This method should be removed once the code depends on git client 2.0.0.
* @param walk object whose close or release method will be called
*/
private static void _release(TreeWalk walk) throws IOException {
/*package*/ static void _release(TreeWalk walk) throws IOException {
if (walk == null) {
return;
}
@@ -273,7 +278,7 @@ private static void _release(TreeWalk walk) throws IOException {
* This method should be removed once the code depends on git client 2.0.0.
* @param walk object whose close or release method will be called
*/
private void _release(RevWalk walk) {
/*package*/ static void _release(RevWalk walk) {
if (walk == null) {
return;
}
@@ -284,34 +289,40 @@ private void _release(RevWalk walk) {
}
}

@NonNull
@Override
protected void retrieve(@NonNull final SCMHeadObserver observer,
protected void retrieve(@CheckForNull final SCMSourceCriteria criteria,
@NonNull final SCMHeadObserver observer,
@CheckForNull final SCMHeadEvent<?> event,
@NonNull final TaskListener listener)
throws IOException, InterruptedException {
doRetrieve(new Retriever<Void>() {
@Override
public Void run(GitClient client, String remoteName) throws IOException, InterruptedException {
final Repository repository = client.getRepository();
listener.getLogger().println("Getting remote branches...");
SCMSourceCriteria branchCriteria = getCriteria();
RevWalk walk = new RevWalk(repository);
try {
walk.setRetainBody(false);
for (Branch b : client.getRemoteBranches()) {
checkInterrupt();
if (!b.getName().startsWith(remoteName + "/")) {
continue;
continue;
}
final String branchName = StringUtils.removeStart(b.getName(), remoteName + "/");
listener.getLogger().println("Checking branch " + branchName);
if (isExcluded(branchName)) {
continue;
if (isExcluded(branchName)){
continue;
}
if (branchCriteria != null) {
if (criteria != null) {
RevCommit commit = walk.parseCommit(b.getSHA1());
final long lastModified = TimeUnit.SECONDS.toMillis(commit.getCommitTime());
final RevTree tree = commit.getTree();
SCMSourceCriteria.Probe probe = new SCMSourceCriteria.Probe() {
SCMSourceCriteria.Probe probe = new SCMProbe() {
@Override
public void close() throws IOException {
// no-op
}

@Override
public String name() {
return branchName;
@@ -323,16 +334,36 @@ public long lastModified() {
}

@Override
public boolean exists(@NonNull String path) throws IOException {
@NonNull
public SCMProbeStat stat(@NonNull String path) throws IOException {
TreeWalk tw = TreeWalk.forPath(repository, path, tree);
try {
return tw != null;
if (tw == null) {
return SCMProbeStat.fromType(SCMFile.Type.NONEXISTENT);
}
FileMode fileMode = tw.getFileMode(0);
if (fileMode == FileMode.MISSING) {
return SCMProbeStat.fromType(SCMFile.Type.NONEXISTENT);
}
if (fileMode == FileMode.EXECUTABLE_FILE) {
return SCMProbeStat.fromType(SCMFile.Type.REGULAR_FILE);
}
if (fileMode == FileMode.REGULAR_FILE) {
return SCMProbeStat.fromType(SCMFile.Type.REGULAR_FILE);
}
if (fileMode == FileMode.SYMLINK) {
return SCMProbeStat.fromType(SCMFile.Type.LINK);
}
if (fileMode == FileMode.TREE) {
return SCMProbeStat.fromType(SCMFile.Type.DIRECTORY);
}
return SCMProbeStat.fromType(SCMFile.Type.OTHER);
} finally {
_release(tw);
}
}
};
if (branchCriteria.isHead(probe, listener)) {
if (criteria.isHead(probe, listener)) {
listener.getLogger().println("Met criteria");
} else {
listener.getLogger().println("Does not meet criteria");
@@ -397,7 +428,7 @@ public Set<String> run(GitClient client, String remoteName) throws IOException,
}

protected String getCacheEntry() {
return "git-" + Util.getDigestOf(getRemote());
return getCacheEntry(getRemote());
}

protected static File getCacheDir(String cacheEntry) {
@@ -478,7 +509,7 @@ protected boolean isExcluded (String branchName){
/**
* Returns the pattern corresponding to the branches containing wildcards.
*
* @param branchName
* @param branches branches
* @return pattern corresponding to the branches containing wildcards
*/
private String getPattern(String branches){
@@ -500,6 +531,10 @@ private String getPattern(String branches){
return quotedBranches.toString();
}

/*package*/ static String getCacheEntry(String remote) {
return "git-" + Util.getDigestOf(remote);
}

/**
* Our implementation.
*/
@@ -0,0 +1,210 @@
/*
* 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 jenkins.plugins.git;

import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import jenkins.scm.api.SCMFile;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;

/**
* Implementation of {@link SCMFile} for Git.
*
* @since FIXME
*/
public class GitSCMFile extends SCMFile {

private final GitSCMFileSystem fs;

public GitSCMFile(GitSCMFileSystem fs) {
this.fs = fs;
}

public GitSCMFile(GitSCMFileSystem fs, @NonNull GitSCMFile parent, String name) {
super(parent, name);
this.fs = fs;
}

@NonNull
@Override
protected SCMFile newChild(String name, boolean assumeIsDirectory) {
return new GitSCMFile(fs, this, name);
}

@NonNull
@Override
public Iterable<SCMFile> children() throws IOException, InterruptedException {
return fs.invoke(new GitSCMFileSystem.FSFunction<List<SCMFile>>() {
@Override
public List<SCMFile> invoke(Repository repository) throws IOException, InterruptedException {
RevWalk walk = new RevWalk(repository);
try {
RevCommit commit = walk.parseCommit(fs.getCommitId());
RevTree tree = commit.getTree();
TreeWalk tw;
if (isRoot()) {
tw = new TreeWalk(repository);
tw.addTree(tree);
tw.setRecursive(false);
try {
List<SCMFile> result = new ArrayList<SCMFile>();
while (tw.next()) {
result.add(new GitSCMFile(fs, GitSCMFile.this, tw.getNameString()));
}
return result;
} finally {
AbstractGitSCMSource._release(tw);
}
} else {
tw = TreeWalk.forPath(repository, getPath(), tree);
if (tw == null) {
throw new FileNotFoundException();
}
try {
FileMode fileMode = tw.getFileMode(0);
if (fileMode == FileMode.MISSING) {
throw new FileNotFoundException();
}
if (fileMode != FileMode.TREE) {
throw new IOException("Not a directory");
}
tw.enterSubtree();
List<SCMFile> result = new ArrayList<SCMFile>();
while (tw.next()) {
result.add(new GitSCMFile(fs, GitSCMFile.this, tw.getNameString()));
}
return result;
} finally {
AbstractGitSCMSource._release(tw);
}
}
} finally {
AbstractGitSCMSource._release(walk);
}
}
});
}

@Override
public long lastModified() throws IOException, InterruptedException {
// TODO a more correct implementation
return fs.lastModified();
}

@NonNull
@Override
protected Type type() throws IOException, InterruptedException {
if (isRoot()) {
// special-case
return Type.DIRECTORY;
}
return fs.invoke(new GitSCMFileSystem.FSFunction<Type>() {
@Override
public Type invoke(Repository repository) throws IOException, InterruptedException {
RevWalk walk = new RevWalk(repository);
try {
RevCommit commit = walk.parseCommit(fs.getCommitId());
RevTree tree = commit.getTree();
TreeWalk tw = TreeWalk.forPath(repository, getPath(), tree);
try {
if (tw == null) {
return SCMFile.Type.NONEXISTENT;
}
FileMode fileMode = tw.getFileMode(0);
if (fileMode == FileMode.MISSING) {
return SCMFile.Type.NONEXISTENT;
}
if (fileMode == FileMode.EXECUTABLE_FILE) {
return SCMFile.Type.REGULAR_FILE;
}
if (fileMode == FileMode.REGULAR_FILE) {
return SCMFile.Type.REGULAR_FILE;
}
if (fileMode == FileMode.SYMLINK) {
return SCMFile.Type.LINK;
}
if (fileMode == FileMode.TREE) {
return SCMFile.Type.DIRECTORY;
}
return SCMFile.Type.OTHER;
} finally {
AbstractGitSCMSource._release(tw);
}
} finally {
AbstractGitSCMSource._release(walk);
}
}
});
}

@NonNull
@Override
public InputStream content() throws IOException, InterruptedException {
return fs.invoke(new GitSCMFileSystem.FSFunction<InputStream>() {
@Override
public InputStream invoke(Repository repository) throws IOException, InterruptedException {
RevWalk walk = new RevWalk(repository);
try {
RevCommit commit = walk.parseCommit(fs.getCommitId());
RevTree tree = commit.getTree();
TreeWalk tw = TreeWalk.forPath(repository, getPath(), tree);
try {
if (tw == null) {
throw new FileNotFoundException();
}
FileMode fileMode = tw.getFileMode(0);
if (fileMode == FileMode.MISSING) {
throw new FileNotFoundException();
}
if (fileMode == FileMode.TREE) {
throw new IOException("Directory");
}
ObjectId objectId = tw.getObjectId(0);
ObjectLoader loader = repository.open(objectId);
return new ByteArrayInputStream(loader.getBytes());
} finally {
AbstractGitSCMSource._release(tw);
}
} finally {
AbstractGitSCMSource._release(walk);
}
}
});
}
}

0 comments on commit 3002ad1

Please sign in to comment.