Skip to content

Commit

Permalink
Merge pull request #455 from jenkinsci/jenkins-39355-follow-up-3.x
Browse files Browse the repository at this point in the history
master branch [JENKINS-39355 follow up][JENKINS-40382] Pick up SCM API 2.x
  • Loading branch information
stephenc committed Dec 16, 2016
2 parents 37a9588 + aa89d25 commit 63a092f
Show file tree
Hide file tree
Showing 9 changed files with 992 additions and 45 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Expand Up @@ -16,7 +16,7 @@
</licenses>

<artifactId>git</artifactId>
<version>3.0.2-SNAPSHOT</version>
<version>3.0.2-beta-1-SNAPSHOT</version>
<packaging>hpi</packaging>
<name>Jenkins Git plugin</name>
<description>Integrates Jenkins with GIT SCM</description>
Expand Down Expand Up @@ -164,7 +164,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>
Expand Down
59 changes: 49 additions & 10 deletions src/main/java/jenkins/plugins/git/AbstractGitSCMSource.java
Expand Up @@ -30,6 +30,7 @@
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.EnvVars;
import hudson.Extension;
import hudson.Util;
Expand All @@ -55,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;
Expand Down Expand Up @@ -225,33 +231,39 @@ public SCMRevision run(GitClient client, String remoteName) throws IOException,
}, listener, /* we don't prune remotes here, as we just want one head's revision */false);
}

@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();
try (RevWalk walk = new RevWalk(repository)) {
walk.setRetainBody(false);
for (Branch b : client.getRemoteBranches()) {
checkInterrupt();
if (!b.getName().startsWith(remoteName + "/")) {
continue;
}
final String branchName = StringUtils.removeStart(b.getName(), remoteName + "/");
listener.getLogger().println("Checking branch " + branchName);
if (isExcluded(branchName)) {
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;
Expand All @@ -263,13 +275,36 @@ public long lastModified() {
}

@Override
public boolean exists(@NonNull String path) throws IOException {
@NonNull
@SuppressFBWarnings(value = "NP_LOAD_OF_KNOWN_NULL_VALUE",
justification = "TreeWalk.forPath can return null, compiler "
+ "generated code for try with resources handles it")
public SCMProbeStat stat(@NonNull String path) throws IOException {
try (TreeWalk tw = TreeWalk.forPath(repository, path, tree)) {
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);
}
}
};
if (branchCriteria.isHead(probe, listener)) {
if (criteria.isHead(probe, listener)) {
listener.getLogger().println("Met criteria");
} else {
listener.getLogger().println("Does not meet criteria");
Expand Down Expand Up @@ -332,7 +367,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) {
Expand Down Expand Up @@ -435,6 +470,10 @@ private String getPattern(String branches){
return quotedBranches.toString();
}

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

/**
* Our implementation.
*/
Expand Down
184 changes: 184 additions & 0 deletions src/main/java/jenkins/plugins/git/GitSCMFile.java
@@ -0,0 +1,184 @@
/*
* 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 {
try (RevWalk walk = new RevWalk(repository)) {
RevCommit commit = walk.parseCommit(fs.getCommitId());
RevTree tree = commit.getTree();
if (isRoot()) {
try (TreeWalk tw = new TreeWalk(repository)) {
tw.addTree(tree);
tw.setRecursive(false);
List<SCMFile> result = new ArrayList<SCMFile>();
while (tw.next()) {
result.add(new GitSCMFile(fs, GitSCMFile.this, tw.getNameString()));
}
return result;
}
} else {
try (TreeWalk tw = TreeWalk.forPath(repository, getPath(), tree)) {
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("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;
}
}
}
}
});
}

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

@NonNull
@Override
protected Type type() throws IOException, InterruptedException {
return fs.invoke(new GitSCMFileSystem.FSFunction<Type>() {
@Override
public Type invoke(Repository repository) throws IOException, InterruptedException {
try (RevWalk walk = new RevWalk(repository)) {
RevCommit commit = walk.parseCommit(fs.getCommitId());
RevTree tree = commit.getTree();
try (TreeWalk tw = TreeWalk.forPath(repository, getPath(), tree)) {
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;
}
}
}
});
}

@NonNull
@Override
public InputStream content() throws IOException, InterruptedException {
return fs.invoke(new GitSCMFileSystem.FSFunction<InputStream>() {
@Override
public InputStream invoke(Repository repository) throws IOException, InterruptedException {
try (RevWalk walk = new RevWalk(repository)) {
RevCommit commit = walk.parseCommit(fs.getCommitId());
RevTree tree = commit.getTree();
try (TreeWalk tw = TreeWalk.forPath(repository, getPath(), tree)) {
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());
}
}
}
});
}
}

0 comments on commit 63a092f

Please sign in to comment.