From ade4a1a1e2fdfac7180cadebd574ffe5bdedd062 Mon Sep 17 00:00:00 2001 From: Maxim Epishchev Date: Tue, 19 Apr 2016 16:58:43 +0300 Subject: Available "pullRequestAuthor" env variable (featured from #83) Env variable "pullRequestAuthor" contain two parts of author: full name of user and short username in format, like: "Some Doo <@somedoo>". Add test for PR build filter: now we can filter also by author: "a:maxvodo" by example. --- .../BitbucketBuildFilter.java | 86 ++++++++++++++++++---- .../BitbucketBuildTrigger.java | 3 + .../BitbucketCause.java | 9 ++- .../BitbucketRepository.java | 7 +- .../bitbucket/Pullrequest.java | 36 +++++++++ src/test/java/BitbucketBuildFilterTest.java | 20 +++++ 6 files changed, 144 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildFilter.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildFilter.java index c251930..d4173a2 100644 --- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildFilter.java +++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildFilter.java @@ -1,5 +1,6 @@ package bitbucketpullrequestbuilder.bitbucketpullrequestbuilder; +import hudson.model.Action; import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.ArrayList; @@ -29,6 +30,7 @@ abstract class Filter { public static final String SRC_RX = "s:(" + RX_FILTER_FLAG_SINGLE + ")?"; public static final String DST_RX = "d:(" + RX_FILTER_FLAG_SINGLE + ")?"; + public static final String AUTHOR_RX = "a:(" + RX_FILTER_FLAG_SINGLE + ")?"; public static final String BRANCH_FILTER_RX_PART = "([^\\s$]*)"; abstract public boolean apply(String filter, BitbucketCause cause); @@ -36,6 +38,20 @@ abstract class Filter { static final Pattern RX_SRC_DST_PARTS = Pattern.compile("(s:)|(d:)"); public static boolean HasSourceOrDestPartsPredicate(String filter) { return RX_SRC_DST_PARTS.matcher(filter).find(); } + + static final Pattern RX_AUTHOR_PARTS = Pattern.compile("(a:)"); + public static boolean HasAuthorPartsPredicate(String filter) { return RX_AUTHOR_PARTS.matcher(filter).find(); } + + protected boolean applyByRx(Pattern rx, Filter usedFilter, String filter, BitbucketCause cause) { + Matcher srcMatch = rx.matcher(filter); + boolean apply = false; + while (srcMatch.find()) { + String computedFilter = ((srcMatch.group(1) == null ? "" : srcMatch.group(1)) + srcMatch.group(2)).trim(); + logger.log(Level.INFO, "Apply computed filter: {0}", computedFilter); + apply = apply || (computedFilter.isEmpty() ? true : usedFilter.apply(computedFilter, cause)); + } + return apply; + } } class EmptyFilter extends Filter { @@ -84,17 +100,6 @@ class SourceDestFlag extends Filter { static final Pattern SRC_MATCHER_RX = Pattern.compile(SRC_RX + BRANCH_FILTER_RX_PART, Pattern.CASE_INSENSITIVE | Pattern.CANON_EQ); static final Pattern DST_MATCHER_RX = Pattern.compile(DST_RX + BRANCH_FILTER_RX_PART, Pattern.CASE_INSENSITIVE | Pattern.CANON_EQ); - boolean applyByRx(Pattern rx, Filter usedFilter, String filter, BitbucketCause cause) { - Matcher srcMatch = rx.matcher(filter); - boolean apply = rx.matcher(filter).matches(); - while (srcMatch.find()) { - String computedFilter = ((srcMatch.group(1) == null ? "" : srcMatch.group(1)) + srcMatch.group(2)).trim(); - logger.log(Level.INFO, "Apply computed filter: {0}", computedFilter); - apply = apply || (computedFilter.isEmpty() ? true : usedFilter.apply(computedFilter, cause)); - } - return apply; - } - @Override public boolean apply(String filter, BitbucketCause cause) { return this.applyByRx(SRC_MATCHER_RX, new OnlySourceFlag(), filter, cause) && @@ -106,6 +111,54 @@ class SourceDestFlag extends Filter { } } +class AuthorFlag extends Filter { + static final Pattern AUTHOR_MATCHER_RX = Pattern.compile(AUTHOR_RX + BRANCH_FILTER_RX_PART, Pattern.CASE_INSENSITIVE | Pattern.CANON_EQ); + + class AuthorFlagImpl extends Filter { + @Override + public boolean apply(String filter, BitbucketCause cause) { + String selectedRx = filter.startsWith(RX_FILTER_FLAG_SINGLE) ? filter.substring(RX_FILTER_FLAG_SINGLE.length()) : Pattern.quote(filter); + logger.log(Level.INFO, "AuthorFlagImpl using filter: {0}", selectedRx); + Matcher matcher = Pattern.compile(selectedRx, Pattern.CASE_INSENSITIVE).matcher(cause.getPullRequestAuthor()); + return filter.startsWith(RX_FILTER_FLAG_SINGLE) ? matcher.find() : matcher.matches(); + } + @Override + public boolean check(String filter) { return false; } + } + + @Override + public boolean apply(String filter, BitbucketCause cause) { + return this.applyByRx(AUTHOR_MATCHER_RX, new AuthorFlagImpl(), filter, cause); + } + @Override + public boolean check(String filter) { + return HasAuthorPartsPredicate(filter); + } +} + +class CombinedFlags extends Filter { + private final Filter[] _filters; + public CombinedFlags(Filter[] filters) { + _filters = filters; + } + + @Override + public boolean apply(String filter, BitbucketCause cause) { + boolean applied = true; + for(Filter f: _filters) + if (f.check(filter)) + applied = applied && f.apply(filter, cause); + return applied; + } + @Override + public boolean check(String filter) { + for(Filter f: _filters) + if (f.check(filter)) + return true; + return false; + } +} + /** * Created by maxvodo */ @@ -118,10 +171,15 @@ public class BitbucketBuildFilter { static { ArrayList filters = new ArrayList(); - filters.add(new AnyFlag()); + + filters.add(new AnyFlag()); + filters.add(new CombinedFlags(new Filter[] { + new SourceDestFlag(), + new AuthorFlag() + })); filters.add(new OnlyDestFlag()); - filters.add(new SourceDestFlag()); - filters.add(new EmptyFilter()); + filters.add(new EmptyFilter()); + AvailableFilters = filters; } diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java index 2375ec7..1120aca 100644 --- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java +++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java @@ -164,6 +164,7 @@ public class BitbucketBuildTrigger extends Trigger> { public QueueTaskFuture startJob(BitbucketCause cause) { Map values = this.getDefaultParameters(); + values.put("sourceBranch", new StringParameterValue("sourceBranch", cause.getSourceBranch())); values.put("targetBranch", new StringParameterValue("targetBranch", cause.getTargetBranch())); values.put("repositoryOwner", new StringParameterValue("repositoryOwner", cause.getRepositoryOwner())); @@ -172,6 +173,8 @@ public class BitbucketBuildTrigger extends Trigger> { values.put("destinationRepositoryOwner", new StringParameterValue("destinationRepositoryOwner", cause.getDestinationRepositoryOwner())); values.put("destinationRepositoryName", new StringParameterValue("destinationRepositoryName", cause.getDestinationRepositoryName())); values.put("pullRequestTitle", new StringParameterValue("pullRequestTitle", cause.getPullRequestTitle())); + values.put("pullRequestAuthor", new StringParameterValue("pullRequestAuthor", cause.getPullRequestAuthor())); + return this.job.scheduleBuild2(0, cause, new ParametersAction(new ArrayList(values.values())), new RevisionParameterAction(cause.getSourceCommitHash())); } diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketCause.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketCause.java index e233371..3cb107b 100644 --- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketCause.java +++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketCause.java @@ -16,6 +16,7 @@ public class BitbucketCause extends Cause { private final String pullRequestTitle; private final String sourceCommitHash; private final String destinationCommitHash; + private final String pullRequestAuthor; public static final String BITBUCKET_URL = "https://bitbucket.org/"; public BitbucketCause(String sourceBranch, @@ -27,7 +28,8 @@ public class BitbucketCause extends Cause { String destinationRepositoryName, String pullRequestTitle, String sourceCommitHash, - String destinationCommitHash) { + String destinationCommitHash, + String pullRequestAuthor) { this.sourceBranch = sourceBranch; this.targetBranch = targetBranch; this.repositoryOwner = repositoryOwner; @@ -38,6 +40,7 @@ public class BitbucketCause extends Cause { this.pullRequestTitle = pullRequestTitle; this.sourceCommitHash = sourceCommitHash; this.destinationCommitHash = destinationCommitHash; + this.pullRequestAuthor = pullRequestAuthor; } public String getSourceBranch() { @@ -83,4 +86,8 @@ public class BitbucketCause extends Cause { description += "\">#" + this.getPullRequestId() + " " + this.getPullRequestTitle() + ""; return description; } + + public String getPullRequestAuthor() { + return this.pullRequestAuthor; + } } diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java index 9b92775..4417d74 100644 --- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java +++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java @@ -117,7 +117,9 @@ public class BitbucketRepository { pullRequest.getDestination().getRepository().getRepositoryName(), pullRequest.getTitle(), pullRequest.getSource().getCommit().getHash(), - pullRequest.getDestination().getCommit().getHash()); + pullRequest.getDestination().getCommit().getHash(), + pullRequest.getAuthor().getCombinedUsername() + ); setBuildStatus(cause, BuildState.INPROGRESS, Jenkins.getInstance().getRootUrl()); this.builder.getTrigger().startJob(cause); } @@ -286,7 +288,8 @@ public class BitbucketRepository { pullRequest.getDestination().getRepository().getRepositoryName(), pullRequest.getTitle(), pullRequest.getSource().getCommit().getHash(), - pullRequest.getDestination().getCommit().getHash() + pullRequest.getDestination().getCommit().getHash(), + pullRequest.getAuthor().getCombinedUsername() ); //@FIXME: Way to iterate over all available SCMSources diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/Pullrequest.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/Pullrequest.java index 1e8bf5c..140c213 100644 --- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/Pullrequest.java +++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/Pullrequest.java @@ -28,6 +28,7 @@ public class Pullrequest { private String updatedOn; private String mergeCommit; private String id; + private Author author; @JsonIgnoreProperties(ignoreUnknown = true) public static class Response { @@ -233,6 +234,33 @@ public class Pullrequest { this.createdOn = createdOn; } } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Author { + private String username; + private String display_name; + public static final String COMBINED_NAME = "%s <@%s>"; + + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + + @JsonProperty("display_name") + public String getDisplayName() { + return display_name; + } + + @JsonProperty("display_name") + public void setDisplayName(String display_name) { + this.display_name = display_name; + } + public String getCombinedUsername() { + return String.format(COMBINED_NAME, this.getDisplayName(), this.getUsername()); + } + } //-------------------- only getters and setters follow ----------------- @@ -341,5 +369,13 @@ public class Pullrequest { public void setId(String id) { this.id = id; } + + public Author getAuthor() { + return this.author; + } + + public void setAutohor(Author author) { + this.author = author; + } } diff --git a/src/test/java/BitbucketBuildFilterTest.java b/src/test/java/BitbucketBuildFilterTest.java index 3b35dbc..3a94c82 100644 --- a/src/test/java/BitbucketBuildFilterTest.java +++ b/src/test/java/BitbucketBuildFilterTest.java @@ -140,6 +140,26 @@ public class BitbucketBuildFilterTest { } } + @Test + @WithoutJenkins + public void authorFilter() { + BitbucketCause cause = EasyMock.createMock(BitbucketCause.class); + EasyMock.expect(cause.getTargetBranch()).andReturn("master").anyTimes(); + EasyMock.expect(cause.getSourceBranch()).andReturn("feature-master").anyTimes(); + EasyMock.expect(cause.getPullRequestAuthor()).andReturn("test").anyTimes(); + EasyMock.replay(cause); + + for(String f : new String[] {"a:test", "a:r:^test", "d: s: a:", "a:", "a:foo a:test"}) { + BitbucketBuildFilter filter = BitbucketBuildFilter.InstanceByString(f); + assertTrue(filter.approved(cause)); + } + + for(String f : new String[] {"s:feature-master", "d:master", "s:feature-master d: a:foo", "a:bar"}) { + BitbucketBuildFilter filter = BitbucketBuildFilter.InstanceByString(f); + assertFalse(filter.approved(cause)); + } + } + @Test @WithoutJenkins public void emptyGitSCMFilter() { -- cgit v1.2.3