Skip to content
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
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,16 @@ multibranchPipelineJob('heart-of-gold') {
repository('spaceships/heart-of-gold')
discoverBranches(true)
discoverPullRequest(true)
excludeDraftPullRequests(false)
discoverTags(false)
}
}
}
```

The parameters `discoverBranches`, `discoverPullRequest` and `discoverTags` are optional
and describe which heads of the repository are build.
The parameters `discoverBranches`, `discoverPullRequest`, `excludeDraftPullRequests` and `discoverTags` are optional
and describe which heads of the repository are built.
When `excludeDraftPullRequests` is `true`, SCM-Manager pull requests with status `DRAFT` are not built.
The example shows the default values.

Have a look at the following example for a Subversion repository:
Expand Down Expand Up @@ -153,6 +155,7 @@ organizationFolder("spaceships") {
namespace("spaceships")
discoverBranches(true)
discoverPullRequest(true)
excludeDraftPullRequests(false)
discoverTags(false)
discoverSvn {
includes("trunk,branches/*,tags/*,sandbox/*")
Expand All @@ -165,7 +168,8 @@ organizationFolder("spaceships") {
queue("spaceships")
```

The `discover*` parameters are optional, the example above shows the default values.
The `discover*` parameters and `excludeDraftPullRequests` are optional, the example above shows the default values.
When `excludeDraftPullRequests` is `true`, SCM-Manager pull requests with status `DRAFT` are not built.
To disable subversion builds, a `false` can be passed to the `discoverSvn` method e.g.: `discoverSvn(false)`.
To build all namespaces of the SCM-Manager instance, the pseudo namespace `--all--` can be used.

Expand Down
8 changes: 6 additions & 2 deletions docs/de/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,15 @@ multibranchPipelineJob('heart-of-gold') {
repository('spaceships/heart-of-gold')
discoverBranches(true)
discoverPullRequest(true)
excludeDraftPullRequests(false)
discoverTags(false)
}
}
}
```

Die Parameter `discoverBranches`, `discoverPullRequest` und `discoverTags` sind optional und bilden ab, welche Typen gebaut werden sollen.
Die Parameter `discoverBranches`, `discoverPullRequest`, `excludeDraftPullRequests` und `discoverTags` sind optional und bilden ab, welche Typen gebaut werden sollen.
Wenn `excludeDraftPullRequests` auf `true` gesetzt ist, werden SCM-Manager-Pull-Requests mit dem Status `DRAFT` nicht gebaut.
Das Beispiel zeigt die Standardwerte.

Die Syntax für ein Subversion-Repository zeigt folgendes Beispiel:
Expand Down Expand Up @@ -142,6 +144,7 @@ organizationFolder("spaceships") {
namespace("spaceships")
discoverBranches(true)
discoverPullRequest(true)
excludeDraftPullRequests(false)
discoverTags(false)
discoverSvn {
includes("trunk,branches/*,tags/*,sandbox/*")
Expand All @@ -153,7 +156,8 @@ organizationFolder("spaceships") {
// scan namespace directly after creation
queue("spaceships")
```
Die `discover*`-Parameter sind optional und das Beispiel zeigt die Standardwerte.
Die `discover*`-Parameter und `excludeDraftPullRequests` sind optional und das Beispiel zeigt die Standardwerte.
Wenn `excludeDraftPullRequests` auf `true` gesetzt ist, werden SCM-Manager-Pull-Requests mit dem Status `DRAFT` nicht gebaut.
Um Subversion-Builds zu deaktivieren, kann der `discoverSvn`-Methode ein `false` übergeben werden: `discoverSvn(false)`.
Um alle Namespaces zu bauen, kann der Pseudo-Namespace `--all--` verwendet werden.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,24 @@
import jenkins.scm.impl.ChangeRequestSCMHeadCategory;
import jenkins.scm.impl.trait.Discovery;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

public class PullRequestDiscoveryTrait extends SCMSourceTrait {

private final boolean excludeBranchesWithPRs;

private boolean excludeDraftPullRequests;

@DataBoundConstructor
public PullRequestDiscoveryTrait(boolean excludeBranchesWithPRs) {
this.excludeBranchesWithPRs = excludeBranchesWithPRs;
}

public PullRequestDiscoveryTrait(boolean excludeBranchesWithPRs, boolean excludeDraftPullRequests) {
this(excludeBranchesWithPRs);
this.excludeDraftPullRequests = excludeDraftPullRequests;
}

/**
* Constructor for old versions of this trait, which does not have the excludeBranchesWithPRs option.
*/
Expand All @@ -38,6 +46,15 @@
return excludeBranchesWithPRs;
}

