Skip to content

Commit 13a4bb7

Browse files
authored
Pull/161 (#193)
* - trigger or ignore builds based on commit message * - added dsl support for branch restrictions - added dsl support for commit message checks * Rename - all Event implementation should end with Event - commit checks moved under package because it other ExtensionPoint - CommitEvent consists from CommitChecks Signed-off-by: Kanstantsin Shautsou <kanstantsin.sha@gmail.com> * Rename dsl in tact Signed-off-by: Kanstantsin Shautsou <kanstantsin.sha@gmail.com> * Fix test? Signed-off-by: Kanstantsin Shautsou <kanstantsin.sha@gmail.com> * Rename forgotten resources as well. Signed-off-by: Kanstantsin Shautsou <kanstantsin.sha@gmail.com> * Fix suckstyle :) Signed-off-by: Kanstantsin Shautsou <kanstantsin.sha@gmail.com>
1 parent 8f5ea85 commit 13a4bb7

19 files changed

Lines changed: 793 additions & 25 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.github.kostyasha.github.integration.branch.dsl.context.events;
2+
3+
4+
import com.github.kostyasha.github.integration.branch.events.impl.commitchecks.GitHubBranchCommitCheck;
5+
import com.github.kostyasha.github.integration.branch.events.impl.GitHubBranchCommitEvent;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
import javaposse.jobdsl.dsl.Context;
11+
import javaposse.jobdsl.plugin.ContextExtensionPoint;
12+
13+
public class GitHubBranchCommitChecksDslContext implements Context {
14+
15+
private GitHubBranchCommitEvent event = new GitHubBranchCommitEvent();
16+
private List<GitHubBranchCommitCheck> checks = new ArrayList<>();
17+
18+
public void commitMessagePattern(Runnable closure) {
19+
GitHubBranchCommitMessageCheckDslContext commitContext = new GitHubBranchCommitMessageCheckDslContext();
20+
ContextExtensionPoint.executeInContext(closure, commitContext);
21+
22+
checks.add(commitContext.getCheck());
23+
}
24+
25+
public GitHubBranchCommitEvent getEvent() {
26+
event.setChecks(checks);
27+
return event;
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.github.kostyasha.github.integration.branch.dsl.context.events;
2+
3+
import com.github.kostyasha.github.integration.branch.events.impl.commitchecks.impl.GitHubBranchCommitMessageCheck;
4+
5+
import java.util.LinkedHashSet;
6+
import java.util.Set;
7+
8+
import javaposse.jobdsl.dsl.Context;
9+
10+
public class GitHubBranchCommitMessageCheckDslContext implements Context {
11+
private static final String LINE_SEPARATOR = System.lineSeparator();
12+
13+
private final Set<String> matchCriteria = new LinkedHashSet<>();
14+
private GitHubBranchCommitMessageCheck event = new GitHubBranchCommitMessageCheck();
15+
16+
public void excludeMatching() {
17+
event.setExclude(true);
18+
}
19+
20+
public void matchCritieria(String matchCritieria) {
21+
this.matchCriteria.add(matchCritieria);
22+
}
23+
24+
public GitHubBranchCommitMessageCheck getCheck() {
25+
event.setMatchCriteria(String.join(LINE_SEPARATOR, matchCriteria));
26+
return event;
27+
}
28+
}

github-pullrequest-plugin/src/main/java/com/github/kostyasha/github/integration/branch/dsl/context/events/GitHubBranchEventsDslContext.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.github.kostyasha.github.integration.branch.events.impl.GitHubBranchDeletedEvent;
66
import com.github.kostyasha.github.integration.branch.events.impl.GitHubBranchHashChangedEvent;
77
import javaposse.jobdsl.dsl.Context;
8+
import javaposse.jobdsl.plugin.ContextExtensionPoint;
89

910
import java.util.ArrayList;
1011
import java.util.List;
@@ -16,6 +17,20 @@ public class GitHubBranchEventsDslContext implements Context {
1617

1718
private List<GitHubBranchEvent> events = new ArrayList<>();
1819

20+
public void branchRestriction(Runnable closure) {
21+
GitHubBranchFilterEventDslContext filterContext = new GitHubBranchFilterEventDslContext();
22+
ContextExtensionPoint.executeInContext(closure, filterContext);
23+
24+
events.add(filterContext.getFilter());
25+
}
26+
27+
public void commitChecks(Runnable closure) {
28+
GitHubBranchCommitChecksDslContext checksContext = new GitHubBranchCommitChecksDslContext();
29+
ContextExtensionPoint.executeInContext(closure, checksContext);
30+
31+
events.add(checksContext.getEvent());
32+
}
33+
1934
public void created() {
2035
events.add(new GitHubBranchCreatedEvent());
2136
}
@@ -31,5 +46,4 @@ public void hashChanged() {
3146
public List<GitHubBranchEvent> events() {
3247
return events;
3348
}
34-
3549
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.github.kostyasha.github.integration.branch.dsl.context.events;
2+
3+
import com.github.kostyasha.github.integration.branch.events.impl.GitHubBranchRestrictionFilter;
4+
5+
import java.util.LinkedHashSet;
6+
import java.util.Set;
7+
8+
import javaposse.jobdsl.dsl.Context;
9+
10+
public class GitHubBranchFilterEventDslContext implements Context {
11+
12+
private static final String LINE_SEPARATOR = System.lineSeparator();
13+
14+
private final GitHubBranchRestrictionFilter filter = new GitHubBranchRestrictionFilter();
15+
private final Set<String> matchCriteria = new LinkedHashSet<>();
16+
17+
public void excludeMatching() {
18+
filter.setExclude(true);
19+
}
20+
21+
public void matchAgainstPatterns() {
22+
filter.setMatchAsPattern(true);
23+
}
24+
25+
public void matchCritieria(String matchCritieria) {
26+
this.matchCriteria.add(matchCritieria);
27+
}
28+
29+
public GitHubBranchRestrictionFilter getFilter() {
30+
filter.setMatchCriteriaStr(String.join(LINE_SEPARATOR, matchCriteria));
31+
return filter;
32+
}
33+
}

github-pullrequest-plugin/src/main/java/com/github/kostyasha/github/integration/branch/events/GitHubBranchEvent.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,22 @@
44
import com.github.kostyasha.github.integration.branch.GitHubBranchCause;
55
import com.github.kostyasha.github.integration.branch.GitHubBranchRepository;
66
import com.github.kostyasha.github.integration.branch.GitHubBranchTrigger;
7+
import hudson.ExtensionPoint;
78
import hudson.model.AbstractDescribableImpl;
89
import hudson.model.TaskListener;
910
import org.kohsuke.github.GHBranch;
1011
import org.kohsuke.github.GHEventPayload;
11-
import org.slf4j.Logger;
12-
import org.slf4j.LoggerFactory;
1312

1413
import javax.annotation.CheckForNull;
1514
import java.io.IOException;
1615

1716
/**
17+
* Different "events" that may want trigger run for branch.
18+
*
1819
* @author Kanstantsin Shautsou
20+
* @see org.jenkinsci.plugins.github.pullrequest.events.GitHubPREvent
1921
*/
20-
public abstract class GitHubBranchEvent extends AbstractDescribableImpl<GitHubBranchEvent> {
21-
private static final Logger LOG = LoggerFactory.getLogger(GitHubBranchEvent.class);
22+
public abstract class GitHubBranchEvent extends AbstractDescribableImpl<GitHubBranchEvent> implements ExtensionPoint {
2223

2324
/**
2425
* indicates that branch was created
@@ -27,7 +28,9 @@ public abstract class GitHubBranchEvent extends AbstractDescribableImpl<GitHubBr
2728
* @param remoteBranch current branch state fetched from GH.
2829
* @param localBranch branch state from last run saved in jenkins. null when not exist before.
2930
* @param localRepo local repository state. Useful to extract repo URLs for example.
30-
* @return true if branch should be run. null when no influence.
31+
* @return cause object. null when no influence (other events will be checked.
32+
* If cause.isSkip() == true, then other checks wouldn't influence. And triggering for this branch will be skipped.
33+
* If cause.isSkip() == false, indicates that branch build should be run.
3134
*/
3235
@CheckForNull
3336
public GitHubBranchCause check(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package com.github.kostyasha.github.integration.branch.events.impl;
2+
3+
import com.github.kostyasha.github.integration.branch.GitHubBranch;
4+
import com.github.kostyasha.github.integration.branch.GitHubBranchCause;
5+
import com.github.kostyasha.github.integration.branch.GitHubBranchRepository;
6+
import com.github.kostyasha.github.integration.branch.GitHubBranchTrigger;
7+
import com.github.kostyasha.github.integration.branch.events.impl.commitchecks.GitHubBranchCommitCheck;
8+
import com.github.kostyasha.github.integration.branch.events.impl.commitchecks.GitHubBranchCommitCheckDescriptor;
9+
import com.github.kostyasha.github.integration.branch.events.GitHubBranchEvent;
10+
import com.github.kostyasha.github.integration.branch.events.GitHubBranchEventDescriptor;
11+
12+
import static org.jenkinsci.plugins.github.pullrequest.utils.ObjectsUtil.isNull;
13+
14+
import hudson.Extension;
15+
import hudson.model.TaskListener;
16+
17+
import net.sf.json.JSONObject;
18+
19+
import org.kohsuke.accmod.Restricted;
20+
import org.kohsuke.accmod.restrictions.NoExternalUse;
21+
import org.kohsuke.github.GHBranch;
22+
import org.kohsuke.github.GHCompare;
23+
import org.kohsuke.stapler.DataBoundConstructor;
24+
import org.kohsuke.stapler.StaplerRequest;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
27+
28+
import javax.annotation.CheckForNull;
29+
import javax.annotation.Nonnull;
30+
31+
import java.io.IOException;
32+
import java.io.PrintStream;
33+
import java.util.ArrayList;
34+
import java.util.List;
35+
import java.util.Objects;
36+
import java.util.stream.Collectors;
37+
38+
/**
39+
* This branch event acts as a wrapper around checks that can be performed against commit data that requires
40+
* an additional round trip to GitHub to retrieve.
41+
* <p>
42+
* Commit data is retrieved and then passed to each implementing instance of <code>GitHubBranchCommitCheck</code>
43+
* to determine information about the commit should trigger a build.
44+
* </p>
45+
*
46+
* @author Kanstantsin Shautsou
47+
* @author Jae Gangemi
48+
*/
49+
public class GitHubBranchCommitEvent extends GitHubBranchEvent {
50+
private static final String DISPLAY_NAME = "Commit Checks";
51+
52+
private static final Logger LOG = LoggerFactory.getLogger(GitHubBranchCommitEvent.class);
53+
54+
private List<GitHubBranchCommitCheck> checks = new ArrayList<>();
55+
56+
/**
57+
* For groovy UI
58+
*/
59+
@Restricted(value = NoExternalUse.class)
60+
public GitHubBranchCommitEvent() {
61+
}
62+
63+
@DataBoundConstructor
64+
public GitHubBranchCommitEvent(List<GitHubBranchCommitCheck> checks) {
65+
this.checks = checks;
66+
}
67+
68+
@Override
69+
public GitHubBranchCause check(GitHubBranchTrigger trigger, GHBranch remoteBranch, @CheckForNull GitHubBranch localBranch,
70+
GitHubBranchRepository localRepo, TaskListener listener)
71+
throws IOException {
72+
final PrintStream lloger = listener.getLogger();
73+
74+
if (localBranch == null) {
75+
LOG.debug("First build of branch '%s' detected, skipping check.", remoteBranch.getName());
76+
lloger.println("First build of branch '" + remoteBranch.getName() + "' detected, skipping check.");
77+
return null;
78+
}
79+
80+
GHCompare.Commit[] commits = getComparedCommits(localBranch, remoteBranch);
81+
List<GitHubBranchCause> causes = checks.stream()
82+
.map(event -> event.check(remoteBranch, localRepo, commits))
83+
.filter(Objects::nonNull)
84+
.collect(Collectors.toList());
85+
86+
String name = remoteBranch.getName();
87+
if (causes.isEmpty()) {
88+
LOG.debug("Commits for branch [{}] had no effect, not triggering run.", name);
89+
return null;
90+
}
91+
92+
GitHubBranchCause cause = causes.get(0);
93+
LOG.info("Building branch [{}] skipped due to commit check: {}", name, cause.getReason());
94+
95+
return cause;
96+
}
97+
98+
// visible for testing to avoid complex mocking
99+
GHCompare.Commit[] getComparedCommits(GitHubBranch localBranch, GHBranch remoteBranch) throws IOException {
100+
String previous = localBranch.getCommitSha();
101+
String current = remoteBranch.getSHA1();
102+
103+
LOG.debug("Comparing previous hash [{}] with current hash [{}]", previous, current);
104+
return remoteBranch.getOwner()
105+
.getCompare(previous, current)
106+
.getCommits();
107+
}
108+
109+
@Nonnull
110+
public List<GitHubBranchCommitCheck> getChecks() {
111+
if (isNull(checks)) {
112+
checks = new ArrayList<>();
113+
}
114+
return checks;
115+
}
116+
117+
public void setChecks(List<GitHubBranchCommitCheck> checks) {
118+
this.checks = checks;
119+
}
120+
121+
@Extension
122+
public static class DescriptorImpl extends GitHubBranchEventDescriptor {
123+
@Override
124+
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
125+
req.bindJSON(this, formData);
126+
127+
save();
128+
return super.configure(req, formData);
129+
}
130+
131+
@Override
132+
public final String getDisplayName() {
133+
return DISPLAY_NAME;
134+
}
135+
136+
public List<GitHubBranchCommitCheckDescriptor> getEventDescriptors() {
137+
return GitHubBranchCommitCheckDescriptor.all();
138+
}
139+
}
140+
}

github-pullrequest-plugin/src/main/java/com/github/kostyasha/github/integration/branch/events/impl/GitHubBranchRestrictionFilter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ public void setMatchAsPattern(boolean matchAsPattern) {
6767
this.matchAsPattern = matchAsPattern;
6868
}
6969

70+
// visible for testing
71+
public Set<String> getMatchCriteria() {
72+
return matchCriteria;
73+
}
74+
7075
@Override
7176
public GitHubBranchCause check(GitHubBranchTrigger gitHubBranchTrigger, GHBranch remoteBranch, GitHubBranch localBranch,
7277
GitHubBranchRepository localRepo, TaskListener listener) {
@@ -125,4 +130,5 @@ public String getDisplayName() {
125130
return DISPLAY_NAME;
126131
}
127132
}
133+
128134
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.github.kostyasha.github.integration.branch.events.impl.commitchecks;
2+
3+
import com.github.kostyasha.github.integration.branch.GitHubBranchCause;
4+
import com.github.kostyasha.github.integration.branch.GitHubBranchRepository;
5+
6+
import com.github.kostyasha.github.integration.branch.events.impl.GitHubBranchCommitEvent;
7+
import hudson.ExtensionPoint;
8+
import hudson.model.AbstractDescribableImpl;
9+
10+
import org.kohsuke.github.GHBranch;
11+
import org.kohsuke.github.GHCompare.Commit;
12+
13+
/**
14+
* @see GitHubBranchCommitEvent
15+
*/
16+
public abstract class GitHubBranchCommitCheck extends AbstractDescribableImpl<GitHubBranchCommitCheck>
17+
implements ExtensionPoint {
18+
19+
@Override
20+
public GitHubBranchCommitCheckDescriptor getDescriptor() {
21+
return (GitHubBranchCommitCheckDescriptor) super.getDescriptor();
22+
}
23+
24+
/**
25+
* Check used to determine if some associated commit property, such as the commit message, should prevent a build from being triggered.
26+
*
27+
* @param remoteBranch current branch state from GH.
28+
* @param localRepo local repository state.
29+
* @param commits commits commits that occurred between the last known local hash and the current remote.
30+
* @return <code>GitHubBranchCause</code> instance indicating if the build should be skipped, <code>null</code> otherwise.
31+
*/
32+
public abstract GitHubBranchCause check(GHBranch remoteBranch, GitHubBranchRepository localRepo, Commit[] commits);
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.github.kostyasha.github.integration.branch.events.impl.commitchecks;
2+
3+
import hudson.DescriptorExtensionList;
4+
import hudson.model.Descriptor;
5+
6+
import jenkins.model.Jenkins;
7+
8+
/**
9+
* @see GitHubBranchCommitCheck
10+
*/
11+
public abstract class GitHubBranchCommitCheckDescriptor extends Descriptor<GitHubBranchCommitCheck> {
12+
public static DescriptorExtensionList<GitHubBranchCommitCheck, GitHubBranchCommitCheckDescriptor> all() {
13+
return Jenkins.getInstance().getDescriptorList(GitHubBranchCommitCheck.class);
14+
}
15+
}

0 commit comments

Comments
 (0)