Skip to content

feat: Be able to retrieve and build a PR from same the origin repository #263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
<version>2.12.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-guava</artifactId>
<version>2.12.3</version>
<version>2.12.4</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
Expand All @@ -123,7 +123,7 @@
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>tuleap-api</artifactId>
<version>2.3.0</version>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
Expand All @@ -148,7 +148,7 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.10.0</version>
<version>2.11.0</version>
<scope>compile</scope>
</dependency>
<!-- tests -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.jenkinsci.plugins.tuleap_git_branch_source;

import edu.umd.cs.findbugs.annotations.NonNull;
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.mixin.ChangeRequestSCMRevision;
import org.jetbrains.annotations.NotNull;

public class TuleapPullRequestRevision extends ChangeRequestSCMRevision<TuleapPullRequestSCMHead> {

private final TuleapBranchSCMRevision origin;

public TuleapPullRequestRevision(@NotNull TuleapPullRequestSCMHead head, @NotNull TuleapBranchSCMRevision target, @NonNull TuleapBranchSCMRevision origin) {
super(head, target);
this.origin = origin;
}

@Override
public boolean equivalent(ChangeRequestSCMRevision<?> revision) {
if(!(revision instanceof TuleapPullRequestRevision)){
return false;
}
TuleapPullRequestRevision tlpRevision = (TuleapPullRequestRevision) revision;
return this.origin.equals(tlpRevision.getOrigin());
}

@Override
protected int _hashCode() {
return this.origin.hashCode();
}

public SCMRevision getOrigin() {
return origin;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.jenkinsci.plugins.tuleap_git_branch_source;

import edu.umd.cs.findbugs.annotations.NonNull;
import io.jenkins.plugins.tuleap_api.client.GitPullRequest;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMHeadOrigin;
import jenkins.scm.api.mixin.ChangeRequestCheckoutStrategy;
import jenkins.scm.api.mixin.ChangeRequestSCMHead2;
import org.jetbrains.annotations.NotNull;

public class TuleapPullRequestSCMHead extends SCMHead implements ChangeRequestSCMHead2 {

private final GitPullRequest pullRequest;
private final SCMHeadOrigin origin;
private final TuleapBranchSCMHead target;

public TuleapPullRequestSCMHead(GitPullRequest pullRequest, SCMHeadOrigin origin, TuleapBranchSCMHead target) {
super("TLP-PR-" + pullRequest.getId());
this.pullRequest = pullRequest;
this.origin = origin;
this.target = target;
}

@NotNull
@Override
public ChangeRequestCheckoutStrategy getCheckoutStrategy() {
return ChangeRequestCheckoutStrategy.HEAD;
}

@NotNull
@Override
public String getOriginName() {
return this.pullRequest.getSourceBranch();
}

@NotNull
@Override
public String getId() {
return this.pullRequest.getId();
}

@NonNull
@Override
public SCMHeadOrigin getOrigin() {
return this.origin;
}

@NonNull
@Override
public SCMHead getTarget() {
return this.target;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.jenkinsci.plugins.tuleap_git_branch_source;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.plugins.git.GitSCM;
import jenkins.plugins.git.GitSCMBuilder;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMRevision;
import org.jetbrains.annotations.NotNull;

public class TuleapSCMBuilder extends GitSCMBuilder<TuleapSCMBuilder> {
public TuleapSCMBuilder(@NotNull SCMHead head, SCMRevision revision, @NotNull String remote, String credentialsId) {
super(head, revision, remote, credentialsId);
withoutRefSpecs();
if (head instanceof TuleapPullRequestSCMHead) {
TuleapPullRequestSCMHead tuleapPullRequestSCMHead = (TuleapPullRequestSCMHead) head;
withRefSpec("+refs/tlpr/" + tuleapPullRequestSCMHead.getId() + "/head:refs/remotes/@{remote}/" + tuleapPullRequestSCMHead.getName());
} else {
withRefSpec("+refs/heads/" + head.getName() + ":refs/remotes/@{remote}/" + head.getName());
}
}

@NonNull
@Override
public GitSCM build() {
final SCMHead head = head();
final SCMRevision revision = revision();
try {
if (head instanceof TuleapPullRequestSCMHead && revision instanceof TuleapPullRequestRevision) {
withRevision(((TuleapPullRequestRevision) revision).getOrigin());
}
return super.build();
} finally {
withHead(head);
withRevision(revision);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import hudson.scm.SCM;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import io.jenkins.plugins.tuleap_api.client.*;
import io.jenkins.plugins.tuleap_api.deprecated_client.TuleapClientCommandConfigurer;
import io.jenkins.plugins.tuleap_api.deprecated_client.TuleapClientRawCmd;
import io.jenkins.plugins.tuleap_api.deprecated_client.api.TuleapBranches;
Expand All @@ -28,8 +29,9 @@
import jenkins.scm.api.trait.SCMSourceTrait;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.tuleap_git_branch_source.config.TuleapSCMFileSystem;
import org.jenkinsci.plugins.tuleap_git_branch_source.helpers.TuleapApiRetriever;
import org.jenkinsci.plugins.tuleap_git_branch_source.trait.TuleapBranchDiscoveryTrait;
import org.jenkinsci.plugins.tuleap_git_branch_source.trait.TuleapPullRequestDiscoveryTrait;
import org.jenkinsci.plugins.tuleap_git_branch_source.trait.TuleapOriginPullRequestDiscoveryTrait;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.kohsuke.accmod.Restricted;
Expand Down Expand Up @@ -101,9 +103,15 @@ protected List<Action> retrieveActions(@NonNull SCMHead head, @CheckForNull SCMH
if (owner instanceof Actionable) {
TuleapLink repoLink = ((Actionable) owner).getAction(TuleapLink.class);
if (repoLink != null) {
String canonicalRepoName = repositoryPath.replace(project.getShortname()+"/", "");
String url = repoLink.getUrl() + "?p=" + canonicalRepoName + "&a=shortlog&h=" + head.getName();
result.add(new TuleapLink("icon-git-branch", url));
if(head instanceof TuleapBranchSCMHead) {
String canonicalRepoName = repositoryPath.replace(project.getShortname() + "/", "");
String url = repoLink.getUrl() + "?p=" + canonicalRepoName + "&a=shortlog&h=" + head.getName();
result.add(new TuleapLink("icon-git-branch", url));
} else if (head instanceof TuleapPullRequestSCMHead){
TuleapPullRequestSCMHead tuleapPullRequestSCMHead = (TuleapPullRequestSCMHead) head;
String prUrl = this.getGitBaseUri()+"?action=pull-requests&repo_id="+this.repository.getId()+"&group_id="+this.projectId+"#/pull-requests/"+tuleapPullRequestSCMHead.getId()+"/overview";
result.add(new TuleapLink("icon-git-branch", prUrl));
}
}
}
return result;
Expand Down Expand Up @@ -164,8 +172,54 @@ public SCMSourceCriteria.Probe create(@NotNull TuleapBranchSCMHead head, @Nullab
}

}
if(request.isRetrievePullRequests()){
request.listener().getLogger().format("Retrieving pull request for repository at %s %n", repositoryPath);
if (request.isRetrieveOriginPullRequests()) {
request.listener().getLogger().format("Fetching pull requests for repository at %s %n", this.repositoryPath);
GitApi gitApi = TuleapApiRetriever.getGitApi();

List<GitPullRequest> pullRequests = gitApi.getPullRequests(Integer.toString(this.repository.getId()), this.credentials);
int prCount = 0;
for (GitPullRequest pullRequest : pullRequests) {
request.listener().getLogger().format("Check the PR id: '%s' %n", pullRequest.getId());
prCount++;
boolean isFork = !pullRequest.getSourceRepository().getId().equals(pullRequest.getDestinationRepository().getId());
if (isFork) {
request.listener().getLogger().println("Skipping: Pull Request from User fork are not supported yet");
continue;
}
TuleapBranchSCMHead targetBranch = new TuleapBranchSCMHead(pullRequest.getDestinationBranch());
SCMHeadOrigin origin = SCMHeadOrigin.DEFAULT;

TuleapPullRequestSCMHead tlpPRSCMHead = new TuleapPullRequestSCMHead(pullRequest, origin, targetBranch);
GitCommit targetLastCommit = gitApi.getCommit(Integer.toString(this.repository.getId()), targetBranch.getName(), this.credentials);
if (request.process(tlpPRSCMHead,
(SCMSourceRequest.RevisionLambda<TuleapPullRequestSCMHead, TuleapPullRequestRevision>) head ->
new TuleapPullRequestRevision(
head,
new TuleapBranchSCMRevision(
head.getTarget(),
targetLastCommit.getHash()
),
new TuleapBranchSCMRevision(
new TuleapBranchSCMHead(head.getOriginName()),
pullRequest.getHead().getId()
)
),
new SCMSourceRequest.ProbeLambda<TuleapPullRequestSCMHead, TuleapPullRequestRevision>() {
@NotNull
@Override
public SCMSourceCriteria.Probe create(@NotNull TuleapPullRequestSCMHead head, @Nullable TuleapPullRequestRevision revisionInfo) throws IOException, InterruptedException {
boolean isTrusted = request.isTrusted(head);
if (!isTrusted) {
listener.getLogger().println("This pull request is not from a trusted source");
}
return createProbe(isTrusted ? head : head.getTarget(), revisionInfo);
}
},
new OFWitness(listener))) {
request.listener().getLogger()
.format("%n %d branches were processed (query completed)%n", prCount).println();
}
}
}
}
}
Expand All @@ -174,6 +228,7 @@ public SCMSourceCriteria.Probe create(@NotNull TuleapBranchSCMHead head, @Nullab
@Override
protected SCMProbe createProbe(@NonNull final SCMHead head, SCMRevision revision) throws IOException {
TuleapSCMFileSystem.BuilderImpl tuleapFileSystemBuilder = ExtensionList.lookup(SCMFileSystem.Builder.class).get(TuleapSCMFileSystem.BuilderImpl.class);

if (tuleapFileSystemBuilder == null) {
throw new IOException("Error while retrieving the tfs");
}
Expand Down Expand Up @@ -211,27 +266,66 @@ public long lastModified() {
};
}

@NonNull
@Override
protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOException, InterruptedException {
Optional<String> revision = Optional.empty();
Stream<TuleapBranches> branches = TuleapClientCommandConfigurer.<Stream<TuleapBranches>>newInstance(getApiBaseUri())
.withCredentials(credentials)
.withCommand(new TuleapClientRawCmd.Branches(this.repository.getId()))
.configure()
.call();
Optional<TuleapBranches> branch = branches.filter(b -> b.getName().equals(head.getName()))
.findFirst();
if (branch.isPresent()) {
revision = Optional.of(branch.get().getCommit().getId());
} else {
listener.getLogger().format("Cannot find the branch %s in repo : %s", head.getName(), repositoryPath);
public SCMRevision getTrustedRevision(@NonNull SCMRevision revision, @NonNull TaskListener listener)
throws IOException, InterruptedException {
if (revision instanceof TuleapPullRequestRevision) {
TuleapPullRequestSCMHead head = (TuleapPullRequestSCMHead) revision.getHead();

try (TuleapSCMSourceRequest request = new TuleapSCMSourceContext(null, SCMHeadObserver.none())
.withTraits(traits)
.newRequest(this, listener)) {
if (request.isTrusted(head)) {
return revision;
}
}
TuleapPullRequestRevision rev = (TuleapPullRequestRevision) revision;
listener.getLogger().format("Loading trusted files from target branch %s at %s rather than %s%n",
head.getTarget().getName(), rev.getTarget(), rev.getOrigin().getHead().getName());
return rev.getTarget();
}
if (revision.isPresent()) {
return new SCMRevisionImpl(head, revision.get());
} else {
listener.getLogger().format("Cannot resolve the hash of the revision in branch %s%n", head.getName());
return null;
return revision;
}

@Override
protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOException, InterruptedException {

if (head instanceof TuleapBranchSCMHead) {
Optional<String> revision = Optional.empty();
Stream<TuleapBranches> branches = TuleapClientCommandConfigurer.<Stream<TuleapBranches>>newInstance(getApiBaseUri())
.withCredentials(credentials)
.withCommand(new TuleapClientRawCmd.Branches(this.repository.getId()))
.configure()
.call();
Optional<TuleapBranches> branch = branches.filter(b -> b.getName().equals(head.getName()))
.findFirst();
if (branch.isPresent()) {
revision = Optional.of(branch.get().getCommit().getId());
} else {
listener.getLogger().format("Cannot find the branch %s in repo : %s", head.getName(), repositoryPath);
}
if (revision.isPresent()) {
return new SCMRevisionImpl(head, revision.get());
}
} else if (head instanceof TuleapPullRequestSCMHead) {
TuleapPullRequestSCMHead tlpSCMHead = (TuleapPullRequestSCMHead) head;
PullRequest pullRequest = TuleapApiRetriever.getPullRequestApi().getPullRequest(tlpSCMHead.getId(), this.credentials);
String targetReference = pullRequest.getDestinationReference();
return new TuleapPullRequestRevision(
tlpSCMHead,
new TuleapBranchSCMRevision(
tlpSCMHead.getTarget(),
targetReference),
new TuleapBranchSCMRevision(
new TuleapBranchSCMHead(
tlpSCMHead.getOriginName()),
pullRequest.getHead().getId()
)
);
}
listener.getLogger().format("Cannot resolve the hash of the revision in branch %s%n", head.getName());
return null;
}

/**
Expand All @@ -252,9 +346,10 @@ public void setCredentials(TuleapAccessToken credentials) {
this.credentials = credentials;
}

@NotNull
@Override
public SCM build(@NonNull SCMHead scmHead, @CheckForNull SCMRevision scmRevision) {
return new GitSCMBuilder(scmHead, scmRevision, remoteUrl, credentialsId).withTraits(traits).build();
return new TuleapSCMBuilder(scmHead, scmRevision, remoteUrl, credentialsId).withTraits(traits).build();
}

public List<SCMSourceTrait> getTraits() {
Expand Down Expand Up @@ -345,7 +440,7 @@ public String getDisplayName() {
}

public List<SCMSourceTrait> getTraitsDefaults() {
return Arrays.asList(new TuleapBranchDiscoveryTrait(), new TuleapPullRequestDiscoveryTrait(), new RefSpecsSCMSourceTrait());
return Arrays.asList(new TuleapBranchDiscoveryTrait(), new TuleapOriginPullRequestDiscoveryTrait(), new RefSpecsSCMSourceTrait());
}

@RequirePOST
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class TuleapSCMSourceContext extends SCMSourceContext<TuleapSCMSourceCont

private boolean notifyPullRequest = false;

private boolean wantPullRequests = false;
private boolean wantOriginPullRequests = false;

public TuleapSCMSourceContext(@CheckForNull SCMSourceCriteria criteria, @NonNull SCMHeadObserver observer) {
super(criteria, observer);
Expand All @@ -40,7 +40,7 @@ public final boolean isNotifyPullRequest() {
return this.notifyPullRequest;
}

public final boolean wantPullRequests() {return this.wantPullRequests; }
public final boolean wantOriginPullRequests() {return this.wantOriginPullRequests; }

/**
* Adds a requirement for branch details to any {@link TuleapSCMSourceContext} for this context.
Expand All @@ -63,8 +63,8 @@ public TuleapSCMSourceContext notifyPullRequest(boolean notify) {
}

@NonNull
public TuleapSCMSourceContext wantPullRequests(boolean include) {
this.wantPullRequests = this.wantPullRequests || include;
public TuleapSCMSourceContext wantOriginPullRequests(boolean include) {
this.wantOriginPullRequests = this.wantOriginPullRequests || include;
return this;
}

Expand Down
Loading