public boolean isExcludeDraftPullRequests() {
return excludeDraftPullRequests;
}

@DataBoundSetter
public void setExcludeDraftPullRequests(boolean excludeDraftPullRequests) {
this.excludeDraftPullRequests = excludeDraftPullRequests;
}

Check warning on line 56 in src/main/java/com/cloudogu/scmmanager/scm/PullRequestDiscoveryTrait.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 55-56 are not covered by tests

@Override
protected void decorateContext(SCMSourceContext<?, ?> context) {
ScmManagerSourceContext scmContext = (ScmManagerSourceContext) context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.trait.SCMSourceTrait;
Expand All @@ -44,7 +45,10 @@
CompletableFuture<? extends ScmManagerObservable> candidate =
getSpecificCandidateFromSourceControl(request, head);
if (candidate != null) {
return Collections.singleton(candidate.get());
ScmManagerObservable observable = candidate.get();
if (observable != null) {
return Collections.singleton(observable);
}
}
} catch (ExecutionException e) {
ExecutionExceptions.log(e);
Expand All @@ -62,7 +66,11 @@
}
} else if (head instanceof ScmManagerPullRequestHead) {
if (request.isFetchPullRequests()) {
return api.getPullRequest(repository, ((ScmManagerPullRequestHead) head).getId());
CompletableFuture<PullRequest> pullRequest =
api.getPullRequest(repository, ((ScmManagerPullRequestHead) head).getId());
if (pullRequest != null) {

Check warning on line 71 in src/main/java/com/cloudogu/scmmanager/scm/ScmManagerSourceRetriever.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 71 is only partially covered, one branch is missing
return pullRequest.thenApply(this::ignoreDraftPullRequestIfNecessary);
}
}
} else if (head instanceof ScmManagerHead && request.isFetchBranches()) {
if (shouldIgnoreBranchBecauseRelatedPullRequestExists(head.getName())) {
Expand All @@ -74,16 +82,39 @@
return null;
}

private PullRequest ignoreDraftPullRequestIfNecessary(PullRequest pullRequest) {
if (shouldExcludeDraftPullRequest(pullRequest)) {
return null;
}
return pullRequest;
}

private boolean shouldIgnoreBranchBecauseRelatedPullRequestExists(String branchName) {
if (traits.stream()
.anyMatch(t -> t instanceof PullRequestDiscoveryTrait
&& ((PullRequestDiscoveryTrait) t).isExcludeBranchesWithPRs())) {
if (excludeBranchesWithPRs()) {
CompletableFuture<List<PullRequest>> pullRequests = api.getPullRequests(repository);
return pullRequests.join().stream().anyMatch(p -> p.getSource().equals(branchName));
return pullRequests.join().stream()
.filter(pullRequest -> !shouldExcludeDraftPullRequest(pullRequest))
.anyMatch(p -> p.getSource().equals(branchName));
}
return false;
}

private boolean excludeBranchesWithPRs() {
return traits.stream()
.anyMatch(t -> t instanceof PullRequestDiscoveryTrait

Check warning on line 104 in src/main/java/com/cloudogu/scmmanager/scm/ScmManagerSourceRetriever.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 104 is only partially covered, one branch is missing
&& ((PullRequestDiscoveryTrait) t).isExcludeBranchesWithPRs());

Check warning on line 105 in src/main/java/com/cloudogu/scmmanager/scm/ScmManagerSourceRetriever.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 105 is only partially covered, one branch is missing
}

private boolean shouldExcludeDraftPullRequest(PullRequest pullRequest) {
return pullRequest != null && excludeDraftPullRequests() && pullRequest.isDraft();

Check warning on line 109 in src/main/java/com/cloudogu/scmmanager/scm/ScmManagerSourceRetriever.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 109 is only partially covered, 2 branches are missing
}

private boolean excludeDraftPullRequests() {
return traits.stream()
.anyMatch(t -> t instanceof PullRequestDiscoveryTrait

Check warning on line 114 in src/main/java/com/cloudogu/scmmanager/scm/ScmManagerSourceRetriever.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 114 is only partially covered, one branch is missing
&& ((PullRequestDiscoveryTrait) t).isExcludeDraftPullRequests());
}

public Iterable<ScmManagerObservable> getAllCandidatesFromSourceControl(ScmManagerSourceRequest request)
throws InterruptedException {
try {
Expand All @@ -94,7 +125,7 @@
? api.getTags(repository)
: CompletableFuture.completedFuture(Collections.emptyList());
CompletableFuture<List<PullRequest>> pullRequestFuture = request.isFetchPullRequests()
? api.getPullRequests(repository)
? api.getPullRequests(repository).thenApply(this::filterDraftPullRequests)
: CompletableFuture.completedFuture(Collections.emptyList());

CompletableFuture.allOf(branchesFuture, tagsFuture, pullRequestFuture)
Expand All @@ -113,6 +144,15 @@
}
}

private List<PullRequest> filterDraftPullRequests(List<PullRequest> pullRequests) {
if (!excludeDraftPullRequests()) {
return pullRequests;
}
return pullRequests.stream()
.filter(pullRequest -> !pullRequest.isDraft())

Check warning on line 152 in src/main/java/com/cloudogu/scmmanager/scm/ScmManagerSourceRetriever.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 152 is only partially covered, one branch is missing
.collect(Collectors.toList());
}

public ScmManagerApiProbe probe(@NonNull SCMHead head, @CheckForNull SCMRevision revision) {
ScmManagerRevision rev = null;

Expand Down
20 changes: 19 additions & 1 deletion src/main/java/com/cloudogu/scmmanager/scm/api/PullRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

private String target;

private String status;

private CloneInformation cloneInformation;

private Branch sourceBranch;
Expand All @@ -21,12 +23,18 @@
PullRequest() {}

public PullRequest(String id, Branch targetBranch, Branch sourceBranch, CloneInformation cloneInformation) {
this(id, targetBranch, sourceBranch, cloneInformation, "OPEN");
}

Check warning on line 27 in src/main/java/com/cloudogu/scmmanager/scm/api/PullRequest.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 26-27 are not covered by tests

public PullRequest(
String id, Branch targetBranch, Branch sourceBranch, CloneInformation cloneInformation, String status) {
this.id = id;
this.targetBranch = targetBranch;
this.target = targetBranch.getName();
this.sourceBranch = sourceBranch;
this.source = sourceBranch.getName();
this.cloneInformation = cloneInformation;
this.status = status;
}

void setCloneInformation(CloneInformation cloneInformation) {
Expand All @@ -53,6 +61,14 @@
return target;
}

public String getStatus() {
return status;
}

public boolean isDraft() {
return "DRAFT".equals(status);
}

@Override
public ScmManagerPullRequestHead head() {
if (head == null) {
Expand All @@ -79,14 +95,16 @@
return Objects.equals(id, that.id)
&& Objects.equals(source, that.source)
&& Objects.equals(target, that.target)
&& Objects.equals(status, that.status)
&& Objects.equals(cloneInformation, that.cloneInformation)
&& Objects.equals(sourceBranch, that.sourceBranch)
&& Objects.equals(targetBranch, that.targetBranch)
&& Objects.equals(head, that.head);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, source, target, cloneInformation, sourceBranch, targetBranch, head);
return Objects.hash(
super.hashCode(), id, source, target, status, cloneInformation, sourceBranch, targetBranch, head);

Check warning on line 108 in src/main/java/com/cloudogu/scmmanager/scm/api/PullRequest.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 98-108 are not covered by tests
}
}
61 changes: 47 additions & 14 deletions src/main/java/com/cloudogu/scmmanager/scm/api/ScmManagerApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.Function;
import java.util.stream.Collectors;
import jenkins.scm.api.SCMFile;
Expand Down Expand Up @@ -152,24 +153,56 @@
public CompletableFuture<List<PullRequest>> getPullRequests(Repository repository) {
Optional<Link> pullRequestLink = repository.getLinks().getLinkBy("pullRequest");
if (pullRequestLink.isPresent()) {
return client.get(
pullRequestLink.get().getHref() + "?status=OPEN",
"application/vnd.scmm-pullRequestCollection+json;v=2",
PullRequestCollection.class)
.thenApply(pullRequestCollection -> pullRequestCollection.get_embedded().getPullRequests().stream()
.map(preparePullRequest(repository))
.filter(cf -> !cf.isCompletedExceptionally())
.collect(Collectors.toList()))
.thenCompose(completableFutures -> CompletableFuture.allOf(
completableFutures.toArray(new CompletableFuture[0]))
.thenApply(future -> completableFutures.stream()
.filter(cf -> !cf.isCompletedExceptionally())
.map(CompletableFuture::join)
.collect(Collectors.toList())));
String href = pullRequestLink.get().getHref();
CompletableFuture<List<PullRequest>> openPullRequests =
getPullRequests(repository, href, "OPEN").exceptionally(this::emptyListOnNotFound);
CompletableFuture<List<PullRequest>> draftPullRequests =
getPullRequests(repository, href, "DRAFT").exceptionally(this::emptyListOnNotFound);

return CompletableFuture.allOf(openPullRequests, draftPullRequests).thenApply(v -> {
List<PullRequest> pullRequests = new java.util.ArrayList<>();
pullRequests.addAll(openPullRequests.join());
pullRequests.addAll(draftPullRequests.join());
return pullRequests;
});
}
return CompletableFuture.completedFuture(Collections.emptyList());

Check warning on line 169 in src/main/java/com/cloudogu/scmmanager/scm/api/ScmManagerApi.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 169 is not covered by tests
}

private List<PullRequest> emptyListOnNotFound(Throwable throwable) {
Throwable cause = unwrapCompletionException(throwable);
if (cause instanceof IllegalReturnStatusException

Check warning on line 174 in src/main/java/com/cloudogu/scmmanager/scm/api/ScmManagerApi.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 174 is only partially covered, one branch is missing
&& ((IllegalReturnStatusException) cause).getStatusCode() == 404) {

Check warning on line 175 in src/main/java/com/cloudogu/scmmanager/scm/api/ScmManagerApi.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 175 is only partially covered, one branch is missing
return Collections.emptyList();
}
throw new CompletionException(cause);

Check warning on line 178 in src/main/java/com/cloudogu/scmmanager/scm/api/ScmManagerApi.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 178 is not covered by tests
}

private Throwable unwrapCompletionException(Throwable throwable) {
if (throwable instanceof CompletionException && throwable.getCause() != null) {

Check warning on line 182 in src/main/java/com/cloudogu/scmmanager/scm/api/ScmManagerApi.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 182 is only partially covered, 2 branches are missing
return throwable.getCause();
}
return throwable;

Check warning on line 185 in src/main/java/com/cloudogu/scmmanager/scm/api/ScmManagerApi.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 185 is not covered by tests
}

private CompletableFuture<List<PullRequest>> getPullRequests(
Repository repository, String pullRequestLink, String status) {
return client.get(
pullRequestLink + "?status=" + status,
"application/vnd.scmm-pullRequestCollection+json;v=2",
PullRequestCollection.class)
.thenApply(pullRequestCollection -> pullRequestCollection.get_embedded().getPullRequests().stream()
.map(preparePullRequest(repository))
.filter(cf -> !cf.isCompletedExceptionally())
.collect(Collectors.toList()))
.thenCompose(completableFutures -> CompletableFuture.allOf(
completableFutures.toArray(new CompletableFuture[0]))
.thenApply(future -> completableFutures.stream()
.filter(cf -> !cf.isCompletedExceptionally())
.map(CompletableFuture::join)
.collect(Collectors.toList())));
}

private Function<PullRequest, CompletableFuture<PullRequest>> preparePullRequest(Repository repository) {
return pullRequest -> {
pullRequest.setCloneInformation(repository.getCloneInformation(client.getProtocol()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class ScmManagerBranchSourceContext extends BranchSourceContext {

private boolean discoverBranches = true;
private boolean discoverPullRequest = true;
private boolean excludeDraftPullRequests = false;
private boolean discoverTags = false;

public void discoverBranches(boolean discoverBranches) {
Expand All @@ -21,6 +22,10 @@ public void discoverPullRequest(boolean discoverPullRequest) {
this.discoverPullRequest = discoverPullRequest;
}

public void excludeDraftPullRequests(boolean excludeDraftPullRequests) {
this.excludeDraftPullRequests = excludeDraftPullRequests;
}

public void discoverTags(boolean discoverTags) {
this.discoverTags = discoverTags;
}
Expand All @@ -31,7 +36,7 @@ public List<SCMSourceTrait> getTraits() {
traits.add(new ScmManagerBranchDiscoveryTrait());
}
if (discoverPullRequest) {
traits.add(new PullRequestDiscoveryTrait());
traits.add(new PullRequestDiscoveryTrait(false, excludeDraftPullRequests));
}
if (discoverTags) {
traits.add(new TagDiscoveryTrait());
Expand Down
Loading
Loading