From 84368171adea5dd3223b8606233c8875b0c053e4 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Thu, 9 Jul 2015 02:34:53 -0400 Subject: [PATCH 001/175] Add ghprbTriggerLogin to allow mentions in the status comments --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index b5c544337..dd8cd7eda 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -237,6 +237,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbTriggerAuthor", triggerAuthor)); values.add(new StringParameterValue("ghprbTriggerAuthorEmail", triggerAuthorEmail)); + values.add(new StringParameterValue("ghprbTriggerLogin", cause.getTriggerSender().getLogin())); final StringParameterValue pullIdPv = new StringParameterValue("ghprbPullId", String.valueOf(cause.getPullID())); values.add(pullIdPv); values.add(new StringParameterValue("ghprbTargetBranch", String.valueOf(cause.getTargetBranch()))); From 38336eca58f9203059069faf33150f59936ce3f1 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Thu, 9 Jul 2015 04:27:40 -0400 Subject: [PATCH 002/175] ghprbTriggerLogin -> ghprbTriggerAuthorLogin Add ghprbPullAuthorLogin for PR author login Fix NPE --- .../java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java | 2 +- .../java/org/jenkinsci/plugins/ghprb/GhprbCause.java | 9 ++++++++- .../org/jenkinsci/plugins/ghprb/GhprbPullRequest.java | 4 ++++ .../java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 7 ++++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 64db371a9..f5d693c2d 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -36,7 +36,7 @@ public GhprbBuilds(GhprbTrigger trigger, GhprbRepository repo) { public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) { GhprbCause cause = new GhprbCause(pr.getHead(), pr.getId(), pr.isMergeable(), pr.getTarget(), pr.getSource(), pr.getAuthorEmail(), pr.getTitle(), pr.getUrl(), triggerSender, commentBody, - pr.getCommitAuthor()); + pr.getCommitAuthor(), pr.getPullRequestAuthor()); for (GhprbExtension ext : Ghprb.getJobExtensions(trigger, GhprbCommitStatus.class)) { if (ext instanceof GhprbCommitStatus) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java index ba8cce14c..c9e34fe83 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java @@ -23,6 +23,7 @@ public class GhprbCause extends Cause { private final GHUser triggerSender; private final String commentBody; private final GitUser commitAuthor; + private final GHUser pullRequestAuthor; public GhprbCause(String commit, int pullID, @@ -34,7 +35,8 @@ public GhprbCause(String commit, URL url, GHUser triggerSender, String commentBody, - GitUser commitAuthor) { + GitUser commitAuthor, + GHUser pullRequestAuthor) { this.commit = commit; this.pullID = pullID; @@ -48,6 +50,7 @@ public GhprbCause(String commit, this.triggerSender = triggerSender; this.commentBody = commentBody; this.commitAuthor = commitAuthor; + this.pullRequestAuthor = pullRequestAuthor; } @Override @@ -91,6 +94,10 @@ public String getCommentBody() { return commentBody; } + public GHUser getPullRequestAuthor() { + return pullRequestAuthor; + } + /** * Returns the title of the cause, not null. * diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 44e7db066..156dd6499 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -451,6 +451,10 @@ public GitUser getCommitAuthor() { return commitAuthor; } + public GHUser getPullRequestAuthor() { + return author; + } + public GHPullRequest getPullRequest() { return pr; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index dd8cd7eda..2aa9a9bea 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -225,6 +225,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbActualCommit", cause.getCommit())); String triggerAuthor = ""; String triggerAuthorEmail = ""; + String triggerAuthorLogin = ""; try { triggerAuthor = getString(cause.getTriggerSender().getName(), ""); @@ -232,12 +233,15 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { try { triggerAuthorEmail = getString(cause.getTriggerSender().getEmail(), ""); } catch (Exception e) {} + try { + triggerAuthorLogin = getString(cause.getTriggerSender().getLogin(), ""); + } catch (Exception e) {} setCommitAuthor(cause, values); values.add(new StringParameterValue("ghprbTriggerAuthor", triggerAuthor)); values.add(new StringParameterValue("ghprbTriggerAuthorEmail", triggerAuthorEmail)); - values.add(new StringParameterValue("ghprbTriggerLogin", cause.getTriggerSender().getLogin())); + values.add(new StringParameterValue("ghprbTriggerAuthorLogin", triggerAuthorLogin)); final StringParameterValue pullIdPv = new StringParameterValue("ghprbPullId", String.valueOf(cause.getPullID())); values.add(pullIdPv); values.add(new StringParameterValue("ghprbTargetBranch", String.valueOf(cause.getTargetBranch()))); @@ -245,6 +249,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("GIT_BRANCH", String.valueOf(cause.getSourceBranch()))); // it's possible the GHUser doesn't have an associated email address values.add(new StringParameterValue("ghprbPullAuthorEmail", getString(cause.getAuthorEmail(), ""))); + values.add(new StringParameterValue("ghprbPullAuthorLogin", String.valueOf(cause.getPullRequestAuthor().getLogin()))); values.add(new StringParameterValue("ghprbPullDescription", String.valueOf(cause.getShortDescription()))); values.add(new StringParameterValue("ghprbPullTitle", String.valueOf(cause.getTitle()))); values.add(new StringParameterValue("ghprbPullLink", String.valueOf(cause.getUrl()))); From 42ac5e23ea2379b903568303395cc20da60eb834 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Fri, 10 Jul 2015 02:32:24 -0400 Subject: [PATCH 003/175] Add *Mention variables for logging --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 2aa9a9bea..f0345f825 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -242,6 +242,8 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbTriggerAuthor", triggerAuthor)); values.add(new StringParameterValue("ghprbTriggerAuthorEmail", triggerAuthorEmail)); values.add(new StringParameterValue("ghprbTriggerAuthorLogin", triggerAuthorLogin)); + values.add(new StringParameterValue("ghprbTriggerAuthorLoginMention", triggerAuthorLogin.isEmpty() ? "@" + + triggerAuthorLogin : "")); final StringParameterValue pullIdPv = new StringParameterValue("ghprbPullId", String.valueOf(cause.getPullID())); values.add(pullIdPv); values.add(new StringParameterValue("ghprbTargetBranch", String.valueOf(cause.getTargetBranch()))); @@ -250,6 +252,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { // it's possible the GHUser doesn't have an associated email address values.add(new StringParameterValue("ghprbPullAuthorEmail", getString(cause.getAuthorEmail(), ""))); values.add(new StringParameterValue("ghprbPullAuthorLogin", String.valueOf(cause.getPullRequestAuthor().getLogin()))); + values.add(new StringParameterValue("ghprbPullAuthorLoginMention", "@" + cause.getPullRequestAuthor().getLogin())); values.add(new StringParameterValue("ghprbPullDescription", String.valueOf(cause.getShortDescription()))); values.add(new StringParameterValue("ghprbPullTitle", String.valueOf(cause.getTitle()))); values.add(new StringParameterValue("ghprbPullLink", String.valueOf(cause.getUrl()))); From bae619f92c64dcba38c1c55b0d65cfcfea73d980 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Fri, 10 Jul 2015 04:04:42 -0400 Subject: [PATCH 004/175] Fix ghprbTriggerAuthorLoginMention --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index f0345f825..907e603a8 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -242,7 +242,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbTriggerAuthor", triggerAuthor)); values.add(new StringParameterValue("ghprbTriggerAuthorEmail", triggerAuthorEmail)); values.add(new StringParameterValue("ghprbTriggerAuthorLogin", triggerAuthorLogin)); - values.add(new StringParameterValue("ghprbTriggerAuthorLoginMention", triggerAuthorLogin.isEmpty() ? "@" + values.add(new StringParameterValue("ghprbTriggerAuthorLoginMention", !triggerAuthorLogin.isEmpty() ? "@" + triggerAuthorLogin : "")); final StringParameterValue pullIdPv = new StringParameterValue("ghprbPullId", String.valueOf(cause.getPullID())); values.add(pullIdPv); From 8c8541523e8ac15b51977754f8add7e55f4feba1 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 14 Jul 2015 17:10:17 -0600 Subject: [PATCH 005/175] Extend the options in the merge step. Also fix an issue where the git user may not match the github user --- README.md | 5 + .../plugins/ghprb/GhprbGitHubAuth.java | 72 +++++++++++++- .../plugins/ghprb/GhprbPullRequestMerge.java | 98 ++++++++++++++----- .../ghprb/GhprbGitHubAuth/config.groovy | 42 +++++++- .../ghprb/GhprbPullRequestMerge/config.jelly | 6 ++ .../ghprb/GhprbPullRequestMergeTest.java | 75 +++++++++----- 6 files changed, 239 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 270ebb180..02add543e 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,11 @@ If you want to manually build the job, in the job setting check ``This build is ### Updates +#### -> 1.26 +* Extend the checking for own code. +* Fail build only when desired if we can't merge the build. +* Add option to delete branch when merge succeeds. + #### -> 1.25 * Fix condition where admin can't run tests #60 JENKINS-25572, JENKINS-25574, JENKINS-25603 * Check for when webhook encoding is null and default to UTF-8 diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java index 08d0d01e7..acbee4bd0 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java @@ -13,6 +13,8 @@ import java.util.logging.Logger; import org.kohsuke.github.GHAuthorization; +import org.kohsuke.github.GHCommitState; +import org.kohsuke.github.GHIssue; import org.kohsuke.github.GHMyself; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GitHub; @@ -244,7 +246,7 @@ public FormValidation doCheckServerAPIUrl(@QueryParameter String value) { public FormValidation doCheckRepoAccess( @QueryParameter("serverAPIUrl") final String serverAPIUrl, @QueryParameter("credentialsId") final String credentialsId, - @QueryParameter("repo") final String repo) { + @QueryParameter("repo1") final String repo) { try { GitHubBuilder builder = getBuilder(null, serverAPIUrl, credentialsId); if (builder == null) { @@ -282,11 +284,77 @@ public FormValidation doTestGithubAccess( } GitHub gh = builder.build(); GHMyself me = gh.getMyself(); - return FormValidation.ok("Connected to " + serverAPIUrl + " as " + me.getName()); + String name = me.getName(); + String email = me.getEmail(); + String login = me.getLogin(); + + String comment = String.format("Connected to %s as %s (%s) login: %s", serverAPIUrl, name, email, login); + return FormValidation.ok(comment); } catch (Exception ex) { return FormValidation.error("Unable to connect to GitHub API: " + ex); } } + + + public FormValidation doTestComment( + @QueryParameter("serverAPIUrl") final String serverAPIUrl, + @QueryParameter("credentialsId") final String credentialsId, + @QueryParameter("repo2") final String repoName, + @QueryParameter("issueId") final int issueId, + @QueryParameter("message1") final String comment) { + try { + GitHubBuilder builder = getBuilder(null, serverAPIUrl, credentialsId); + if (builder == null) { + return FormValidation.error("Unable to look up GitHub credentials using ID: " + credentialsId + "!!"); + } + GitHub gh = builder.build(); + GHRepository repo = gh.getRepository(repoName); + GHIssue issue = repo.getIssue(issueId); + issue.comment(comment); + + return FormValidation.ok("Issued comment to issue: " + issue.getHtmlUrl()); + } catch (Exception ex) { + return FormValidation.error("Unable to issue comment: " + ex); + } + } + + public FormValidation doTestUpdateStatus( + @QueryParameter("serverAPIUrl") final String serverAPIUrl, + @QueryParameter("credentialsId") final String credentialsId, + @QueryParameter("repo3") final String repoName, + @QueryParameter("sha1") final String sha1, + @QueryParameter("state") final GHCommitState state, + @QueryParameter("url") final String url, + @QueryParameter("message2") final String message, + @QueryParameter("context") final String context) { + try { + GitHubBuilder builder = getBuilder(null, serverAPIUrl, credentialsId); + if (builder == null) { + return FormValidation.error("Unable to look up GitHub credentials using ID: " + credentialsId + "!!"); + } + GitHub gh = builder.build(); + GHRepository repo = gh.getRepository(repoName); + repo.createCommitStatus(sha1, state, url, message, context); + return FormValidation.ok("Updated status of: " + sha1); + } catch (Exception ex) { + return FormValidation.error("Unable to update status: " + ex); + } + } + + public ListBoxModel doFillStateItems(@QueryParameter("state") String state) { + ListBoxModel items = new ListBoxModel(); + for (GHCommitState commitState : GHCommitState.values()) { + + items.add(commitState.toString(), commitState.toString()); + if (state.equals(commitState.toString())) { + items.get(items.size() - 1).selected = true; + } + } + + return items; + } } + + } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 6a76b71ed..48a8e1b51 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -4,11 +4,13 @@ import java.io.PrintStream; import java.util.concurrent.ConcurrentMap; -import org.kohsuke.github.GHBranch; import org.kohsuke.github.GHPullRequestCommitDetail.Commit; import org.kohsuke.github.GHPullRequest; import org.kohsuke.github.GHPullRequestCommitDetail; +import org.kohsuke.github.GHRef; +import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHUser; +import org.kohsuke.github.GitUser; import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; @@ -33,18 +35,28 @@ public class GhprbPullRequestMerge extends Recorder { private PrintStream logger; - private final boolean onlyAdminsMerge; - private final boolean disallowOwnCode; - private boolean onlyTriggerPhrase; - private String mergeComment; + private final Boolean onlyAdminsMerge; + private final Boolean disallowOwnCode; + private final Boolean onlyTriggerPhrase; + private final String mergeComment; + private final Boolean failOnNonMerge; + private final Boolean deleteOnMerge; @DataBoundConstructor - public GhprbPullRequestMerge(String mergeComment, boolean onlyTriggerPhrase, boolean onlyAdminsMerge, boolean disallowOwnCode) { + public GhprbPullRequestMerge( + String mergeComment, + boolean onlyTriggerPhrase, + boolean onlyAdminsMerge, + boolean disallowOwnCode, + boolean failOnNonMerge, + boolean deleteOnMerge) { this.mergeComment = mergeComment; this.onlyTriggerPhrase = onlyTriggerPhrase; this.onlyAdminsMerge = onlyAdminsMerge; this.disallowOwnCode = disallowOwnCode; + this.failOnNonMerge = failOnNonMerge; + this.deleteOnMerge = deleteOnMerge; } public String getMergeComment() { @@ -52,15 +64,25 @@ public String getMergeComment() { } public boolean isOnlyTriggerPhrase() { - return onlyTriggerPhrase; + return onlyTriggerPhrase == null ? false : onlyTriggerPhrase; } public boolean isOnlyAdminsMerge() { - return onlyAdminsMerge; + return onlyAdminsMerge == null ? false : onlyAdminsMerge; } public boolean isDisallowOwnCode() { - return disallowOwnCode; + return disallowOwnCode == null ? false : disallowOwnCode; + } + + + public boolean isFailOnNonMerge() { + return failOnNonMerge == null ? false : failOnNonMerge; + } + + + public boolean isDeleteOnMerge() { + return deleteOnMerge == null ? false : deleteOnMerge; } public BuildStepMonitor getRequiredMonitorService() { @@ -105,19 +127,11 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build return false; } - Boolean isMergeable = cause.isMerged(); - if (helper == null) { helper = new Ghprb(project, trigger, pulls); helper.init(); } - if (isMergeable == null || !isMergeable) { - logger.println("Pull request cannot be automerged."); - commentOnRequest("Pull request is not mergeable."); - listener.finished(Result.FAILURE); - return false; - } GHUser triggerSender = cause.getTriggerSender(); @@ -151,12 +165,21 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build commentOnRequest(String.format("Code not merged because %s has committed code in the request.", triggerSender.getName())); } + Boolean isMergeable = cause.isMerged(); + + if (isMergeable == null || !isMergeable) { + logger.println("Pull request cannot be automerged."); + commentOnRequest("Pull request is not mergeable."); + listener.finished(Result.FAILURE); + return false; + } + if (merge) { logger.println("Merging the pull request"); pr.merge(getMergeComment()); logger.println("Pull request successfully merged"); - // deleteBranch(); //TODO: Update so it also deletes the branch being pulled from. probably make it an option. + deleteBranch(build, launcher, listener); } if (merge) { @@ -167,14 +190,20 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build return merge; } - private void deleteBranch() { + private void deleteBranch(AbstractBuild build, Launcher launcher, final BuildListener listener) { + if (!deleteOnMerge){ + return; + } String branchName = pr.getHead().getRef(); try { - GHBranch branch = pr.getRepository().getBranches().get(branchName); + GHRepository repo = pr.getRepository(); + GHRef ref = repo.getRef("heads/" + branchName); + ref.delete(); + listener.getLogger().println("Deleted branch " + branchName); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + listener.getLogger().println("Unable to delete branch " + branchName); + e.printStackTrace(listener.getLogger()); } } @@ -187,14 +216,29 @@ private void commentOnRequest(String comment) { } } - private boolean isOwnCode(GHPullRequest pr, GHUser committer) { + private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { try { - String commentorName = committer.getName(); + String commentorName = commentor.getName(); + String commentorEmail = commentor.getEmail(); + String commentorLogin = commentor.getLogin(); + + GHUser prUser = pr.getUser(); + if (prUser != null && prUser.getLogin().equals(commentorLogin)) { + return true; + } + for (GHPullRequestCommitDetail detail : pr.listCommits()) { Commit commit = detail.getCommit(); - String committerName = commit.getCommitter().getName(); - - if (committerName.equalsIgnoreCase(commentorName)) { + GitUser committer = commit.getCommitter(); + String committerName = committer.getName(); + String committerEmail = committer.getEmail(); + + boolean isSame = false; + + isSame |= commentorName.equals(committerName); + isSame |= commentorEmail.equals(committerEmail); + + if (isSame) { return true; } } diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy index 6aefeca56..1f2e759f5 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy @@ -20,12 +20,46 @@ f.entry(title:_("Credentials"), field:"credentialsId") { } f.advanced(title:_("Test Credentials")) { - f.entry(title:_("Test Credentials")) { - f.validateButton(title:_("Connect to API"), progress:_("Connecting..."), with:"serverAPIUrl,credentialsId", method:"testGithubAccess") - f.entry(title:_("Repository owner/name"), field:"repo") { + f.optionalBlock(title:_("Test basic connection to GitHub")) { + f.entry() { + f.validateButton(title:_("Connect to API"), progress:_("Connecting..."), with:"serverAPIUrl,credentialsId", method:"testGithubAccess") + } + } + + f.entry(title:_("Repository owner/name"), field:"repo") { + f.textbox() + } + f.optionalBlock(title:_("Test Permissions to a Repository")) { + f.entry() { + f.validateButton(title:_("Check repo permissions"), progress:_("Checking..."), with:"serverAPIUrl,credentialsId,repo", method:"checkRepoAccess") + } + } + f.optionalBlock(title:_("Test adding comment to Pull Request")) { + f.entry(title:_("Issue ID"), field:"issueId") { + f.number() + } + f.entry(title:_("Comment to post"), field:"message1") { + f.textbox() + } + f.validateButton(title:_("Comment to issue"), progress:_("Commenting..."), with:"serverAPIUrl,credentialsId,repo,issueId,message1", method:"testComment") + } + f.optionalBlock(title:_("Test updating commit status")) { + f.entry(title:_("Commit SHA"), field:"sha1") { + f.textbox() + } + f.entry(title:_("Commit State"), field:"state") { + f.select() + } + f.entry(title:_("Status url"), field:"url") { + f.textbox() + } + f.entry(title:_("Message to post"), field:"message2") { + f.textbox() + } + f.entry(title:_("Context for the status"), field:"context") { f.textbox() } - f.validateButton(title:_("Check repo permissions"), progress:_("Connecting..."), with:"serverAPIUrl,credentialsId,repo", method:"checkRepoAccess") + f.validateButton(title:_("Update status"), progress:_("Updating..."), with:"serverAPIUrl,credentialsId,repo,sha1,state,url,message2,context", method:"testUpdateStatus") } } diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/config.jelly index d36347b90..d34fb4bd5 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/config.jelly @@ -11,4 +11,10 @@ + + + + + + diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index ff56c0b08..5a5a537bd 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -86,6 +86,9 @@ public class GhprbPullRequestMergeTest { private final String committerName = "committer"; private final String nonCommitterName = "noncommitter"; + + private final String committerEmail = "committer@mail.com"; + private final String nonCommitterEmail = "noncommitter@mail.com"; private final String mergeComment = "merge"; @@ -155,9 +158,10 @@ public void afterClass() { } @SuppressWarnings("unchecked") - private void setupConditions(String triggerLogin, String committerName, String comment) throws IOException { + private void setupConditions(String triggerLogin, String committerName, String committerEmail, String comment) throws IOException { given(triggerSender.getLogin()).willReturn(triggerLogin); given(triggerSender.getName()).willReturn(committerName); + given(triggerSender.getEmail()).willReturn(committerEmail); given(committer.getName()).willReturn(this.committerName); PagedIterator itr = Mockito.mock(PagedIterator.class); @@ -178,15 +182,34 @@ private void setupConditions(String triggerLogin, String committerName, String c given(cause.getCommentBody()).willReturn(comment); } - - private GhprbPullRequestMerge setupMerger(boolean onlyTriggerPhrase, boolean onlyAdminsMerge, boolean disallowOwnCode) { - GhprbPullRequestMerge merger = spy(new GhprbPullRequestMerge(mergeComment, onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode)); + + private GhprbPullRequestMerge setupMerger( + boolean onlyTriggerPhrase, + boolean onlyAdminsMerge, + boolean disallowOwnCode, + boolean failOnNonMerge, + boolean deleteOnMerge + ) { + + GhprbPullRequestMerge merger = spy(new GhprbPullRequestMerge( + mergeComment, + onlyTriggerPhrase, + onlyAdminsMerge, + disallowOwnCode, + failOnNonMerge, + deleteOnMerge)); merger.setHelper(helper); return merger; } + private GhprbPullRequestMerge setupMerger(boolean onlyTriggerPhrase, + boolean onlyAdminsMerge, + boolean disallowOwnCode) { + return setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode, false, false); + } + @Test public void testApproveMerge() throws Exception { @@ -196,28 +219,28 @@ public void testApproveMerge() throws Exception { GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); - setupConditions(nonAdminLogin, committerName, triggerPhrase); + setupConditions(nonAdminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(adminLogin, nonCommitterName, triggerPhrase); + setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(adminLogin, committerName, nonTriggerPhrase); + setupConditions(adminLogin, committerName, committerEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(nonAdminLogin, nonCommitterName, triggerPhrase); + setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(nonAdminLogin, nonCommitterName, nonTriggerPhrase); + setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(adminLogin, nonCommitterName, nonTriggerPhrase); + setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(nonAdminLogin, nonCommitterName, nonTriggerPhrase); + setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(adminLogin, committerName, triggerPhrase); + setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); } @@ -230,10 +253,10 @@ public void testAdminMerge() throws Exception { GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); - setupConditions(adminLogin, committerName, triggerPhrase); + setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(nonAdminLogin, committerName, triggerPhrase); + setupConditions(nonAdminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); } @@ -246,10 +269,10 @@ public void testTriggerMerge() throws Exception { GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); - setupConditions(adminLogin, committerName, triggerPhrase); + setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(adminLogin, committerName, nonTriggerPhrase); + setupConditions(adminLogin, committerName, committerEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); } @@ -262,10 +285,10 @@ public void testOwnCodeMerge() throws Exception { GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); - setupConditions(adminLogin, nonCommitterName, triggerPhrase); + setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); - setupConditions(adminLogin, committerName, triggerPhrase); + setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); } @@ -278,28 +301,28 @@ public void testDenyMerge() throws Exception { GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); - setupConditions(nonAdminLogin, nonCommitterName, triggerPhrase); + setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(adminLogin, committerName, triggerPhrase); + setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(adminLogin, nonCommitterName, nonTriggerPhrase); + setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(nonAdminLogin, nonCommitterName, triggerPhrase); + setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(nonAdminLogin, nonCommitterName, nonTriggerPhrase); + setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(adminLogin, committerName, nonTriggerPhrase); + setupConditions(adminLogin, committerName, committerEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(nonAdminLogin, committerName, nonTriggerPhrase); + setupConditions(nonAdminLogin, committerName, committerEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(adminLogin, nonCommitterName, triggerPhrase); + setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); } From 88c693b6dbe0c38aee16762ace5f6e54a13e7ffe Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 14 Jul 2015 21:43:45 -0600 Subject: [PATCH 006/175] [maven-release-plugin] prepare release ghprb-1.26 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2933ce890..e72d15e38 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.26-SNAPSHOT + 1.26 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.26 From 3909b227b8cf2f5d2f9b8388b85fab197e1cb9d4 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 14 Jul 2015 21:43:48 -0600 Subject: [PATCH 007/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e72d15e38..012a91cea 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.26 + 1.27-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.26 + HEAD From 410ec92490efeb6031ae9774b3596ece8284e7a9 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 15 Jul 2015 09:50:46 -0600 Subject: [PATCH 008/175] Fix null pointer when testing credentials --- .../java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java index acbee4bd0..819aa60f5 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java @@ -246,7 +246,7 @@ public FormValidation doCheckServerAPIUrl(@QueryParameter String value) { public FormValidation doCheckRepoAccess( @QueryParameter("serverAPIUrl") final String serverAPIUrl, @QueryParameter("credentialsId") final String credentialsId, - @QueryParameter("repo1") final String repo) { + @QueryParameter("repo") final String repo) { try { GitHubBuilder builder = getBuilder(null, serverAPIUrl, credentialsId); if (builder == null) { @@ -299,7 +299,7 @@ public FormValidation doTestGithubAccess( public FormValidation doTestComment( @QueryParameter("serverAPIUrl") final String serverAPIUrl, @QueryParameter("credentialsId") final String credentialsId, - @QueryParameter("repo2") final String repoName, + @QueryParameter("repo") final String repoName, @QueryParameter("issueId") final int issueId, @QueryParameter("message1") final String comment) { try { @@ -321,7 +321,7 @@ public FormValidation doTestComment( public FormValidation doTestUpdateStatus( @QueryParameter("serverAPIUrl") final String serverAPIUrl, @QueryParameter("credentialsId") final String credentialsId, - @QueryParameter("repo3") final String repoName, + @QueryParameter("repo") final String repoName, @QueryParameter("sha1") final String sha1, @QueryParameter("state") final GHCommitState state, @QueryParameter("url") final String url, From 4d62ba4f35d79478b2c6c1a8f9d083946ad2a4db Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 15 Jul 2015 09:54:39 -0600 Subject: [PATCH 009/175] [maven-release-plugin] prepare release ghprb-1.26.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 012a91cea..1d95c4880 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.27-SNAPSHOT + 1.26.1 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.26.1 From d364b4cdf3daa9e2daea4a44b0aefec6417e47d4 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 15 Jul 2015 09:54:42 -0600 Subject: [PATCH 010/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1d95c4880..012a91cea 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.26.1 + 1.27-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.26.1 + HEAD From c7bc0e92a9d5a6f89b031eb2064140c6cdd272b7 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 15 Jul 2015 11:48:22 -0600 Subject: [PATCH 011/175] Use failOnError setting Prevent null pointer when checking isOwnCode Fix tests and add a test for pr user login --- .../plugins/ghprb/GhprbPullRequestMerge.java | 18 +++++------ .../ghprb/GhprbPullRequestMergeTest.java | 31 +++++++++++++------ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 48a8e1b51..6cfdd96e8 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -182,16 +182,16 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build deleteBranch(build, launcher, listener); } - if (merge) { - listener.finished(Result.SUCCESS); - } else { + if (!merge && isFailOnNonMerge()) { listener.finished(Result.FAILURE); + } else { + listener.finished(Result.SUCCESS); } return merge; } private void deleteBranch(AbstractBuild build, Launcher launcher, final BuildListener listener) { - if (!deleteOnMerge){ + if (!isDeleteOnMerge()){ return; } String branchName = pr.getHead().getRef(); @@ -223,7 +223,7 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { String commentorLogin = commentor.getLogin(); GHUser prUser = pr.getUser(); - if (prUser != null && prUser.getLogin().equals(commentorLogin)) { + if (prUser.getLogin().equals(commentorLogin)) { return true; } @@ -235,12 +235,10 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { boolean isSame = false; - isSame |= commentorName.equals(committerName); - isSame |= commentorEmail.equals(committerEmail); + isSame |= commentorName != null && commentorName.equals(committerName); + isSame |= commentorEmail != null && commentorEmail.equals(committerEmail); - if (isSame) { - return true; - } + return isSame; } } catch (IOException e) { logger.println("Unable to get committer name"); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 5a5a537bd..316dfd44f 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -64,6 +64,8 @@ public class GhprbPullRequestMergeTest { @Mock private GHUser triggerSender; @Mock + private GHUser prCreator; + @Mock private GhprbCause cause; @Mock private Ghprb helper; @@ -158,11 +160,14 @@ public void afterClass() { } @SuppressWarnings("unchecked") - private void setupConditions(String triggerLogin, String committerName, String committerEmail, String comment) throws IOException { + private void setupConditions(String prUserLogin, String triggerLogin, String committerName, String committerEmail, String comment) throws IOException { given(triggerSender.getLogin()).willReturn(triggerLogin); given(triggerSender.getName()).willReturn(committerName); given(triggerSender.getEmail()).willReturn(committerEmail); given(committer.getName()).willReturn(this.committerName); + + given(prCreator.getLogin()).willReturn(prUserLogin); + given(pr.getUser()).willReturn(prCreator); PagedIterator itr = Mockito.mock(PagedIterator.class); PagedIterable pagedItr = Mockito.mock(PagedIterable.class); @@ -183,6 +188,10 @@ private void setupConditions(String triggerLogin, String committerName, String c given(cause.getCommentBody()).willReturn(comment); } + private void setupConditions(String triggerLogin, String committerName, String committerEmail, String comment) throws IOException { + setupConditions(nonCommitterName, triggerLogin, committerName, committerEmail, comment); + } + private GhprbPullRequestMerge setupMerger( boolean onlyTriggerPhrase, boolean onlyAdminsMerge, @@ -301,29 +310,33 @@ public void testDenyMerge() throws Exception { GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); - setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); + setupConditions(nonAdminLogin, nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); + setupConditions(nonAdminLogin, adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); + setupConditions(nonAdminLogin, adminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); + setupConditions(nonAdminLogin, nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); + setupConditions(nonAdminLogin, nonAdminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(adminLogin, committerName, committerEmail, nonTriggerPhrase); + setupConditions(nonAdminLogin, adminLogin, committerName, committerEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(nonAdminLogin, committerName, committerEmail, nonTriggerPhrase); + setupConditions(nonAdminLogin, nonAdminLogin, committerName, committerEmail, nonTriggerPhrase); + assertThat(merger.perform(build, null, listener)).isEqualTo(false); + + setupConditions(adminLogin, adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); - setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); + setupConditions(nonAdminLogin, adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + } } From 0954f344f6af9c416d213d968a6c088a357eb27b Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 15 Jul 2015 11:53:49 -0600 Subject: [PATCH 012/175] [maven-release-plugin] prepare release ghprb-1.26.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 012a91cea..72123c16f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.27-SNAPSHOT + 1.26.2 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.26.2 From ce547bf3e51aed49ed2ad8b38fad2d0c7fd5f28e Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 15 Jul 2015 11:53:52 -0600 Subject: [PATCH 013/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 72123c16f..e3d73377f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.26.2 + 1.26.3-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.26.2 + HEAD From 9f6a58814424e54bbe05fe686a9f348c2628bfc0 Mon Sep 17 00:00:00 2001 From: Antoine Duprat Date: Fri, 7 Aug 2015 10:12:07 +0200 Subject: [PATCH 014/175] [JENKINS-29850] Add author github repo URL --- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 2 +- .../jenkinsci/plugins/ghprb/GhprbCause.java | 8 +- .../plugins/ghprb/GhprbPullRequest.java | 16 +++- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 1 + .../plugins/ghprb/GhprbPullRequestTest.java | 76 +++++++++++++++++++ .../plugins/ghprb/GhprbRepositoryTest.java | 6 +- 6 files changed, 102 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 818553d7c..c79c53a4e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -40,7 +40,7 @@ public GhprbBuilds(GhprbTrigger trigger, GhprbRepository repo) { public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) { GhprbCause cause = new GhprbCause(pr.getHead(), pr.getId(), pr.isMergeable(), pr.getTarget(), pr.getSource(), pr.getAuthorEmail(), pr.getTitle(), pr.getUrl(), triggerSender, commentBody, - pr.getCommitAuthor()); + pr.getCommitAuthor(), pr.getAuthorRepoGitUrl()); for (GhprbExtension ext : Ghprb.getJobExtensions(trigger, GhprbCommitStatus.class)) { if (ext instanceof GhprbCommitStatus) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java index ba8cce14c..33ac51592 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java @@ -23,6 +23,7 @@ public class GhprbCause extends Cause { private final GHUser triggerSender; private final String commentBody; private final GitUser commitAuthor; + private final String authorRepoGitUrl; public GhprbCause(String commit, int pullID, @@ -34,7 +35,8 @@ public GhprbCause(String commit, URL url, GHUser triggerSender, String commentBody, - GitUser commitAuthor) { + GitUser commitAuthor, + String authorRepoGitUrl) { this.commit = commit; this.pullID = pullID; @@ -48,6 +50,7 @@ public GhprbCause(String commit, this.triggerSender = triggerSender; this.commentBody = commentBody; this.commitAuthor = commitAuthor; + this.authorRepoGitUrl = authorRepoGitUrl; } @Override @@ -113,4 +116,7 @@ public GitUser getCommitAuthor() { return commitAuthor; } + public String getAuthorRepoGitUrl() { + return authorRepoGitUrl; + } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 77db13e7d..6147f7989 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -3,10 +3,12 @@ import com.google.common.base.Joiner; import org.apache.commons.lang.StringUtils; +import org.kohsuke.github.GHCommitPointer; import org.kohsuke.github.GHIssue; import org.kohsuke.github.GHIssueComment; import org.kohsuke.github.GHPullRequest; import org.kohsuke.github.GHPullRequestCommitDetail; +import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHUser; import org.kohsuke.github.GitUser; @@ -36,6 +38,7 @@ public class GhprbPullRequest { private String title; private Date updated; private String head; + private String authorRepoGitUrl; private boolean mergeable; private String reponame; private String target; @@ -63,12 +66,17 @@ public class GhprbPullRequest { e.printStackTrace(); updated = new Date(); } - head = pr.getHead().getSha(); + GHCommitPointer commitPointer = pr.getHead(); + head = commitPointer.getSha(); title = pr.getTitle(); author = pr.getUser(); + GHRepository repository = commitPointer.getRepository(); + if (repository != null) { + authorRepoGitUrl = repository.gitHttpTransportUrl(); + } reponame = repo.getName(); target = pr.getBase().getRef(); - source = pr.getHead().getRef(); + source = commitPointer.getRef(); url = pr.getHtmlUrl(); this.pr = pr; obtainAuthorEmail(pr); @@ -424,6 +432,10 @@ public String getHead() { return head; } + public String getAuthorRepoGitUrl() { + return authorRepoGitUrl; + } + public boolean isMergeable() { return mergeable; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index e4a1629bb..942bfc9f8 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -237,6 +237,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { } catch (Exception e) {} setCommitAuthor(cause, values); + values.add(new StringParameterValue("ghprbAuthorRepoGitUrl", cause.getAuthorRepoGitUrl())); values.add(new StringParameterValue("ghprbTriggerAuthor", triggerAuthor)); values.add(new StringParameterValue("ghprbTriggerAuthorEmail", triggerAuthorEmail)); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java index fccf277d3..2914aa549 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java @@ -4,6 +4,7 @@ import org.junit.runner.RunWith; import org.kohsuke.github.GHCommitPointer; import org.kohsuke.github.GHPullRequest; +import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHUser; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -143,4 +144,79 @@ public void testInitRepoNameNotNull() throws IOException { verify(ghprbRepository, never()).getName(); } + @Test + public void authorRepoGitUrlShouldBeNullWhenNoRepository() throws Exception { + // GIVEN + GHUser ghUser = mock(GHUser.class); + GHCommitPointer head = mock(GHCommitPointer.class); + GHCommitPointer base = mock(GHCommitPointer.class); + + // Mocks for GHPullRequest + given(pr.getNumber()).willReturn(10); + given(pr.getUpdatedAt()).willReturn(new Date()); + given(pr.getTitle()).willReturn("title"); + given(pr.getHead()).willReturn(head); + given(pr.getBase()).willReturn(base); + given(head.getSha()).willReturn("some sha"); + given(base.getRef()).willReturn("some ref"); + given(pr.getUser()).willReturn(ghUser); + given(ghUser.getEmail()).willReturn("email"); + + // Mocks for GhprbRepository + given(repo.getName()).willReturn("name"); + doNothing().when(repo).addComment(eq(10), anyString()); + + // Mocks for Ghprb + given(helper.isWhitelisted(ghUser)).willReturn(true); + + GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); + GhprbRepository ghprbRepository = mock(GhprbRepository.class); + given(ghprbRepository.getName()).willReturn("name"); + + // WHEN + ghprbPullRequest.init(helper, ghprbRepository); + + // THEN + assertThat(ghprbPullRequest.getAuthorRepoGitUrl()).isNull(); + } + + @Test + public void authorRepoGitUrlShouldBeSetWhenRepository() throws Exception { + // GIVEN + GHUser ghUser = mock(GHUser.class); + GHCommitPointer head = mock(GHCommitPointer.class); + GHCommitPointer base = mock(GHCommitPointer.class); + GHRepository repository = mock(GHRepository.class); + + // Mocks for GHPullRequest + given(pr.getNumber()).willReturn(10); + given(pr.getUpdatedAt()).willReturn(new Date()); + given(pr.getTitle()).willReturn("title"); + given(pr.getHead()).willReturn(head); + given(pr.getBase()).willReturn(base); + given(head.getSha()).willReturn("some sha"); + given(base.getRef()).willReturn("some ref"); + given(pr.getUser()).willReturn(ghUser); + given(ghUser.getEmail()).willReturn("email"); + given(head.getRepository()).willReturn(repository); + String expectedAuthorRepoGitUrl = "https://github.com/jenkinsci/ghprb-plugin"; + given(repository.gitHttpTransportUrl()).willReturn(expectedAuthorRepoGitUrl); + + // Mocks for GhprbRepository + given(repo.getName()).willReturn("name"); + doNothing().when(repo).addComment(eq(10), anyString()); + + // Mocks for Ghprb + given(helper.isWhitelisted(ghUser)).willReturn(true); + + GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); + GhprbRepository ghprbRepository = mock(GhprbRepository.class); + given(ghprbRepository.getName()).willReturn("name"); + + // WHEN + ghprbPullRequest.init(helper, ghprbRepository); + + // THEN + assertThat(ghprbPullRequest.getAuthorRepoGitUrl()).isEqualTo(expectedAuthorRepoGitUrl); + } } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 8011fdae5..7b9bc8ad3 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -235,7 +235,7 @@ public void testCheckMethodWithNewPR() throws IOException { verify(ghPullRequest, times(1)).getTitle(); verify(ghPullRequest, times(2)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(8)).getHead(); + verify(ghPullRequest, times(7)).getHead(); verify(ghPullRequest, times(3)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(3)).getUpdatedAt(); @@ -311,7 +311,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(ghPullRequest, times(2)).getTitle(); verify(ghPullRequest, times(2)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(8)).getHead(); + verify(ghPullRequest, times(7)).getHead(); verify(ghPullRequest, times(3)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(1)).getHtmlUrl(); @@ -395,7 +395,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(ghPullRequest, times(2)).getTitle(); verify(ghPullRequest, times(2)).getUser(); verify(ghPullRequest, times(2)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(8)).getHead(); + verify(ghPullRequest, times(7)).getHead(); verify(ghPullRequest, times(3)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(3)).getUpdatedAt(); From cf6271b399c32e0bf6844f25a722ad936ff40541 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 11 Aug 2015 22:00:55 -0600 Subject: [PATCH 015/175] Allow multiline for regex. Trigger is regex. Add description. All regex matching uses DOTALL and IGNORECASE. The trigger phrase has been updated to be a regex. If it had special characters, they have been quoted. Add the description to the cause and env variables --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 53 +++++++++-- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 2 +- .../jenkinsci/plugins/ghprb/GhprbCause.java | 11 ++- .../plugins/ghprb/GhprbPullRequest.java | 59 ++++--------- .../plugins/ghprb/GhprbPullRequestMerge.java | 9 +- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 2 +- .../GhprbTriggerBackwardsCompatible.java | 9 +- .../plugins/ghprb/GhprbRepositoryTest.java | 7 +- .../plugins/ghprb/GhprbTriggerTest.java | 88 +++++++++++++++---- 9 files changed, 162 insertions(+), 78 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 1f7f2a6de..9c2dc1a50 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -37,6 +37,7 @@ import org.jenkinsci.plugins.ghprb.extensions.GhprbProjectExtension; import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl; import org.kohsuke.github.GHCommitState; +import org.kohsuke.github.GHIssue; import org.kohsuke.github.GHUser; import java.net.URI; @@ -122,24 +123,62 @@ void stop() { repository = null; builds = null; } + + public static Pattern compilePattern(String regex) { + return Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL); + } // These used to be stored on the object in the constructor. // But because the object is only instantiated once per PR, configuration would go stale. // Some optimization could be done around re-compiling regex/hash sets, but beyond that we still have to re-pull the text. private Pattern retestPhrasePattern() { - return Pattern.compile(trigger.getDescriptor().getRetestPhrase()); + return compilePattern(trigger.getDescriptor().getRetestPhrase()); } - + + /** + * Returns skip build phrases from Jenkins global configuration + * + * @return + */ + public Set getSkipBuildPhrases() { + return new HashSet(Arrays.asList(GhprbTrigger.getDscp().getSkipBuildPhrase().split("[\\r\\n]+"))); + } + + /** + * Checks for skip build phrase in pull request comment. If present it updates shouldRun as false. + * + * @param issue + */ + public String checkSkipBuild(GHIssue issue) { + // check for skip build phrase. + String pullRequestBody = issue.getBody(); + if (StringUtils.isNotBlank(pullRequestBody)) { + pullRequestBody = pullRequestBody.trim(); + Set skipBuildPhrases = getSkipBuildPhrases(); + skipBuildPhrases.remove(""); + + for (String skipBuildPhrase : skipBuildPhrases) { + skipBuildPhrase = skipBuildPhrase.trim(); + Pattern skipBuildPhrasePattern = compilePattern(skipBuildPhrase); + + if (skipBuildPhrasePattern.matcher(pullRequestBody).matches()) { + return skipBuildPhrase; + } + } + } + return null; + } + private Pattern whitelistPhrasePattern() { - return Pattern.compile(trigger.getDescriptor().getWhitelistPhrase()); + return compilePattern(trigger.getDescriptor().getWhitelistPhrase()); } private Pattern oktotestPhrasePattern() { - return Pattern.compile(trigger.getDescriptor().getOkToTestPhrase()); + return compilePattern(trigger.getDescriptor().getOkToTestPhrase()); } - private String triggerPhrase() { - return trigger.getTriggerPhrase(); + private Pattern triggerPhrase() { + return compilePattern(trigger.getTriggerPhrase()); } private HashSet admins() { @@ -176,7 +215,7 @@ public boolean isOktotestPhrase(String comment) { } public boolean isTriggerPhrase(String comment) { - return !triggerPhrase().equals("") && comment != null && comment.contains(triggerPhrase()); + return triggerPhrase().matcher(comment).matches(); } public boolean ifOnlyTriggerPhrase() { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 83a140a91..86643ee18 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -40,7 +40,7 @@ public GhprbBuilds(GhprbTrigger trigger, GhprbRepository repo) { public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) { GhprbCause cause = new GhprbCause(pr.getHead(), pr.getId(), pr.isMergeable(), pr.getTarget(), pr.getSource(), pr.getAuthorEmail(), pr.getTitle(), pr.getUrl(), triggerSender, commentBody, - pr.getCommitAuthor(), pr.getPullRequestAuthor()); + pr.getCommitAuthor(), pr.getPullRequestAuthor(), pr.getDescription()); for (GhprbExtension ext : Ghprb.getJobExtensions(trigger, GhprbCommitStatus.class)) { if (ext instanceof GhprbCommitStatus) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java index c9e34fe83..c88fc2644 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCause.java @@ -24,6 +24,7 @@ public class GhprbCause extends Cause { private final String commentBody; private final GitUser commitAuthor; private final GHUser pullRequestAuthor; + private final String description; public GhprbCause(String commit, int pullID, @@ -36,7 +37,8 @@ public GhprbCause(String commit, GHUser triggerSender, String commentBody, GitUser commitAuthor, - GHUser pullRequestAuthor) { + GHUser pullRequestAuthor, + String description) { this.commit = commit; this.pullID = pullID; @@ -46,13 +48,14 @@ public GhprbCause(String commit, this.authorEmail = authorEmail; this.title = title; this.url = url; + this.description = description; this.triggerSender = triggerSender; this.commentBody = commentBody; this.commitAuthor = commitAuthor; this.pullRequestAuthor = pullRequestAuthor; } - + @Override public String getShortDescription() { return "GitHub pull request #" + pullID + " of commit " + commit + (merged ? ", no merge conflicts." : ", has merge conflicts."); @@ -119,5 +122,9 @@ public String getAbbreviatedTitle() { public GitUser getCommitAuthor() { return commitAuthor; } + + public String getDescription() { + return description; + } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 741a212cb..cec422448 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -12,14 +12,10 @@ import java.io.IOException; import java.net.URL; -import java.util.Arrays; import java.util.Date; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.regex.Pattern; /** * Maintains state about a Pull Request for a particular Jenkins job. This is what understands the current state of a PR for a particular job. @@ -42,6 +38,7 @@ public class GhprbPullRequest { private String source; private String authorEmail; private URL url; + private String description; private GHUser triggerSender; private GitUser commitAuthor; @@ -55,7 +52,7 @@ public class GhprbPullRequest { private String commentBody; - GhprbPullRequest(GHPullRequest pr, Ghprb helper, GhprbRepository repo) { + public GhprbPullRequest(GHPullRequest pr, Ghprb helper, GhprbRepository repo) { id = pr.getNumber(); try { updated = pr.getUpdatedAt(); @@ -75,6 +72,7 @@ public class GhprbPullRequest { this.helper = helper; this.repo = repo; + this.description = pr.getBody(); if (helper.isWhitelisted(author)) { accepted = true; @@ -97,40 +95,6 @@ public void init(Ghprb helper, GhprbRepository repo) { } } - /** - * Returns skip build phrases from Jenkins global configuration - * - * @return - */ - public Set getSkipBuildPhrases() { - return new HashSet(Arrays.asList(GhprbTrigger.getDscp().getSkipBuildPhrase().split("[\\r\\n]+"))); - } - - /** - * Checks for skip build phrase in pull request comment. If present it updates shouldRun as false. - * - * @param issue - */ - private void checkSkipBuild(GHIssue issue) { - // check for skip build phrase. - String pullRequestBody = issue.getBody(); - if (StringUtils.isNotBlank(pullRequestBody)) { - pullRequestBody = pullRequestBody.trim(); - Set skipBuildPhrases = getSkipBuildPhrases(); - skipBuildPhrases.remove(""); - - for (String skipBuildPhrase : skipBuildPhrases) { - skipBuildPhrase = skipBuildPhrase.trim(); - Pattern skipBuildPhrasePattern = Pattern.compile(skipBuildPhrase, Pattern.CASE_INSENSITIVE); - if (skipBuildPhrasePattern.matcher(pullRequestBody).matches()) { - logger.log(Level.INFO, "Pull request commented with {0} skipBuildPhrase. Hence skipping the build.", skipBuildPhrase); - shouldRun = false; - break; - } - } - } - } - /** * Checks this Pull Request representation against a GitHub version of the Pull Request, and triggers a build if necessary. * @@ -149,10 +113,18 @@ public void check(GHPullRequest pr) { } updatePR(pr, author); - + checkSkipBuild(pr); tryBuild(pr); } + + private void checkSkipBuild(GHIssue issue) { + String skipBuildPhrase = helper.checkSkipBuild(issue); + if (!StringUtils.isEmpty(skipBuildPhrase)) { + logger.log(Level.INFO, "Pull request commented with {0} skipBuildPhrase. Hence skipping the build.", skipBuildPhrase); + shouldRun = false; + } + } public void check(GHIssueComment comment) { if (helper.isProjectDisabled()) { @@ -189,8 +161,9 @@ private void updatePR(GHPullRequest pr, GHUser author) { accepted = true; } - // the title could have been updated since the original PR was opened + // the title or description could have been updated since the original PR was opened title = pr.getTitle(); + description = pr.getBody(); int commentsChecked = checkComments(pr, lastUpdateTime); boolean newCommit = checkCommit(pr.getHead().getSha()); @@ -464,4 +437,8 @@ public GHUser getPullRequestAuthor() { public GHPullRequest getPullRequest() { return pr; } + + public String getDescription() { + return description; + } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 6cfdd96e8..852f32eb5 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -112,7 +112,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build if (trigger == null) return false; - cause = getCause(build); + cause = Ghprb.getCause(build); if (cause == null) { return true; } @@ -247,13 +247,6 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { return false; } - private GhprbCause getCause(AbstractBuild build) { - Cause cause = build.getCause(GhprbCause.class); - if (cause == null || (!(cause instanceof GhprbCause))) - return null; - return (GhprbCause) cause; - } - @Extension(ordinal = -1) public static class DescriptorImpl extends BuildStepDescriptor { @Override diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 991f778cb..bafdaef73 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -57,7 +57,6 @@ public class GhprbTrigger extends GhprbTriggerBackwardsCompatible { private final Boolean allowMembersOfWhitelistedOrgsAsAdmin; private final String orgslist; private final String cron; - private final String triggerPhrase; private final String buildDescTemplate; private final Boolean onlyTriggerPhrase; private final Boolean useGitHubHooks; @@ -259,6 +258,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbPullDescription", String.valueOf(cause.getShortDescription()))); values.add(new StringParameterValue("ghprbPullTitle", String.valueOf(cause.getTitle()))); values.add(new StringParameterValue("ghprbPullLink", String.valueOf(cause.getUrl()))); + values.add(new StringParameterValue("ghprbPullLongDescription", String.valueOf(cause.getDescription()))); // add the previous pr BuildData as an action so that the correct change log is generated by the GitSCM plugin // note that this will be removed from the Actions list after the job is completed so that the old (and incorrect) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java index cff33d046..3becaa477 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; @@ -23,6 +24,7 @@ public abstract class GhprbTriggerBackwardsCompatible extends Trigger getExtensions(); + protected String triggerPhrase; protected Integer configVersion; public GhprbTriggerBackwardsCompatible(String cron) throws ANTLRException { @@ -41,17 +43,22 @@ public GhprbTriggerBackwardsCompatible(String cron) throws ANTLRException { @Deprecated protected transient GhprbGitHubAuth gitHubApiAuth; + + protected void convertPropertiesToExtensions() { if (configVersion == null) { configVersion = 0; } + if (configVersion <= 2 && !StringUtils.isEmpty(triggerPhrase)) { + triggerPhrase = Pattern.quote(triggerPhrase); + } checkCommentsFile(); checkBuildStatusMessages(); checkCommitStatusContext(); - configVersion = 2; + configVersion = 3; } private void checkBuildStatusMessages() { diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 8011fdae5..a37e48e25 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -179,12 +179,12 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(2)).getNumber(); verify(ghPullRequest, times(1)).getUpdatedAt(); - verify(ghPullRequest, times(1)).getBody(); verifyNoMoreInteractions(ghPullRequest); verify(helper).ifOnlyTriggerPhrase(); verify(helper).getWhiteListTargetBranches(); verify(helper, times(3)).isProjectDisabled(); + verify(helper).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); verifyNoMoreInteractions(gt); @@ -241,7 +241,7 @@ public void testCheckMethodWithNewPR() throws IOException { verify(ghPullRequest, times(3)).getUpdatedAt(); verify(ghPullRequest, times(1)).getHtmlUrl(); verify(ghPullRequest, times(1)).listCommits(); - verify(ghPullRequest, times(2)).getBody(); + verify(ghPullRequest, times(1)).getBody(); verifyNoMoreInteractions(ghPullRequest); verify(helper, times(1)).isWhitelisted(eq(ghUser)); // Call to Github API @@ -249,6 +249,7 @@ public void testCheckMethodWithNewPR() throws IOException { verify(helper, times(1)).getBuilds(); verify(helper, times(2)).getWhiteListTargetBranches(); verify(helper, times(5)).isProjectDisabled(); + verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); verify(ghUser, times(1)).getEmail(); // Call to Github API @@ -333,6 +334,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(helper).isRetestPhrase(eq("comment body")); verify(helper).isTriggerPhrase(eq("comment body")); verify(helper, times(6)).isProjectDisabled(); + verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); verify(ghUser, times(1)).getEmail(); // Call to Github API @@ -417,6 +419,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(helper).isRetestPhrase(eq("test this please")); verify(helper).isAdmin(eq(ghUser)); verify(helper, times(6)).isProjectDisabled(); + verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); verify(ghUser, times(1)).getEmail(); // Call to Github API diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java index 0022e0412..b4817eedb 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java @@ -5,10 +5,12 @@ import static org.mockito.Mockito.*; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.regex.Pattern; @@ -26,36 +28,92 @@ public class GhprbTriggerTest { @Mock private GhprbPullRequest pr; + + @Mock + private Ghprb helper; @Test public void testCheckSkipBuild() throws Exception { GHIssue issue = mock(GHIssue.class); - - String[] comments = { "Some dumb comment\r\nThat shouldn't match", "[skip ci]" }; - String[] phraseArray = { "\\[skip\\W+ci\\]", "skip ci" }; - + + boolean skipBuild = false; + boolean build = true; + + String nonMatch = "Some dumb comment\r\nThat shouldn't match"; + String multiLine = "This is a multiline skip\r\n[skip ci]"; + String justSkipCi = "skip ci"; + String fullSkipCi = "[skip ci]"; + + Map> stringsToTest = new HashMap>(10); + + Map comment = new HashMap(5); + comment.put(nonMatch, build); + comment.put(multiLine, skipBuild); + comment.put(justSkipCi, build); + comment.put(fullSkipCi, skipBuild); + stringsToTest.put(".*\\[skip\\W+ci\\].*", comment); + + comment = new HashMap(5); + comment.put(nonMatch, build); + comment.put(multiLine, build); + comment.put(justSkipCi, build); + comment.put(fullSkipCi, skipBuild); + stringsToTest.put("\\[skip ci\\]", comment); + + comment = new HashMap(5); + comment.put(nonMatch, build); + comment.put(multiLine, skipBuild); + comment.put(justSkipCi, skipBuild); + comment.put(fullSkipCi, skipBuild); + stringsToTest.put("\\[skip ci\\]\n.*\\[skip\\W+ci\\].*\nskip ci", comment); + Method checkSkip = GhprbPullRequest.class.getDeclaredMethod("checkSkipBuild", GHIssue.class); checkSkip.setAccessible(true); Field shouldRun = GhprbPullRequest.class.getDeclaredField("shouldRun"); shouldRun.setAccessible(true); + + Field prHelper = GhprbPullRequest.class.getDeclaredField("helper"); + prHelper.setAccessible(true); + prHelper.set(pr, helper); - for (String phraseString : phraseArray) { - for (String comment : comments) { + for (Entry> skipMap : stringsToTest.entrySet()) { + String skipPhrases = skipMap.getKey(); - Set phrases = new HashSet(Arrays.asList(phraseString.split("[\\r\\n]+"))); - given(issue.getBody()).willReturn(comment); - given(pr.getSkipBuildPhrases()).willReturn(phrases); - boolean isMatch = false; - for (String phrase : phrases) { - isMatch = Pattern.matches(phrase, comment); - if (isMatch) { + Set phrases = new HashSet(Arrays.asList(skipPhrases.split("[\\r\\n]+"))); + + given(helper.getSkipBuildPhrases()).willReturn(phrases); + + for (Entry skipResults : skipMap.getValue().entrySet()) { + String nextComment = skipResults.getKey(); + Boolean shouldBuild = skipResults.getValue(); + + given(issue.getBody()).willReturn(nextComment); + String skipPhrase = ""; + + for (String skipBuildPhrase : phrases) { + skipBuildPhrase = skipBuildPhrase.trim(); + Pattern skipBuildPhrasePattern = Ghprb.compilePattern(skipBuildPhrase); + + if (skipBuildPhrasePattern.matcher(nextComment).matches()) { + skipPhrase = skipBuildPhrase; break; } } + + given(helper.checkSkipBuild(issue)).willReturn(skipPhrase); + shouldRun.set(pr, true); checkSkip.invoke(pr, issue); - assertThat(shouldRun.get(pr)).isEqualTo(!isMatch); + String errorMessage = String.format("Comment does %scontain skip phrase \n(\n%s\n)\n[\n%s\n]", shouldBuild ? "not ": "", nextComment, skipPhrases); + + if (shouldBuild) { + assertThat(skipPhrase).overridingErrorMessage(errorMessage).isEmpty(); + } else { + assertThat(skipPhrase).overridingErrorMessage(errorMessage).isNotEmpty(); + } + + assertThat(shouldRun.get(pr)).overridingErrorMessage(errorMessage).isEqualTo(shouldBuild); } } From aeb85d4721a206beaed9b46af546c894e7769e2f Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 14 Aug 2015 09:00:12 -0600 Subject: [PATCH 016/175] Update readme. Fixed #151. Fixed #105 Fixed https://github.com/janinko/ghprb/pull/313 --- README.md | 6 ++++++ src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 1 + 2 files changed, 7 insertions(+) diff --git a/README.md b/README.md index 02add543e..f5e3cd91b 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,12 @@ If you want to manually build the job, in the job setting check ``This build is ### Updates +#### -> 1.27 +* Trigger is now a regex term +* Phrases are no matched agains multiple lines properly +* All regex patterns use ignore case and dotall +* Added variables to the parameters + #### -> 1.26 * Extend the checking for own code. * Fail build only when desired if we can't merge the build. diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index bafdaef73..ad2a2cf84 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -259,6 +259,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbPullTitle", String.valueOf(cause.getTitle()))); values.add(new StringParameterValue("ghprbPullLink", String.valueOf(cause.getUrl()))); values.add(new StringParameterValue("ghprbPullLongDescription", String.valueOf(cause.getDescription()))); + values.add(new StringParameterValue("ghprbCommentBody", String.valueOf(cause.getCommentBody()))); // add the previous pr BuildData as an action so that the correct change log is generated by the GitSCM plugin // note that this will be removed from the Actions list after the job is completed so that the old (and incorrect) From c36f4dfd81a73a350ba18da6cbe96fe877fc2479 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 14 Aug 2015 09:03:34 -0600 Subject: [PATCH 017/175] [maven-release-plugin] prepare release ghprb-1.27 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e3d73377f..9f7cf1f87 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.26.3-SNAPSHOT + 1.27 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.27 From c875ec2de0a617924201eeda0a0796744c2796cf Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 14 Aug 2015 09:03:36 -0600 Subject: [PATCH 018/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9f7cf1f87..632f3a851 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.27 + 1.28-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.27 + HEAD From 6dcf06ad9f7c800c3b18ed3f01fb2a27f08fed81 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Sun, 16 Aug 2015 06:05:52 -0400 Subject: [PATCH 019/175] Fixing NPE and non-sensical behavior of the GHPRB 1. Fix NPEs where `triggerSender` is not available 2. Infer intent to merge based on comment trigger 3. If merge can only triggered by comment and there is no comment, there is no intent to merge, therefore do not fail or check other conditions 4. Do not post comments about commentors not being Admins etc if build is triggered by automation connected to #158, fixes #158 --- .../plugins/ghprb/GhprbPullRequestMerge.java | 54 ++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 852f32eb5..c2f2c4203 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -143,38 +143,55 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build return false; } - boolean merge = true; + boolean intendToMerge = false, commentTrigger = false; + boolean canMerge = true; String commentBody = cause.getCommentBody(); - if (isOnlyAdminsMerge() && (triggerSender == null || !helper.isAdmin(triggerSender) )) { - merge = false; - logger.println("Only admins can merge this pull request, " + triggerSender.getLogin() + " is not an admin."); - commentOnRequest(String.format("Code not merged because %s is not in the Admin list.", triggerSender.getName())); + if (isOnlyTriggerPhrase()) { + // If merge can only be triggered by a comment and there is a + // comment + if (commentBody == null || !helper.isTriggerPhrase(commentBody)) { + logger.println("The comment does not contain the required trigger phrase."); + } else { + intendToMerge = true; + commentTrigger = true; + } + } else { + intendToMerge = true; } - if (isOnlyTriggerPhrase() && (commentBody == null || !helper.isTriggerPhrase(cause.getCommentBody()) )) { - merge = false; - logger.println("The comment does not contain the required trigger phrase."); - - commentOnRequest(String.format("Please comment with '%s' to automerge this request", trigger.getTriggerPhrase())); + // If there is no intention to merge there is no point checking + if (intendToMerge && isOnlyAdminsMerge() && (triggerSender == null || !helper.isAdmin(triggerSender))) { + canMerge = false; + logger.println("Only admins can merge this pull request, " + + (triggerSender != null ? triggerSender.getLogin() + " is not an admin" + : " and build was triggered via automation") + "."); + if (commentTrigger && triggerSender != null) { + commentOnRequest(String.format("Code not merged because %s is not in the Admin list.", triggerSender.getName())); + } } - if (isDisallowOwnCode() && (triggerSender == null || isOwnCode(pr, triggerSender) )) { - merge = false; - logger.println("The commentor is also one of the contributors."); - commentOnRequest(String.format("Code not merged because %s has committed code in the request.", triggerSender.getName())); + // If there is no intention to merge there is no point checking + if (intendToMerge && isDisallowOwnCode() && (triggerSender == null || isOwnCode(pr, triggerSender))) { + canMerge = false; + if (commentTrigger && triggerSender != null) { + logger.println("The commentor is also one of the contributors."); + commentOnRequest(String.format("Code not merged because %s has committed code in the request.", + triggerSender.getName())); + } } Boolean isMergeable = cause.isMerged(); - if (isMergeable == null || !isMergeable) { + // The build should not fail if no merge is expected + if (intendToMerge && canMerge && (isMergeable == null || !isMergeable)) { logger.println("Pull request cannot be automerged."); commentOnRequest("Pull request is not mergeable."); listener.finished(Result.FAILURE); return false; } - if (merge) { + if (intendToMerge && canMerge) { logger.println("Merging the pull request"); pr.merge(getMergeComment()); @@ -182,12 +199,13 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build deleteBranch(build, launcher, listener); } - if (!merge && isFailOnNonMerge()) { + // We should only fail the build if the trigger phrase is NOT used + if (intendToMerge && !canMerge && isFailOnNonMerge()) { listener.finished(Result.FAILURE); } else { listener.finished(Result.SUCCESS); } - return merge; + return canMerge; } private void deleteBranch(AbstractBuild build, Launcher launcher, final BuildListener listener) { From 3eaa8b8d9bc12b5e84492b98ff0e1520625de861 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Sun, 16 Aug 2015 07:29:30 -0400 Subject: [PATCH 020/175] Fix unit tests to comply with new behavior --- .../plugins/ghprb/GhprbPullRequestMergeTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 316dfd44f..8db3519cc 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -282,7 +282,7 @@ public void testTriggerMerge() throws Exception { assertThat(merger.perform(build, null, listener)).isEqualTo(true); setupConditions(adminLogin, committerName, committerEmail, nonTriggerPhrase); - assertThat(merger.perform(build, null, listener)).isEqualTo(false); + assertThat(merger.perform(build, null, listener)).isEqualTo(true); } @Test @@ -317,19 +317,19 @@ public void testDenyMerge() throws Exception { assertThat(merger.perform(build, null, listener)).isEqualTo(false); setupConditions(nonAdminLogin, adminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); - assertThat(merger.perform(build, null, listener)).isEqualTo(false); + assertThat(merger.perform(build, null, listener)).isEqualTo(true); setupConditions(nonAdminLogin, nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); setupConditions(nonAdminLogin, nonAdminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); - assertThat(merger.perform(build, null, listener)).isEqualTo(false); + assertThat(merger.perform(build, null, listener)).isEqualTo(true); setupConditions(nonAdminLogin, adminLogin, committerName, committerEmail, nonTriggerPhrase); - assertThat(merger.perform(build, null, listener)).isEqualTo(false); + assertThat(merger.perform(build, null, listener)).isEqualTo(true); setupConditions(nonAdminLogin, nonAdminLogin, committerName, committerEmail, nonTriggerPhrase); - assertThat(merger.perform(build, null, listener)).isEqualTo(false); + assertThat(merger.perform(build, null, listener)).isEqualTo(true); setupConditions(adminLogin, adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); From b2dab2f6b0628633de41b115d55ab9dfe8010606 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Wed, 19 Aug 2015 07:42:20 -0400 Subject: [PATCH 021/175] Remove onlyTriggerPhrase option, trigger-phrase-only behavior is now the only possible one Update unit tests to validate new behavior --- .../plugins/ghprb/GhprbPullRequestMerge.java | 53 ++++++++++--------- .../ghprb/GhprbPullRequestMerge/config.jelly | 3 -- .../ghprb/GhprbPullRequestMerge/global.jelly | 3 -- .../help-onlyTriggerPhrase.html | 4 -- .../ghprb/GhprbPullRequestMergeTest.java | 26 +++++++++ 5 files changed, 53 insertions(+), 36 deletions(-) delete mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/help-onlyTriggerPhrase.html diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index c2f2c4203..f76110ce4 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -37,34 +37,38 @@ public class GhprbPullRequestMerge extends Recorder { private final Boolean onlyAdminsMerge; private final Boolean disallowOwnCode; - private final Boolean onlyTriggerPhrase; private final String mergeComment; private final Boolean failOnNonMerge; private final Boolean deleteOnMerge; @DataBoundConstructor public GhprbPullRequestMerge( - String mergeComment, - boolean onlyTriggerPhrase, + String mergeComment, boolean onlyAdminsMerge, boolean disallowOwnCode, boolean failOnNonMerge, boolean deleteOnMerge) { this.mergeComment = mergeComment; - this.onlyTriggerPhrase = onlyTriggerPhrase; this.onlyAdminsMerge = onlyAdminsMerge; this.disallowOwnCode = disallowOwnCode; this.failOnNonMerge = failOnNonMerge; this.deleteOnMerge = deleteOnMerge; } - public String getMergeComment() { - return mergeComment; + public GhprbPullRequestMerge( + String mergeComment, + boolean onlyTriggerPhrase, + boolean onlyAdminsMerge, + boolean disallowOwnCode, + boolean failOnNonMerge, + boolean deleteOnMerge) { + + this(mergeComment, onlyAdminsMerge, disallowOwnCode, failOnNonMerge, deleteOnMerge); } - public boolean isOnlyTriggerPhrase() { - return onlyTriggerPhrase == null ? false : onlyTriggerPhrase; + public String getMergeComment() { + return mergeComment; } public boolean isOnlyAdminsMerge() { @@ -137,26 +141,22 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build // ignore comments from bot user, this fixes an issue where the bot would auto-merge // a PR when the 'request for testing' phrase contains the PR merge trigger phrase and - // the bot is a member of a whitelisted organisation + // the bot is a member of a whitelisted organization if (helper.isBotUser(triggerSender)) { logger.println("Comment from bot user " + triggerSender.getLogin() + " ignored."); return false; } - boolean intendToMerge = false, commentTrigger = false; + boolean intendToMerge = false; boolean canMerge = true; String commentBody = cause.getCommentBody(); - if (isOnlyTriggerPhrase()) { - // If merge can only be triggered by a comment and there is a - // comment - if (commentBody == null || !helper.isTriggerPhrase(commentBody)) { - logger.println("The comment does not contain the required trigger phrase."); - } else { - intendToMerge = true; - commentTrigger = true; - } - } else { + // If merge can only be triggered by a comment and there is a + // comment + if (commentBody == null || !helper.isTriggerPhrase(commentBody)) { + logger.println("The comment does not contain the required trigger phrase."); + } + else { intendToMerge = true; } @@ -166,18 +166,19 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build logger.println("Only admins can merge this pull request, " + (triggerSender != null ? triggerSender.getLogin() + " is not an admin" : " and build was triggered via automation") + "."); - if (commentTrigger && triggerSender != null) { - commentOnRequest(String.format("Code not merged because %s is not in the Admin list.", triggerSender.getName())); + if (triggerSender != null) { + commentOnRequest(String.format("Code not merged because @%s (%s) is not in the Admin list.", + triggerSender.getLogin(), triggerSender.getName())); } } // If there is no intention to merge there is no point checking if (intendToMerge && isDisallowOwnCode() && (triggerSender == null || isOwnCode(pr, triggerSender))) { canMerge = false; - if (commentTrigger && triggerSender != null) { + if (triggerSender != null) { logger.println("The commentor is also one of the contributors."); - commentOnRequest(String.format("Code not merged because %s has committed code in the request.", - triggerSender.getName())); + commentOnRequest(String.format("Code not merged because @%s (%s) has committed code in the request.", + triggerSender.getLogin(), triggerSender.getName())); } } @@ -199,7 +200,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build deleteBranch(build, launcher, listener); } - // We should only fail the build if the trigger phrase is NOT used + // We should only fail the build if there is an intent to merge if (intendToMerge && !canMerge && isFailOnNonMerge()) { listener.finished(Result.FAILURE); } else { diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/config.jelly index d34fb4bd5..c720ee69c 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/config.jelly @@ -2,9 +2,6 @@ - - - diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/global.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/global.jelly index acb0a3d2e..2f5c4993a 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/global.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/global.jelly @@ -3,9 +3,6 @@ - - - diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/help-onlyTriggerPhrase.html b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/help-onlyTriggerPhrase.html deleted file mode 100644 index 6a5ba1cec..000000000 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge/help-onlyTriggerPhrase.html +++ /dev/null @@ -1,4 +0,0 @@ -
- When checked, only commenting the trigger phrase in the pull request will trigger a build. - All other methods of triggering a pull request build are disabled. -
\ No newline at end of file diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 8db3519cc..5db98925a 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -44,6 +44,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; @RunWith(MockitoJUnitRunner.class) public class GhprbPullRequestMergeTest { @@ -210,6 +212,7 @@ private GhprbPullRequestMerge setupMerger( merger.setHelper(helper); + Mockito.reset(pr); return merger; } @@ -230,27 +233,35 @@ public void testApproveMerge() throws Exception { setupConditions(nonAdminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(1)).merge(mergeComment); setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(2)).merge(mergeComment); setupConditions(adminLogin, committerName, committerEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(2)).merge(mergeComment); setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(3)).merge(mergeComment); setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(3)).merge(mergeComment); setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(3)).merge(mergeComment); setupConditions(nonAdminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(3)).merge(mergeComment); setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(4)).merge(mergeComment); } @Test @@ -264,9 +275,11 @@ public void testAdminMerge() throws Exception { setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(1)).merge(mergeComment); setupConditions(nonAdminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); + verify(pr, times(1)).merge(mergeComment); } @Test @@ -280,9 +293,11 @@ public void testTriggerMerge() throws Exception { setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(1)).merge(mergeComment); setupConditions(adminLogin, committerName, committerEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(1)).merge(mergeComment); } @Test @@ -296,9 +311,11 @@ public void testOwnCodeMerge() throws Exception { setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(1)).merge(mergeComment); setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); + verify(pr, times(1)).merge(mergeComment); } @Test @@ -312,30 +329,39 @@ public void testDenyMerge() throws Exception { setupConditions(nonAdminLogin, nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); + verify(pr, times(0)).merge(mergeComment); setupConditions(nonAdminLogin, adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); + verify(pr, times(0)).merge(mergeComment); setupConditions(nonAdminLogin, adminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(0)).merge(mergeComment); setupConditions(nonAdminLogin, nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); + verify(pr, times(0)).merge(mergeComment); setupConditions(nonAdminLogin, nonAdminLogin, nonCommitterName, nonCommitterEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(0)).merge(mergeComment); setupConditions(nonAdminLogin, adminLogin, committerName, committerEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(0)).merge(mergeComment); setupConditions(nonAdminLogin, nonAdminLogin, committerName, committerEmail, nonTriggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(0)).merge(mergeComment); setupConditions(adminLogin, adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); + verify(pr, times(0)).merge(mergeComment); setupConditions(nonAdminLogin, adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); + verify(pr, times(1)).merge(mergeComment); } From 9470f35cc66ab4beefa83e885c26b0923da4a88a Mon Sep 17 00:00:00 2001 From: Kevin Suwala Date: Mon, 24 Aug 2015 11:01:46 -0700 Subject: [PATCH 022/175] JENKINS-30115 Allow downstream jobs to attach GitHub status messages to pulled repo - Added support for GitHub contexts and messages to be added from downstream jobs --- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 1 + .../plugins/ghprb/GhprbCustomStatus.java | 74 +++++++++++++ .../ghprb/GhprbCustomStatusListener.java | 103 ++++++++++++++++++ .../ghprb/GhprbCustomStatusRepoPasser.java | 24 ++++ .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 1 + .../ghprb/GhprbCustomStatus/config.jelly | 9 ++ .../ghprb/GhprbCustomStatus/help-context.html | 3 + .../ghprb/GhprbCustomStatus/help-message.html | 3 + .../plugins/ghprb/GhprbCustomStatus/help.html | 8 ++ 9 files changed, 226 insertions(+) create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatus.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusListener.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusRepoPasser.java create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/config.jelly create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-context.html create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-message.html create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help.html diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 86643ee18..5599f683c 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -59,6 +59,7 @@ public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) public void onStarted(AbstractBuild build, TaskListener listener) { + GhprbCustomStatusRepoPasser.addRepo(build.getFullDisplayName(), repo.getGitHubRepo()); PrintStream logger = listener.getLogger(); GhprbCause c = Ghprb.getCause(build); if (c == null) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatus.java new file mode 100644 index 000000000..a9cbc6f69 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatus.java @@ -0,0 +1,74 @@ +package org.jenkinsci.plugins.ghprb; + +import hudson.Extension; +import hudson.Launcher; +import hudson.model.*; +import hudson.tasks.BuildWrapper; +import hudson.util.FormValidation; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.QueryParameter; + +import javax.servlet.ServletException; +import java.io.IOException; +import java.util.Map; +import java.util.logging.Logger; + +/** + * @author Kevin Suwala + */ + +public class GhprbCustomStatus extends BuildWrapper { + private static final Logger logger = Logger.getLogger(Ghprb.class.getName()); + private String context = ""; + private String message = ""; + public String getContext() { + return context; + } + + public String getMessage() { + return message; + } + + @DataBoundConstructor + public GhprbCustomStatus(String context, String message) { + this.message = message; + this.context = context; + } + + @Extension + public static final class DescriptorImpl extends Descriptor { + public DescriptorImpl() { + load(); + } + + @Override + public String getDisplayName() { + return "Set GitHub commit status with custom context and message (Must configure upstream job using GHPRB)"; + } + + public FormValidation doCheckValue(@QueryParameter String value) throws IOException, ServletException { + if(value.isEmpty()) { + return FormValidation.error("You must have a context!"); + } + return FormValidation.ok(); + } + } + + // sets the context and message as env vars so that they are available in the Listener class + @Override + public void makeBuildVariables(AbstractBuild build, Map variables){ + variables.put("context", context); + variables.put("message", message); + } + + @Override + public BuildWrapper.Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + makeBuildVariables(build, build.getBuildVariables()); + return new Environment(){}; + } + + @Override + public void preCheckout(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + makeBuildVariables(build, build.getBuildVariables()); + } +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusListener.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusListener.java new file mode 100644 index 000000000..f9d8c996c --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusListener.java @@ -0,0 +1,103 @@ +package org.jenkinsci.plugins.ghprb; + +import hudson.EnvVars; +import hudson.Extension; +import hudson.Launcher; +import hudson.model.*; +import hudson.model.listeners.RunListener; +import org.kohsuke.github.GHCommitState; +import org.kohsuke.github.GHRepository; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author Kevin Suwala + * This class is responsible for sending the custom status and message on + * downstream jobs that have the option configured. + */ + +@Extension +public class GhprbCustomStatusListener extends RunListener> { + private static final Logger logger = Logger.getLogger(Ghprb.class.getName()); + private String context = ""; + private String message = ""; + private String sha = ""; + private String url = ""; + private String upstreamJob = ""; + private String jobName = ""; + + // Gets all the custom env vars needed to send information to GitHub + private void updateEnvironmentVars(AbstractBuild build, TaskListener listener){ + EnvVars envVars = new EnvVars(); + try { + envVars = build.getEnvironment(listener); + } catch (Exception e) { + logger.log(Level.WARNING, "Unable to get update environment variables!"); + listener.getLogger().println("Unable to get environment variables, is the upstream job configured with the GHPRB plugin?"); + return; + } + + context = envVars.get("context"); + message = envVars.get("message"); + sha = envVars.get("ghprbActualCommit"); + url = envVars.get("BUILD_URL"); + if (url == "") url = envVars.get("JOB_URL"); + jobName = envVars.get("JOB_NAME"); + upstreamJob = envVars.get("ghprbTriggerJob"); + } + + // Sends the commit status and message to GitHub + private void createCommitStatus(String sha, GHCommitState state, String url, String message, String context, AbstractBuild build) { + // return if it's the upstream job, otherwise if context isn't set make it job name + if (context == null) return; + if (context.isEmpty()) context = jobName; + + logger.log(Level.FINE, "Job: " + build.getFullDisplayName() + " Attempting to send GitHub commit status"); + GHRepository r = GhprbCustomStatusRepoPasser.getRepoMap().get(upstreamJob); + + try { + r.createCommitStatus(sha, state, url, message, context); + logger.log(Level.FINE, "Status sent successfully"); + } catch(Exception e) { + logger.log(Level.WARNING, "GitHub status could not be created!"); + } + } + + // Sets the status as pending when the job starts and then calls the createCommitStatus method to send it to GitHub + @Override + public Environment setUpEnvironment(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException { + updateEnvironmentVars(build, listener); + + GHCommitState state = GHCommitState.PENDING; + createCommitStatus(sha, state, url, "Build has started, please wait for results... ", context, build); + + return new hudson.model.Environment(){}; + } + + @Override + public void onStarted(AbstractBuild build, TaskListener listener) { + updateEnvironmentVars(build, listener); + } + + // Sets the status to the build result when the job is done, and then calls the createCommitStatus method to send it to GitHub + @Override + public void onCompleted(AbstractBuild build, TaskListener listener) { + updateEnvironmentVars(build, listener); + + GHCommitState state = GHCommitState.SUCCESS; + + if (build.getResult().isWorseThan(Result.SUCCESS)) { + state = GHCommitState.FAILURE; + } + + String newMessage = ""; + if (message.isEmpty()) { + newMessage = "Build finished."; + } else { + newMessage = "Build finished with message: " + message; + } + createCommitStatus(sha, state, url, newMessage, context, build); + } +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusRepoPasser.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusRepoPasser.java new file mode 100644 index 000000000..0f2fe67a1 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusRepoPasser.java @@ -0,0 +1,24 @@ +package org.jenkinsci.plugins.ghprb; + +import org.kohsuke.github.GHRepository; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Kevin Suwala + * This class is responsible for storing the GHRepository for each job and making + * it accesible for other classes + */ + +public class GhprbCustomStatusRepoPasser { + private static Map repoMap = new HashMap(); + + public static void addRepo(String name, GHRepository repo) { + repoMap.put(name, repo); + } + + public static Map getRepoMap() { + return repoMap; + } +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index ad2a2cf84..7867236af 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -260,6 +260,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbPullLink", String.valueOf(cause.getUrl()))); values.add(new StringParameterValue("ghprbPullLongDescription", String.valueOf(cause.getDescription()))); values.add(new StringParameterValue("ghprbCommentBody", String.valueOf(cause.getCommentBody()))); + values.add(new StringParameterValue("ghprbTriggerJob", this.job.getFullDisplayName() + " #" + this.job.getNextBuildNumber())); // add the previous pr BuildData as an action so that the correct change log is generated by the GitSCM plugin // note that this will be removed from the Actions list after the job is completed so that the old (and incorrect) diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/config.jelly new file mode 100644 index 000000000..4afebb901 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/config.jelly @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-context.html b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-context.html new file mode 100644 index 000000000..89aa0b3a0 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-context.html @@ -0,0 +1,3 @@ +
+ Set a custom context that will appear on the Github PR that the upstream job pulled +
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-message.html b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-message.html new file mode 100644 index 000000000..a8eea72c1 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-message.html @@ -0,0 +1,3 @@ +
+ Set a custom message that will appear on the Github PR that the upstream job pulled +
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help.html b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help.html new file mode 100644 index 000000000..664d45aec --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help.html @@ -0,0 +1,8 @@ +
+ Allows you to set a custom context and message on a pull request pulled using GHPRB. +
This will add the context and message to the pull request found in the upstream job NOT on any pull requests taken on this job +
To add a custom context and message on any pull requests on THIS job see the GHPRB section in the Build Triggers section +
+
IMPORTANT: +
This will only work if you configure a upstream job that uses the Github Pull Request Builder Plugin +
\ No newline at end of file From df597e01e07368f11036afc9761af5fa6a631a2e Mon Sep 17 00:00:00 2001 From: Alex Rodionov Date: Mon, 7 Sep 2015 10:17:17 +0600 Subject: [PATCH 023/175] Rename LICENCE to LICENSE --- LICENCE => LICENSE | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename LICENCE => LICENSE (100%) diff --git a/LICENCE b/LICENSE similarity index 100% rename from LICENCE rename to LICENSE From a3bd987ddf5be70d1df0570158bd4cd496c56ec5 Mon Sep 17 00:00:00 2001 From: Emanuele Zattin Date: Wed, 9 Sep 2015 14:18:00 +0200 Subject: [PATCH 024/175] Use the correct SHA1 for Matrix builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The problem was that job.getBuilds() would return the ongoing matrix root build, causing to build the previous SHA1 in case a commit was not the first of the pull request. The current fix breaks the “smart changes” logic for matrix jobs. A proper fix that preserves this functionality because it would be very hard to determine which is a root build of the same run, especially if the concurrent builds options is enabled. The PR also simplifies some logic. --- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index ad2a2cf84..fae038b62 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -326,17 +326,18 @@ private String getString(String actual, String d) { * Find the previous BuildData for the given pull request number; this may return null */ private BuildData findPreviousBuildForPullId(StringParameterValue pullIdPv) { + // Don't add the Action if it's a matrix job. + // This is suboptimal, but necessary until we find a way to determine if the build we're about to start is + // the root build or one of the leaves. + if (job instanceof MatrixProject) { + return null; + } + // find the previous build for this particular pull request, it may not be the last build for (Run r : job.getBuilds()) { ParametersAction pa = r.getAction(ParametersAction.class); - if (pa != null) { - for (ParameterValue pv : pa.getParameters()) { - if (pv.equals(pullIdPv)) { - for (BuildData bd : r.getActions(BuildData.class)) { - return bd; - } - } - } + if (pa != null && pa.getParameters().contains(pullIdPv)) { + return r.getAction(BuildData.class); } } return null; From 7dad0b2b6a073116142210ed8e83a8ea823b71ef Mon Sep 17 00:00:00 2001 From: Emanuele Zattin Date: Wed, 9 Sep 2015 14:29:58 +0200 Subject: [PATCH 025/175] Add the matrix project dependency --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 632f3a851..62955caf1 100644 --- a/pom.xml +++ b/pom.xml @@ -50,6 +50,11 @@ github 1.9.1 + + org.jenkins-ci.plugins + matrix-project + 1.4.1 + org.jenkins-ci.plugins github-api From 9495ea94b81a2afdf02a9932ed09e8f80c3b2583 Mon Sep 17 00:00:00 2001 From: Emanuele Zattin Date: Wed, 9 Sep 2015 15:54:27 +0200 Subject: [PATCH 026/175] Include the needed classes --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index fae038b62..63d145824 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -7,6 +7,7 @@ import hudson.Extension; import hudson.Util; +import hudson.matrix.MatrixProject; import hudson.model.*; import hudson.model.AbstractProject; import hudson.model.queue.QueueTaskFuture; From fffea6b43755f2f6c17309d2d6da68dca17af8ad Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 9 Sep 2015 16:42:24 -0600 Subject: [PATCH 027/175] Fix global defaults. Job configurations now defer to the global setup. fixed a couple bugs. Updated some of the help messages. --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 49 +++++++ .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 25 ++-- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 2 +- .../extensions/comments/GhprbBuildLog.java | 13 +- .../extensions/comments/GhprbBuildStatus.java | 19 +-- .../extensions/status/GhprbSimpleStatus.java | 136 +++++++----------- .../comments/GhprbBuildLog/config.jelly | 2 +- .../comments/GhprbBuildStatus/config.jelly | 2 +- .../GhprbBuildStatus/help-messages.html | 4 +- .../status/GhprbSimpleStatus/config.jelly | 10 +- .../help-completedStatus.html | 2 +- .../GhprbSimpleStatus/help-statusUrl.html | 1 + .../ghprb/GhprbPullRequestMergeTest.java | 2 +- .../plugins/ghprb/GhprbRepositoryTest.java | 17 ++- .../plugins/ghprb/GhprbRootActionTest.java | 4 +- .../plugins/ghprb/GhprbTestUtil.java | 3 +- .../status/GhprbSimpleStatusTest.java | 21 ++- 17 files changed, 175 insertions(+), 137 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 9c2dc1a50..526400b4a 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -496,4 +496,53 @@ private static String createCredentials(String serverAPIUrl, StandardCredentials provider.addDomain(domain, credentials); return credentials.getId(); } + + public static T getGlobal(Class clazz) { + DescribableList copyExtensions = new DescribableList(Saveable.NOOP); + + copyExtensions.addAll(GhprbTrigger.DESCRIPTOR.getExtensions()); + + filterList(copyExtensions, InstanceofPredicate.getInstance(clazz)); + + return copyExtensions.get(clazz); + } + + + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static T getDefaultValue(Object local, Class globalClass, String methodName) { + T toReturn = null; + Object global = getGlobal(globalClass); + if (local == null && global == null) { + return null; + } + try { + + if (local == null) { + return (T) global.getClass().getMethod(methodName).invoke(global); + } else if (global == null) { + return (T) local.getClass().getMethod(methodName).invoke(local); + } + + T localValue = (T) local.getClass().getMethod(methodName).invoke(local); + T globalValue = (T) global.getClass().getMethod(methodName).invoke(global); + + + if (localValue instanceof String) { + if (StringUtils.isEmpty((String) localValue)) { + return globalValue; + } + } else if (localValue instanceof List) { + if (((List) localValue).isEmpty()) { + return globalValue; + } + } + + return localValue; + + } catch (Exception e) { + e.printStackTrace(); + } + return toReturn; + } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 86643ee18..d1ffe171d 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -57,7 +57,6 @@ public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) } } - public void onStarted(AbstractBuild build, TaskListener listener) { PrintStream logger = listener.getLogger(); GhprbCause c = Ghprb.getCause(build); @@ -88,20 +87,20 @@ public void onStarted(AbstractBuild build, TaskListener listener) { isMerged = false; } } - + if (isMerged) { logger.println("PR has already been merged, builds using the merged sha1 will fail!!!"); } else if (isMergeable == null) { logger.println("PR merge status couldn't be retrieved, maybe GitHub hasn't settled yet"); } else if (isMergeable != c.isMerged()) { logger.println("!!! PR mergeability status has changed !!! "); - if (isMergeable) { + if (isMergeable) { logger.println("PR now has NO merge conflicts"); } else if (!isMergeable) { logger.println("PR now has merge conflicts!"); } } - + } catch (Exception e) { logger.print("Unable to query GitHub for status of PullRequest"); e.printStackTrace(logger); @@ -116,7 +115,7 @@ public void onStarted(AbstractBuild build, TaskListener listener) { } } } - + try { String template = trigger.getBuildDescTemplate(); if (StringUtils.isEmpty(template)) { @@ -133,12 +132,16 @@ public void onStarted(AbstractBuild build, TaskListener listener) { } public Map getVariables(GhprbCause c) { - Map vars = new HashMap(); - vars.put("title", c.getTitle()); - vars.put("url", c.getUrl().toString()); - vars.put("pullId", Integer.toString(c.getPullID())); - vars.put("abbrTitle", c.getAbbreviatedTitle()); - return vars; + Map vars = new HashMap(); + vars.put("title", c.getTitle()); + if (c.getUrl() != null) { + vars.put("url", c.getUrl().toString()); + } else { + vars.put("url", ""); + } + vars.put("pullId", Integer.toString(c.getPullID())); + vars.put("abbrTitle", c.getAbbreviatedTitle()); + return vars; } public void onCompleted(AbstractBuild build, TaskListener listener) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index ad2a2cf84..47c3d2189 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -91,7 +91,7 @@ private void setExtensions(List extensions) { ); // Now make sure we have at least one of the types we need one of. - Ghprb.addIfMissing(this.extensions, new GhprbSimpleStatus(), GhprbCommitStatus.class); + Ghprb.addIfMissing(this.extensions, Ghprb.getGlobal(GhprbSimpleStatus.class), GhprbCommitStatus.class); } @DataBoundConstructor diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog.java index 6aa2966bf..6d2c8006e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog.java @@ -12,10 +12,11 @@ import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtensionDescriptor; import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalExtension; +import org.jenkinsci.plugins.ghprb.extensions.GhprbProjectExtension; import org.kohsuke.github.GHCommitState; import org.kohsuke.stapler.DataBoundConstructor; -public class GhprbBuildLog extends GhprbExtension implements GhprbCommentAppender, GhprbGlobalExtension { +public class GhprbBuildLog extends GhprbExtension implements GhprbCommentAppender, GhprbProjectExtension, GhprbGlobalExtension { @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); @@ -36,7 +37,7 @@ public String postBuildComment(AbstractBuild build, TaskListener listener) StringBuilder msg = new StringBuilder(); GHCommitState state = Ghprb.getState(build); - int numLines = getLogExcerptLines(); + int numLines = getDescriptor().getLogExcerptLinesDefault(this); if (state != GHCommitState.SUCCESS && numLines > 0) { // on failure, append an excerpt of the build log @@ -74,6 +75,14 @@ public static final class DescriptorImpl extends GhprbExtensionDescriptor implem public String getDisplayName() { return "Append portion of build log"; } + + public Integer getLogExcerptLinesDefault(GhprbBuildLog local) { + Integer lines = Ghprb.getDefaultValue(local, GhprbBuildLog.class, "getLogExcerptLines"); + if (lines == null) { + lines = 0; + } + return lines; + } } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus.java index 7a7aca3eb..3a3cf5b04 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus.java @@ -7,6 +7,7 @@ import hudson.model.TaskListener; import hudson.model.AbstractBuild; +import org.jenkinsci.plugins.ghprb.Ghprb; import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommentAppender; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; @@ -35,6 +36,8 @@ public List getMessages() { public String postBuildComment(AbstractBuild build, TaskListener listener) { StringBuilder msg = new StringBuilder(); + List messages = getDescriptor().getMessagesDefault(this); + for (GhprbBuildResultMessage messager: messages) { msg.append(messager.postBuildComment(build, listener)); } @@ -53,21 +56,9 @@ public static class DescriptorImpl extends GhprbExtensionDescriptor implements G public String getDisplayName() { return "Build Status Messages"; } - - public List getMessageList(List messages) { - List newMessages = new ArrayList(10); - if (messages != null){ - newMessages.addAll(messages); - } else { - for(GhprbExtension extension : GhprbTrigger.getDscp().getExtensions()) { - if (extension instanceof GhprbBuildStatus) { - newMessages.addAll(((GhprbBuildStatus)extension).getMessages()); - } - } - } - return newMessages; + public List getMessagesDefault(GhprbBuildStatus local) { + return Ghprb.getDefaultValue(local, GhprbBuildStatus.class, "getMessages"); } - } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index b8d20688b..64d42b883 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -13,7 +13,6 @@ import jenkins.model.Jenkins; import org.apache.commons.lang.StringUtils; - import org.jenkinsci.plugins.ghprb.Ghprb; import org.jenkinsci.plugins.ghprb.GhprbCause; import org.jenkinsci.plugins.ghprb.GhprbPullRequest; @@ -36,40 +35,34 @@ public class GhprbSimpleStatus extends GhprbExtension implements GhprbCommitStat @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); - + private final String commitStatusContext; private final String triggeredStatus; private final String startedStatus; private final String statusUrl; private final List completedStatus; - + public GhprbSimpleStatus() { this(null, null, null, null, new ArrayList(0)); } - + public GhprbSimpleStatus(String commitStatusContext) { this(commitStatusContext, null, null, null, new ArrayList(0)); } - + @DataBoundConstructor - public GhprbSimpleStatus( - String commitStatusContext, - String statusUrl, - String triggeredStatus, - String startedStatus, - List completedStatus - ) { + public GhprbSimpleStatus(String commitStatusContext, String statusUrl, String triggeredStatus, String startedStatus, List completedStatus) { this.statusUrl = statusUrl; this.commitStatusContext = commitStatusContext == null ? "" : commitStatusContext; this.triggeredStatus = triggeredStatus; this.startedStatus = startedStatus; this.completedStatus = completedStatus; } - + public String getStatusUrl() { return statusUrl == null ? "" : statusUrl; } - + public String getCommitStatusContext() { return commitStatusContext == null ? "" : commitStatusContext; } @@ -77,7 +70,7 @@ public String getCommitStatusContext() { public String getStartedStatus() { return startedStatus == null ? "" : startedStatus; } - + public String getTriggeredStatus() { return triggeredStatus == null ? "" : triggeredStatus; } @@ -85,16 +78,20 @@ public String getTriggeredStatus() { public List getCompletedStatus() { return completedStatus == null ? new ArrayList(0) : completedStatus; } - + public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHRepository ghRepository) throws GhprbCommitStatusException { + String triggeredStatus = getDescriptor().getTriggeredStatusDefault(this); + String statusUrl = getDescriptor().getStatusUrlDefault(this); + String commitStatusContext = getDescriptor().getCommitStatusContextDefault(this); + StringBuilder sb = new StringBuilder(); GHCommitState state = GHCommitState.PENDING; - + AbstractProject project = trigger.getActualProject(); - + String context = Util.fixEmpty(commitStatusContext); context = Ghprb.replaceMacros(project, context); - + if (!StringUtils.isEmpty(triggeredStatus)) { sb.append(Ghprb.replaceMacros(project, triggeredStatus)); } else { @@ -105,7 +102,7 @@ public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHReposi sb.append(" sha1 is original commit."); } } - + String url = Ghprb.replaceMacros(project, statusUrl); String message = sb.toString(); @@ -117,6 +114,8 @@ public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHReposi } public void onBuildStart(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { + String startedStatus = getDescriptor().getStartedStatusDefault(this); + GhprbCause c = Ghprb.getCause(build); StringBuilder sb = new StringBuilder(); if (StringUtils.isEmpty(startedStatus)) { @@ -129,6 +128,7 @@ public void onBuildStart(AbstractBuild build, TaskListener listener, GHRep } public void onBuildComplete(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { + List completedStatus = getDescriptor().getCompletedStatusDefault(this); GHCommitState state = Ghprb.getState(build); @@ -141,36 +141,38 @@ public void onBuildComplete(AbstractBuild build, TaskListener listener, GH sb.append(buildStatus.postBuildComment(build, listener)); } } - + sb.append(" "); GhprbTrigger trigger = Ghprb.extractTrigger(build); if (trigger == null) { listener.getLogger().println("Unable to get pull request builder trigger!!"); } else { - JobConfiguration jobConfiguration = - JobConfiguration.builder() - .printStackTrace(trigger.isDisplayBuildErrorsOnDownstreamBuilds()) - .build(); + JobConfiguration jobConfiguration = JobConfiguration.builder().printStackTrace(trigger.isDisplayBuildErrorsOnDownstreamBuilds()).build(); - GhprbBuildManager buildManager = - GhprbBuildManagerFactoryUtil.getBuildManager(build, jobConfiguration); + GhprbBuildManager buildManager = GhprbBuildManagerFactoryUtil.getBuildManager(build, jobConfiguration); sb.append(buildManager.getOneLineTestResults()); } - + createCommitStatus(build, listener, sb.toString(), repo, state); } private void createCommitStatus(AbstractBuild build, TaskListener listener, String message, GHRepository repo, GHCommitState state) throws GhprbCommitStatusException { - GhprbCause cause = Ghprb.getCause(build); + String statusUrl = getDescriptor().getStatusUrlDefault(this); + String commitStatusContext = getDescriptor().getCommitStatusContextDefault(this); + GhprbCause cause = Ghprb.getCause(build); + String sha1 = cause.getCommit(); String url = Jenkins.getInstance().getRootUrl() + build.getUrl(); - if (!StringUtils.isEmpty(statusUrl)) { - url = Ghprb.replaceMacros(build, listener, statusUrl); + if (statusUrl == "--none--") { + url = ""; + } else if (!StringUtils.isEmpty(statusUrl)) { + url = Ghprb.replaceMacros(build, listener, statusUrl); } + String context = Util.fixEmpty(commitStatusContext); context = Ghprb.replaceMacros(build, listener, context); - + listener.getLogger().println(String.format("Setting status of %s to %s with url %s and message: '%s'", sha1, state, url, message)); if (context != null) { listener.getLogger().println(String.format("Using context: " + context)); @@ -186,66 +188,32 @@ private void createCommitStatus(AbstractBuild build, TaskListener listener public DescriptorImpl getDescriptor() { return DESCRIPTOR; } - + public static final class DescriptorImpl extends GhprbExtensionDescriptor implements GhprbGlobalExtension, GhprbProjectExtension { - + @Override public String getDisplayName() { return "Update commit status during build"; } - - public String getTriggeredStatusDefault(String triggeredStatusLocal) { - String triggeredStatus = triggeredStatusLocal; - if (triggeredStatus == null) { - for(GhprbExtension extension : GhprbTrigger.getDscp().getExtensions()) { - if (extension instanceof GhprbSimpleStatus) { - triggeredStatus = ((GhprbSimpleStatus) extension).getTriggeredStatus(); - break; - } - } - } - return triggeredStatus; - } - - public String getStartedStatusDefault(String startedStatusLocal) { - String startedStatus = startedStatusLocal; - if (startedStatus == null) { - for(GhprbExtension extension : GhprbTrigger.getDscp().getExtensions()) { - if (extension instanceof GhprbSimpleStatus) { - startedStatus = ((GhprbSimpleStatus) extension).getStartedStatus(); - break; - } - } - } - return startedStatus; + + public String getTriggeredStatusDefault(GhprbSimpleStatus local) { + return Ghprb.getDefaultValue(local, GhprbSimpleStatus.class, "getTriggeredStatus"); } - - public List getCompletedStatusList(List completedStatusLocal) { - List completedStatus = completedStatusLocal; - if (completedStatus == null) { - for(GhprbExtension extension : GhprbTrigger.getDscp().getExtensions()) { - if (extension instanceof GhprbSimpleStatus) { - completedStatus = ((GhprbSimpleStatus) extension).getCompletedStatus(); - break; - } - } - } - return completedStatus; + + public String getStatusUrlDefault(GhprbSimpleStatus local) { + return Ghprb.getDefaultValue(local, GhprbSimpleStatus.class, "getStatusUrl"); } - - public String getCommitContextDefault(String commitStatusContextLocal){ - String commitStatusContext = commitStatusContextLocal; - if (commitStatusContext == null) { - for(GhprbExtension extension : GhprbTrigger.getDscp().getExtensions()) { - if (extension instanceof GhprbSimpleStatus) { - commitStatusContext = ((GhprbSimpleStatus) extension).getCommitStatusContext(); - break; - } - } - } - return commitStatusContext; + + public String getStartedStatusDefault(GhprbSimpleStatus local) { + return Ghprb.getDefaultValue(local, GhprbSimpleStatus.class, "getStartedStatus"); } - } + public List getCompletedStatusDefault(GhprbSimpleStatus local) { + return Ghprb.getDefaultValue(local, GhprbSimpleStatus.class, "getCompletedStatus"); + } + public String getCommitStatusContextDefault(GhprbSimpleStatus local) { + return Ghprb.getDefaultValue(local, GhprbSimpleStatus.class, "getCommitStatusContext"); + } + } } diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog/config.jelly index 3b79b49b7..22345540d 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog/config.jelly @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus/config.jelly index dcb6b0fe5..0ab4c2b80 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus/config.jelly @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus/help-messages.html b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus/help-messages.html index f99a6a9ce..3c224a0f9 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus/help-messages.html +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus/help-messages.html @@ -1,5 +1,5 @@
- Global: Sets a default for each job, but won't be used by default.
+ Global: Sets a default for each job, if the job setup has no entries then this is used.

- Add a text message to the comment appended to the pull request on build completion. + Add a text message to the comment posted to the pull request on build completion.
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/config.jelly index 93b5fe8b8..d883f91dd 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/config.jelly @@ -1,17 +1,17 @@ - + - + - + - + - + \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-completedStatus.html b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-completedStatus.html index 8095eedc4..0301c9968 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-completedStatus.html +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-completedStatus.html @@ -1,4 +1,4 @@
- Use a custom status for when a build is completed. + Use a custom status on the commit for when a build is completed. If the field is left blank then the default value is used instead.
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-statusUrl.html b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-statusUrl.html index af04b3035..82c957c7c 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-statusUrl.html +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-statusUrl.html @@ -1,3 +1,4 @@
Use a custom url instead of the Jenkins job url. + If the desired url should be blank, use "--none--" to alert the trigger to use a blank url.
\ No newline at end of file diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 316dfd44f..d5357ff8b 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -104,7 +104,7 @@ public void beforeTest() throws Exception { triggerValues.put("adminlist", adminList); triggerValues.put("triggerPhrase", triggerPhrase); - GhprbTrigger trigger = spy(GhprbTestUtil.getTrigger(triggerValues)); + GhprbTrigger trigger = GhprbTestUtil.getTrigger(triggerValues); ConcurrentMap pulls = new ConcurrentHashMap(1); pulls.put(pullId, pullRequest); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index a37e48e25..7048cbd4e 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -48,7 +48,6 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.only; import static org.mockito.Mockito.reset; @@ -102,7 +101,7 @@ public class GhprbRepositoryTest { @SuppressWarnings("unused") public void setUp() throws Exception { AbstractProject project = jenkinsRule.createFreeStyleProject("GhprbRepoTest"); - trigger = spy(GhprbTestUtil.getTrigger(null)); + trigger = GhprbTestUtil.getTrigger(null); doReturn(mock(QueueTaskFuture.class)).when(trigger).startJob(any(GhprbCause.class), any(GhprbRepository.class)); initGHPRWithTestData(); @@ -118,9 +117,13 @@ public void setUp() throws Exception { } - private void addSimpleStatus() throws IOException { + private void addSimpleStatus() { GhprbSimpleStatus status = new GhprbSimpleStatus("default"); - trigger.getExtensions().remove(GhprbSimpleStatus.class); + try { + trigger.getExtensions().remove(GhprbSimpleStatus.class); + } catch (Exception e) { + e.printStackTrace(); + } trigger.getExtensions().add(status); } @@ -229,7 +232,7 @@ public void testCheckMethodWithNewPR() throws IOException { /** GH PR verifications */ verify(builds, times(1)).build(any(GhprbPullRequest.class), any(GHUser.class), any(String.class)); verify(ghRepository, times(1)).getPullRequests(OPEN); // Call to Github API - verify(ghRepository, times(1)).createCommitStatus(eq("head sha"), eq(PENDING), isNull(String.class), eq(msg), eq("default")); // Call to Github API + verify(ghRepository, times(1)).createCommitStatus(eq("head sha"), eq(PENDING), eq(""), eq(msg), eq("default")); // Call to Github API verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(1)).getTitle(); @@ -306,7 +309,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException /** GH PR verifications */ verify(builds, times(1)).build(any(GhprbPullRequest.class), any(GHUser.class), any(String.class)); verify(ghRepository, times(2)).getPullRequests(eq(OPEN)); // Call to Github API - verify(ghRepository, times(1)).createCommitStatus(eq("head sha"), eq(PENDING), isNull(String.class), eq(msg), eq("default")); // Call to Github API + verify(ghRepository, times(1)).createCommitStatus(eq("head sha"), eq(PENDING), eq(""), eq(msg), eq("default")); // Call to Github API verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(2)).getTitle(); @@ -391,7 +394,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verifyNoMoreInteractions(builds); verify(ghRepository, times(2)).getPullRequests(eq(OPEN)); // Call to Github API - verify(ghRepository, times(2)).createCommitStatus(eq("head sha"), eq(PENDING), isNull(String.class), eq(msg), eq("default")); // Call to Github API + verify(ghRepository, times(2)).createCommitStatus(eq("head sha"), eq(PENDING), eq(""), eq(msg), eq("default")); // Call to Github API verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(2)).getTitle(); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java index 033fc2fc3..0b7d64484 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java @@ -93,7 +93,7 @@ public void setup() throws Exception { public void testUrlEncoded() throws Exception { // GIVEN FreeStyleProject project = jenkinsRule.createFreeStyleProject("testUrlEncoded"); - GhprbTrigger trigger = spy(GhprbTestUtil.getTrigger(null)); + GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); given(commitPointer.getSha()).willReturn("sha1"); GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); @@ -133,7 +133,7 @@ public void testUrlEncoded() throws Exception { public void disabledJobsDontBuild() throws Exception { // GIVEN FreeStyleProject project = jenkinsRule.createFreeStyleProject("disabledJobsDontBuild"); - GhprbTrigger trigger = spy(GhprbTestUtil.getTrigger(null)); + GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); given(commitPointer.getSha()).willReturn("sha1"); GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java index 381ea1b02..c670fbeec 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java @@ -37,6 +37,7 @@ import hudson.plugins.git.UserRemoteConfig; import net.sf.json.JSONObject; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.spy; public class GhprbTestUtil { @@ -369,7 +370,7 @@ public static GhprbTrigger getTrigger(Map values) throws Excepti defaults.put(next.getKey(), next.getValue()); } - GhprbTrigger trigger = req.bindJSON(GhprbTrigger.class, defaults); + GhprbTrigger trigger = spy(req.bindJSON(GhprbTrigger.class, defaults)); return trigger; } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatusTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatusTest.java index 9396c4d2b..0741c28fd 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatusTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatusTest.java @@ -1,9 +1,13 @@ package org.jenkinsci.plugins.ghprb.extensions.status; import org.jenkinsci.plugins.ghprb.GhprbPullRequest; +import org.jenkinsci.plugins.ghprb.GhprbTestUtil; import org.jenkinsci.plugins.ghprb.GhprbTrigger; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.jvnet.hudson.test.JenkinsRule; import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GHRepository; import org.mockito.Mock; @@ -19,13 +23,22 @@ @RunWith(MockitoJUnitRunner.class) public class GhprbSimpleStatusTest { + @Rule + public JenkinsRule jenkinsRule = new JenkinsRule(); + @Mock private GHRepository ghRepository; @Mock private GhprbPullRequest ghprbPullRequest; - @Mock + private GhprbTrigger trigger; + + @Before + public void setUp() throws Exception { + trigger = GhprbTestUtil.getTrigger(null); + } + @Test public void testMergedMessage() throws Exception { String mergedMessage = "Build triggered. sha1 is merged."; @@ -35,7 +48,7 @@ public void testMergedMessage() throws Exception { GhprbSimpleStatus status = spy(new GhprbSimpleStatus("default")); status.onBuildTriggered(trigger, ghprbPullRequest, ghRepository); - verify(ghRepository).createCommitStatus(eq("sha"), eq(GHCommitState.PENDING), isNull(String.class), eq(mergedMessage), eq("default")); + verify(ghRepository).createCommitStatus(eq("sha"), eq(GHCommitState.PENDING), eq(""), eq(mergedMessage), eq("default")); verifyNoMoreInteractions(ghRepository); verify(ghprbPullRequest).getHead(); @@ -52,7 +65,7 @@ public void testMergeConflictMessage() throws Exception { GhprbSimpleStatus status = spy(new GhprbSimpleStatus("default")); status.onBuildTriggered(trigger, ghprbPullRequest, ghRepository); - verify(ghRepository).createCommitStatus(eq("sha"), eq(GHCommitState.PENDING), isNull(String.class), eq(mergedMessage), eq("default")); + verify(ghRepository).createCommitStatus(eq("sha"), eq(GHCommitState.PENDING), eq(""), eq(mergedMessage), eq("default")); verifyNoMoreInteractions(ghRepository); verify(ghprbPullRequest).getHead(); @@ -69,7 +82,7 @@ public void testDoesNotSendEmptyContext() throws Exception { GhprbSimpleStatus status = spy(new GhprbSimpleStatus("")); status.onBuildTriggered(trigger, ghprbPullRequest, ghRepository); - verify(ghRepository).createCommitStatus(eq("sha"), eq(GHCommitState.PENDING), isNull(String.class), eq(mergedMessage), isNull(String.class)); + verify(ghRepository).createCommitStatus(eq("sha"), eq(GHCommitState.PENDING), eq(""), eq(mergedMessage), isNull(String.class)); verifyNoMoreInteractions(ghRepository); verify(ghprbPullRequest).getHead(); From e091c6da37c1ccd3b1fee4628f8ee2b2173fc681 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 9 Sep 2015 16:45:52 -0600 Subject: [PATCH 028/175] Fix some formatting --- .../plugins/ghprb/extensions/status/GhprbSimpleStatus.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index 64d42b883..0c03ff04c 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -51,7 +51,12 @@ public GhprbSimpleStatus(String commitStatusContext) { } @DataBoundConstructor - public GhprbSimpleStatus(String commitStatusContext, String statusUrl, String triggeredStatus, String startedStatus, List completedStatus) { + public GhprbSimpleStatus( + String commitStatusContext, + String statusUrl, + String triggeredStatus, + String startedStatus, + List completedStatus) { this.statusUrl = statusUrl; this.commitStatusContext = commitStatusContext == null ? "" : commitStatusContext; this.triggeredStatus = triggeredStatus; From 8fa3e3da55f92271ff1de47263d0b07177d080f7 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 9 Sep 2015 21:24:53 -0600 Subject: [PATCH 029/175] Update to mimick current update format. Merge in defaults branch. Change variable names to be prefixed with ghprb. --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 20 ++- .../plugins/ghprb/GhprbBuildListener.java | 29 +++-- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 19 ++- .../plugins/ghprb/GhprbCustomStatus.java | 74 ----------- .../ghprb/GhprbCustomStatusListener.java | 103 --------------- .../ghprb/GhprbCustomStatusRepoPasser.java | 24 ---- .../ghprb/extensions/GhprbCommitStatus.java | 6 +- .../status/GhprbNoCommitStatus.java | 14 +- .../extensions/status/GhprbSimpleStatus.java | 45 ++++--- .../ghprb/upstream/GhprbUpstreamStatus.java | 120 ++++++++++++++++++ .../upstream/GhprbUpstreamStatusListener.java | 115 +++++++++++++++++ .../GhprbUpstreamStatusRepoPasser.java | 28 ++++ .../ghprb/GhprbCustomStatus/config.jelly | 9 -- .../ghprb/GhprbCustomStatus/help-context.html | 3 - .../ghprb/GhprbCustomStatus/help-message.html | 3 - .../upstream/GhprbUpstreamStatus/config.jelly | 17 +++ .../help-commitStatusContext.html | 4 + .../help-completedStatus.html | 4 + .../help-startedStatus.html | 4 + .../GhprbUpstreamStatus/help-statusUrl.html | 4 + .../help-triggeredStatus.html | 4 + .../GhprbUpstreamStatus}/help.html | 0 .../status/GhprbSimpleStatusTest.java | 12 +- 23 files changed, 393 insertions(+), 268 deletions(-) delete mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatus.java delete mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusListener.java delete mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusRepoPasser.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusListener.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusRepoPasser.java delete mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/config.jelly delete mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-context.html delete mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-message.html create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/config.jelly create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-commitStatusContext.html create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-completedStatus.html create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-startedStatus.html create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-statusUrl.html create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-triggeredStatus.html rename src/main/resources/org/jenkinsci/plugins/ghprb/{GhprbCustomStatus => upstream/GhprbUpstreamStatus}/help.html (100%) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 526400b4a..64a134484 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -256,11 +256,7 @@ public static String replaceMacros(AbstractBuild build, TaskListener liste String returnString = inputString; if (build != null && inputString != null) { try { - Map messageEnvVars = new HashMap(); - - messageEnvVars.putAll(build.getCharacteristicEnvVars()); - messageEnvVars.putAll(build.getBuildVariables()); - messageEnvVars.putAll(build.getEnvironment(listener)); + Map messageEnvVars = getEnvVars(build, listener); returnString = Util.replaceMacro(inputString, messageEnvVars); @@ -271,6 +267,20 @@ public static String replaceMacros(AbstractBuild build, TaskListener liste return returnString; } + public static Map getEnvVars(AbstractBuild build, TaskListener listener) { + Map messageEnvVars = new HashMap(); + if (build != null) { + messageEnvVars.putAll(build.getCharacteristicEnvVars()); + messageEnvVars.putAll(build.getBuildVariables()); + try { + messageEnvVars.putAll(build.getEnvironment(listener)); + } catch (Exception e) { + logger.log(Level.SEVERE, "Couldn't get Env Variables: ", e); + } + } + return messageEnvVars; + } + public static String replaceMacros(AbstractProject project, String inputString) { String returnString = inputString; diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuildListener.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuildListener.java index 106d2028c..db20c2b81 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuildListener.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuildListener.java @@ -1,8 +1,13 @@ package org.jenkinsci.plugins.ghprb; -import com.google.common.base.Optional; +import java.io.IOException; + import hudson.Extension; +import hudson.Launcher; import hudson.model.AbstractBuild; +import hudson.model.BuildListener; +import hudson.model.Environment; +import hudson.model.Run; import hudson.model.TaskListener; import hudson.model.listeners.RunListener; @@ -14,21 +19,27 @@ public class GhprbBuildListener extends RunListener> { @Override public void onStarted(AbstractBuild build, TaskListener listener) { - final Optional trigger = findTrigger(build); - if (trigger.isPresent()) { - trigger.get().getBuilds().onStarted(build, listener); + GhprbTrigger trigger = Ghprb.extractTrigger(build); + if (trigger != null) { + trigger.getBuilds().onStarted(build, listener); } } @Override public void onCompleted(AbstractBuild build, TaskListener listener) { - final Optional trigger = findTrigger(build); - if (trigger.isPresent()) { - trigger.get().getBuilds().onCompleted(build, listener); + GhprbTrigger trigger = Ghprb.extractTrigger(build); + if (trigger != null) { + trigger.getBuilds().onCompleted(build, listener); } } - private static Optional findTrigger(AbstractBuild build) { - return Optional.fromNullable(Ghprb.extractTrigger(build)); + @Override + public Environment setUpEnvironment(@SuppressWarnings("rawtypes") AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException { + GhprbTrigger trigger = Ghprb.extractTrigger(build); + if (trigger != null) { + trigger.getBuilds().onEnvironmentSetup(build, launcher, listener); + } + + return new hudson.model.Environment(){}; } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 5bc3045e9..42c3340f4 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -1,7 +1,9 @@ package org.jenkinsci.plugins.ghprb; +import hudson.Launcher; import hudson.Util; import hudson.model.AbstractBuild; +import hudson.model.BuildListener; import hudson.model.TaskListener; import hudson.model.queue.QueueTaskFuture; import hudson.plugins.git.util.BuildData; @@ -11,6 +13,7 @@ import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatus; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; +import org.jenkinsci.plugins.ghprb.upstream.GhprbCustomStatusRepoPasser; import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GHIssueState; import org.kohsuke.github.GHPullRequest; @@ -45,7 +48,7 @@ public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) for (GhprbExtension ext : Ghprb.getJobExtensions(trigger, GhprbCommitStatus.class)) { if (ext instanceof GhprbCommitStatus) { try { - ((GhprbCommitStatus) ext).onBuildTriggered(trigger, pr, repo.getGitHubRepo()); + ((GhprbCommitStatus) ext).onBuildTriggered(trigger.getActualProject(), pr.getHead(), pr.isMergeable(), pr.getId(), repo.getGitHubRepo()); } catch (GhprbCommitStatusException e) { repo.commentOnFailure(null, null, e); } @@ -213,4 +216,18 @@ private void commentOnBuildResult(AbstractBuild build, TaskListener listen } } + public void onEnvironmentSetup(@SuppressWarnings("rawtypes") AbstractBuild build, Launcher launcher, BuildListener listener) { + logger.log(Level.FINE, "Job: " + build.getFullDisplayName() + " Attempting to send GitHub commit status"); + + for (GhprbExtension ext : Ghprb.getJobExtensions(trigger, GhprbCommitStatus.class)) { + if (ext instanceof GhprbCommitStatus) { + try { + ((GhprbCommitStatus) ext).onEnvironmentSetup(build, listener, repo.getGitHubRepo()); + } catch (GhprbCommitStatusException e) { + repo.commentOnFailure(build, listener, e); + } + } + } + } + } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatus.java deleted file mode 100644 index a9cbc6f69..000000000 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatus.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.jenkinsci.plugins.ghprb; - -import hudson.Extension; -import hudson.Launcher; -import hudson.model.*; -import hudson.tasks.BuildWrapper; -import hudson.util.FormValidation; -import org.kohsuke.stapler.DataBoundConstructor; -import org.kohsuke.stapler.QueryParameter; - -import javax.servlet.ServletException; -import java.io.IOException; -import java.util.Map; -import java.util.logging.Logger; - -/** - * @author Kevin Suwala - */ - -public class GhprbCustomStatus extends BuildWrapper { - private static final Logger logger = Logger.getLogger(Ghprb.class.getName()); - private String context = ""; - private String message = ""; - public String getContext() { - return context; - } - - public String getMessage() { - return message; - } - - @DataBoundConstructor - public GhprbCustomStatus(String context, String message) { - this.message = message; - this.context = context; - } - - @Extension - public static final class DescriptorImpl extends Descriptor { - public DescriptorImpl() { - load(); - } - - @Override - public String getDisplayName() { - return "Set GitHub commit status with custom context and message (Must configure upstream job using GHPRB)"; - } - - public FormValidation doCheckValue(@QueryParameter String value) throws IOException, ServletException { - if(value.isEmpty()) { - return FormValidation.error("You must have a context!"); - } - return FormValidation.ok(); - } - } - - // sets the context and message as env vars so that they are available in the Listener class - @Override - public void makeBuildVariables(AbstractBuild build, Map variables){ - variables.put("context", context); - variables.put("message", message); - } - - @Override - public BuildWrapper.Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { - makeBuildVariables(build, build.getBuildVariables()); - return new Environment(){}; - } - - @Override - public void preCheckout(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { - makeBuildVariables(build, build.getBuildVariables()); - } -} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusListener.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusListener.java deleted file mode 100644 index f9d8c996c..000000000 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusListener.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.jenkinsci.plugins.ghprb; - -import hudson.EnvVars; -import hudson.Extension; -import hudson.Launcher; -import hudson.model.*; -import hudson.model.listeners.RunListener; -import org.kohsuke.github.GHCommitState; -import org.kohsuke.github.GHRepository; - -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * @author Kevin Suwala - * This class is responsible for sending the custom status and message on - * downstream jobs that have the option configured. - */ - -@Extension -public class GhprbCustomStatusListener extends RunListener> { - private static final Logger logger = Logger.getLogger(Ghprb.class.getName()); - private String context = ""; - private String message = ""; - private String sha = ""; - private String url = ""; - private String upstreamJob = ""; - private String jobName = ""; - - // Gets all the custom env vars needed to send information to GitHub - private void updateEnvironmentVars(AbstractBuild build, TaskListener listener){ - EnvVars envVars = new EnvVars(); - try { - envVars = build.getEnvironment(listener); - } catch (Exception e) { - logger.log(Level.WARNING, "Unable to get update environment variables!"); - listener.getLogger().println("Unable to get environment variables, is the upstream job configured with the GHPRB plugin?"); - return; - } - - context = envVars.get("context"); - message = envVars.get("message"); - sha = envVars.get("ghprbActualCommit"); - url = envVars.get("BUILD_URL"); - if (url == "") url = envVars.get("JOB_URL"); - jobName = envVars.get("JOB_NAME"); - upstreamJob = envVars.get("ghprbTriggerJob"); - } - - // Sends the commit status and message to GitHub - private void createCommitStatus(String sha, GHCommitState state, String url, String message, String context, AbstractBuild build) { - // return if it's the upstream job, otherwise if context isn't set make it job name - if (context == null) return; - if (context.isEmpty()) context = jobName; - - logger.log(Level.FINE, "Job: " + build.getFullDisplayName() + " Attempting to send GitHub commit status"); - GHRepository r = GhprbCustomStatusRepoPasser.getRepoMap().get(upstreamJob); - - try { - r.createCommitStatus(sha, state, url, message, context); - logger.log(Level.FINE, "Status sent successfully"); - } catch(Exception e) { - logger.log(Level.WARNING, "GitHub status could not be created!"); - } - } - - // Sets the status as pending when the job starts and then calls the createCommitStatus method to send it to GitHub - @Override - public Environment setUpEnvironment(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException { - updateEnvironmentVars(build, listener); - - GHCommitState state = GHCommitState.PENDING; - createCommitStatus(sha, state, url, "Build has started, please wait for results... ", context, build); - - return new hudson.model.Environment(){}; - } - - @Override - public void onStarted(AbstractBuild build, TaskListener listener) { - updateEnvironmentVars(build, listener); - } - - // Sets the status to the build result when the job is done, and then calls the createCommitStatus method to send it to GitHub - @Override - public void onCompleted(AbstractBuild build, TaskListener listener) { - updateEnvironmentVars(build, listener); - - GHCommitState state = GHCommitState.SUCCESS; - - if (build.getResult().isWorseThan(Result.SUCCESS)) { - state = GHCommitState.FAILURE; - } - - String newMessage = ""; - if (message.isEmpty()) { - newMessage = "Build finished."; - } else { - newMessage = "Build finished with message: " + message; - } - createCommitStatus(sha, state, url, newMessage, context, build); - } -} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusRepoPasser.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusRepoPasser.java deleted file mode 100644 index 0f2fe67a1..000000000 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCustomStatusRepoPasser.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.jenkinsci.plugins.ghprb; - -import org.kohsuke.github.GHRepository; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author Kevin Suwala - * This class is responsible for storing the GHRepository for each job and making - * it accesible for other classes - */ - -public class GhprbCustomStatusRepoPasser { - private static Map repoMap = new HashMap(); - - public static void addRepo(String name, GHRepository repo) { - repoMap.put(name, repo); - } - - public static Map getRepoMap() { - return repoMap; - } -} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbCommitStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbCommitStatus.java index f1a20cfef..e13cbca89 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbCommitStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbCommitStatus.java @@ -1,15 +1,15 @@ package org.jenkinsci.plugins.ghprb.extensions; import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; import hudson.model.TaskListener; -import org.jenkinsci.plugins.ghprb.GhprbPullRequest; -import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.kohsuke.github.GHRepository; public interface GhprbCommitStatus { - public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHRepository ghRepository) throws GhprbCommitStatusException; + public void onEnvironmentSetup(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException; + public void onBuildTriggered(AbstractProject project, String commitSha, boolean isMergeable, int prId, GHRepository ghRepository) throws GhprbCommitStatusException; public void onBuildStart(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException; public void onBuildComplete(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException; diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbNoCommitStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbNoCommitStatus.java index 94ff88dd5..bbc998fdb 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbNoCommitStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbNoCommitStatus.java @@ -3,9 +3,8 @@ import hudson.Extension; import hudson.model.TaskListener; import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; -import org.jenkinsci.plugins.ghprb.GhprbPullRequest; -import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatus; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; @@ -25,15 +24,19 @@ public GhprbNoCommitStatus() { } - public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHRepository ghRepository) throws GhprbCommitStatusException { + public void onBuildStart(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { } - public void onBuildStart(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { + public void onBuildComplete(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { } - public void onBuildComplete(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { + public void onEnvironmentSetup(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { + + } + + public void onBuildTriggered(AbstractProject project, String commitSha, boolean isMergeable, int prId, GHRepository ghRepository) throws GhprbCommitStatusException { } @@ -51,4 +54,5 @@ public String getDisplayName() { } + } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index 0c03ff04c..e71144dae 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -9,13 +9,11 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; - -import jenkins.model.Jenkins; +import java.util.Map; import org.apache.commons.lang.StringUtils; import org.jenkinsci.plugins.ghprb.Ghprb; import org.jenkinsci.plugins.ghprb.GhprbCause; -import org.jenkinsci.plugins.ghprb.GhprbPullRequest; import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatus; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; @@ -41,11 +39,12 @@ public class GhprbSimpleStatus extends GhprbExtension implements GhprbCommitStat private final String startedStatus; private final String statusUrl; private final List completedStatus; - + + public GhprbSimpleStatus() { this(null, null, null, null, new ArrayList(0)); } - + public GhprbSimpleStatus(String commitStatusContext) { this(commitStatusContext, null, null, null, new ArrayList(0)); } @@ -84,15 +83,13 @@ public List getCompletedStatus() { return completedStatus == null ? new ArrayList(0) : completedStatus; } - public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHRepository ghRepository) throws GhprbCommitStatusException { +public void onBuildTriggered(AbstractProject project, String commitSha, boolean isMergeable, int prId, GHRepository ghRepository) throws GhprbCommitStatusException { + StringBuilder sb = new StringBuilder(); + GHCommitState state = GHCommitState.PENDING; String triggeredStatus = getDescriptor().getTriggeredStatusDefault(this); String statusUrl = getDescriptor().getStatusUrlDefault(this); String commitStatusContext = getDescriptor().getCommitStatusContextDefault(this); - StringBuilder sb = new StringBuilder(); - GHCommitState state = GHCommitState.PENDING; - - AbstractProject project = trigger.getActualProject(); String context = Util.fixEmpty(commitStatusContext); context = Ghprb.replaceMacros(project, context); @@ -101,7 +98,7 @@ public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHReposi sb.append(Ghprb.replaceMacros(project, triggeredStatus)); } else { sb.append("Build triggered."); - if (pr.isMergeable()) { + if (isMergeable) { sb.append(" sha1 is merged."); } else { sb.append(" sha1 is original commit."); @@ -112,11 +109,15 @@ public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHReposi String message = sb.toString(); try { - ghRepository.createCommitStatus(pr.getHead(), state, url, message, context); + ghRepository.createCommitStatus(commitSha, state, url, message, context); } catch (IOException e) { - throw new GhprbCommitStatusException(e, state, message, pr.getId()); + throw new GhprbCommitStatusException(e, state, message, prId); } } + + public void onEnvironmentSetup(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { + createCommitStatus(build, listener, "Build has started, please wait for results...", repo, GHCommitState.PENDING); + } public void onBuildStart(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { String startedStatus = getDescriptor().getStartedStatusDefault(this); @@ -162,17 +163,21 @@ public void onBuildComplete(AbstractBuild build, TaskListener listener, GH } private void createCommitStatus(AbstractBuild build, TaskListener listener, String message, GHRepository repo, GHCommitState state) throws GhprbCommitStatusException { - String statusUrl = getDescriptor().getStatusUrlDefault(this); - String commitStatusContext = getDescriptor().getCommitStatusContextDefault(this); + + Map envVars = Ghprb.getEnvVars(build, listener); - GhprbCause cause = Ghprb.getCause(build); + String sha1 = envVars.get("ghprbActualCommit"); + Integer pullId = Integer.parseInt(envVars.get("ghprbPullId")); - String sha1 = cause.getCommit(); - String url = Jenkins.getInstance().getRootUrl() + build.getUrl(); + String url = envVars.get("BUILD_URL"); + if (StringUtils.isEmpty(url)) { + url = envVars.get("JOB_URL"); + } + if (statusUrl == "--none--") { url = ""; } else if (!StringUtils.isEmpty(statusUrl)) { - url = Ghprb.replaceMacros(build, listener, statusUrl); + url = Ghprb.replaceMacros(build, listener, statusUrl); } String context = Util.fixEmpty(commitStatusContext); @@ -185,7 +190,7 @@ private void createCommitStatus(AbstractBuild build, TaskListener listener try { repo.createCommitStatus(sha1, state, url, message, context); } catch (IOException e) { - throw new GhprbCommitStatusException(e, state, message, cause.getPullID()); + throw new GhprbCommitStatusException(e, state, message, pullId); } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java new file mode 100644 index 000000000..b7a48f263 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java @@ -0,0 +1,120 @@ +package org.jenkinsci.plugins.ghprb.upstream; + +import hudson.Extension; +import hudson.Launcher; +import hudson.model.*; +import hudson.tasks.BuildWrapper; + +import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; +import org.kohsuke.github.GHCommitState; +import org.kohsuke.stapler.DataBoundConstructor; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * @author Kevin Suwala + */ + +public class GhprbUpstreamStatus extends BuildWrapper { + + private final String commitStatusContext; + private final String triggeredStatus; + private final String startedStatus; + private final String statusUrl; + private final List completedStatus; + + // sets the context and message as env vars so that they are available in the Listener class + @Override + public void makeBuildVariables(@SuppressWarnings("rawtypes") AbstractBuild build, Map variables){ + variables.put("ghprbUpstreamStatus", "true"); + variables.put("ghprbCommitStatusContext", commitStatusContext); + variables.put("ghprbTriggeredStatus", triggeredStatus); + variables.put("ghprbStartedStatus", startedStatus); + variables.put("ghprbStatusUrl", statusUrl); + + Map statusMessages = new HashMap(5); + + for (GhprbBuildResultMessage message : completedStatus) { + GHCommitState state = message.getResult(); + StringBuilder sb; + if (statusMessages.containsKey(state)){ + sb = new StringBuilder(); + statusMessages.put(state, sb); + } else { + sb = statusMessages.get(state); + sb.append("\n"); + } + sb.append(message.getMessage()); + } + + for (Entry next : statusMessages.entrySet()) { + String key = String.format("ghprb%sMessage", next.getKey().name()); + variables.put(key, next.getValue().toString()); + } + } + + @Override + @SuppressWarnings("unchecked") + public BuildWrapper.Environment setUp(@SuppressWarnings("rawtypes") AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + makeBuildVariables(build, build.getBuildVariables()); + return new Environment(){}; + } + + @Override + @SuppressWarnings("unchecked") + public void preCheckout(@SuppressWarnings("rawtypes") AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + makeBuildVariables(build, build.getBuildVariables()); + } + + @DataBoundConstructor + public GhprbUpstreamStatus( + String commitStatusContext, + String statusUrl, + String triggeredStatus, + String startedStatus, + List completedStatus + ) { + this.statusUrl = statusUrl; + this.commitStatusContext = commitStatusContext == null ? "" : commitStatusContext; + this.triggeredStatus = triggeredStatus; + this.startedStatus = startedStatus; + this.completedStatus = completedStatus; + } + + + public String getStatusUrl() { + return statusUrl == null ? "" : statusUrl; + } + + public String getCommitStatusContext() { + return commitStatusContext == null ? "" : commitStatusContext; + } + + public String getStartedStatus() { + return startedStatus == null ? "" : startedStatus; + } + + public String getTriggeredStatus() { + return triggeredStatus == null ? "" : triggeredStatus; + } + + public List getCompletedStatus() { + return completedStatus == null ? new ArrayList(0) : completedStatus; + } + + @Extension + public static final class DescriptorImpl extends Descriptor { + + @Override + public String getDisplayName() { + return "Set GitHub commit status with custom context and message (Must configure upstream job using GHPRB)"; + } + } + + +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusListener.java b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusListener.java new file mode 100644 index 000000000..7221244fc --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusListener.java @@ -0,0 +1,115 @@ +package org.jenkinsci.plugins.ghprb.upstream; + +import hudson.Extension; +import hudson.Launcher; +import hudson.model.BuildListener; +import hudson.model.Environment; +import hudson.model.TaskListener; +import hudson.model.AbstractBuild; +import hudson.model.listeners.RunListener; + +import org.apache.commons.lang.StringUtils; +import org.jenkinsci.plugins.ghprb.Ghprb; +import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; +import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; +import org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus; +import org.kohsuke.github.GHCommitState; +import org.kohsuke.github.GHRepository; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author Kevin Suwala + * This class is responsible for sending the custom status and message on + * downstream jobs that have the option configured. + */ + +@Extension +public class GhprbUpstreamStatusListener extends RunListener> { + private static final Logger logger = Logger.getLogger(GhprbUpstreamStatusListener.class.getName()); + + private GhprbSimpleStatus statusUpdater; + + private String upstreamJob = ""; + private GHRepository repo; + + // Gets all the custom env vars needed to send information to GitHub + private boolean updateEnvironmentVars(AbstractBuild build, TaskListener listener){ + + + Map envVars = Ghprb.getEnvVars(build, listener); + + if (!envVars.containsKey("ghprbUpstreamStatus")) { + return false; + } + + String jobName = envVars.get("JOB_NAME"); + + List statusMessages = new ArrayList(5); + + for (GHCommitState state : GHCommitState.values()) { + String envVar = String.format("ghprb%sMessage", state.name()); + String message = envVars.get(envVar); + statusMessages.add(new GhprbBuildResultMessage(state, message)); + } + + String context = envVars.get("commitStatusContext"); + + if (StringUtils.isEmpty(context)) { + context = jobName; + } + + statusUpdater = new GhprbSimpleStatus(envVars.get("ghprbCommitStatusContext"), envVars.get("ghprbStatusUrl"), envVars.get("ghprbTriggeredStatus"), envVars.get("ghprbStartedStatus"), statusMessages); + + upstreamJob = envVars.get("ghprbTriggerJob"); + repo = GhprbUpstreamStatusRepoPasser.getRepo(upstreamJob); + return true; + } + + // Sets the status as pending when the job starts and then calls the createCommitStatus method to send it to GitHub + @Override + public Environment setUpEnvironment(@SuppressWarnings("rawtypes") AbstractBuild build, Launcher launcher, BuildListener listener) { + if (updateEnvironmentVars(build, listener)) { + logger.log(Level.FINE, "Job: " + build.getFullDisplayName() + " Attempting to send GitHub commit status"); + + try { + statusUpdater.onEnvironmentSetup(build, listener, repo); + } catch (GhprbCommitStatusException e) { + e.printStackTrace(); + } + } + + return new Environment(){}; + } + + @Override + public void onStarted(AbstractBuild build, TaskListener listener) { + if (!updateEnvironmentVars(build, listener)) { + return; + } + + try { + statusUpdater.onBuildStart(build, listener, repo); + } catch (GhprbCommitStatusException e) { + e.printStackTrace(); + } + } + + // Sets the status to the build result when the job is done, and then calls the createCommitStatus method to send it to GitHub + @Override + public void onCompleted(AbstractBuild build, TaskListener listener) { + if (!updateEnvironmentVars(build, listener)) { + return; + } + + try { + statusUpdater.onBuildComplete(build, listener, repo); + } catch (GhprbCommitStatusException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusRepoPasser.java b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusRepoPasser.java new file mode 100644 index 000000000..39f8e892f --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusRepoPasser.java @@ -0,0 +1,28 @@ +package org.jenkinsci.plugins.ghprb.upstream; + +import org.kohsuke.github.GHRepository; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Kevin Suwala + * This class is responsible for storing the GHRepository for each job and making + * it accesible for other classes + */ + +public class GhprbUpstreamStatusRepoPasser { + private static Map repoMap = new HashMap(); + + public static GHRepository addRepo(String name, GHRepository repo) { + return repoMap.put(name, repo); + } + + public static GHRepository removeRepo(String name) { + return repoMap.remove(name); + } + + public static GHRepository getRepo(String name) { + return repoMap.get(name); + } +} diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/config.jelly deleted file mode 100644 index 4afebb901..000000000 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/config.jelly +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-context.html b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-context.html deleted file mode 100644 index 89aa0b3a0..000000000 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-context.html +++ /dev/null @@ -1,3 +0,0 @@ -
- Set a custom context that will appear on the Github PR that the upstream job pulled -
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-message.html b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-message.html deleted file mode 100644 index a8eea72c1..000000000 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help-message.html +++ /dev/null @@ -1,3 +0,0 @@ -
- Set a custom message that will appear on the Github PR that the upstream job pulled -
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/config.jelly new file mode 100644 index 000000000..d883f91dd --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/config.jelly @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-commitStatusContext.html b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-commitStatusContext.html new file mode 100644 index 000000000..f9f488e71 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-commitStatusContext.html @@ -0,0 +1,4 @@ +
+ Context: + A string label to differentiate this status from the status of other systems. Default: "default" +
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-completedStatus.html b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-completedStatus.html new file mode 100644 index 000000000..0301c9968 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-completedStatus.html @@ -0,0 +1,4 @@ +
+ Use a custom status on the commit for when a build is completed. + If the field is left blank then the default value is used instead. +
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-startedStatus.html b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-startedStatus.html new file mode 100644 index 000000000..4b6235478 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-startedStatus.html @@ -0,0 +1,4 @@ +
+ Use a custom status for when a build is started. + If the field is left blank then the default value is used instead. +
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-statusUrl.html b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-statusUrl.html new file mode 100644 index 000000000..82c957c7c --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-statusUrl.html @@ -0,0 +1,4 @@ +
+ Use a custom url instead of the Jenkins job url. + If the desired url should be blank, use "--none--" to alert the trigger to use a blank url. +
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-triggeredStatus.html b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-triggeredStatus.html new file mode 100644 index 000000000..f942bd38c --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help-triggeredStatus.html @@ -0,0 +1,4 @@ +
+ Use a custom status for when a build is triggered. + If the field is left blank then the default value is used instead. +
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help.html b/src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help.html similarity index 100% rename from src/main/resources/org/jenkinsci/plugins/ghprb/GhprbCustomStatus/help.html rename to src/main/resources/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus/help.html diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatusTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatusTest.java index 0741c28fd..212546b46 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatusTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatusTest.java @@ -46,13 +46,11 @@ public void testMergedMessage() throws Exception { given(ghprbPullRequest.isMergeable()).willReturn(true); GhprbSimpleStatus status = spy(new GhprbSimpleStatus("default")); - status.onBuildTriggered(trigger, ghprbPullRequest, ghRepository); + status.onBuildTriggered(trigger.getActualProject(), "sha", true, 1, ghRepository); verify(ghRepository).createCommitStatus(eq("sha"), eq(GHCommitState.PENDING), eq(""), eq(mergedMessage), eq("default")); verifyNoMoreInteractions(ghRepository); - verify(ghprbPullRequest).getHead(); - verify(ghprbPullRequest).isMergeable(); verifyNoMoreInteractions(ghprbPullRequest); } @@ -63,13 +61,11 @@ public void testMergeConflictMessage() throws Exception { given(ghprbPullRequest.isMergeable()).willReturn(false); GhprbSimpleStatus status = spy(new GhprbSimpleStatus("default")); - status.onBuildTriggered(trigger, ghprbPullRequest, ghRepository); + status.onBuildTriggered(trigger.getActualProject(), "sha", false, 1, ghRepository); verify(ghRepository).createCommitStatus(eq("sha"), eq(GHCommitState.PENDING), eq(""), eq(mergedMessage), eq("default")); verifyNoMoreInteractions(ghRepository); - verify(ghprbPullRequest).getHead(); - verify(ghprbPullRequest).isMergeable(); verifyNoMoreInteractions(ghprbPullRequest); } @@ -80,13 +76,11 @@ public void testDoesNotSendEmptyContext() throws Exception { given(ghprbPullRequest.isMergeable()).willReturn(false); GhprbSimpleStatus status = spy(new GhprbSimpleStatus("")); - status.onBuildTriggered(trigger, ghprbPullRequest, ghRepository); + status.onBuildTriggered(trigger.getActualProject(), "sha", false, 1, ghRepository); verify(ghRepository).createCommitStatus(eq("sha"), eq(GHCommitState.PENDING), eq(""), eq(mergedMessage), isNull(String.class)); verifyNoMoreInteractions(ghRepository); - verify(ghprbPullRequest).getHead(); - verify(ghprbPullRequest).isMergeable(); verifyNoMoreInteractions(ghprbPullRequest); } } From 8edd0d253e4d82c88ffcca56b5b49cb8b986e520 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 10 Sep 2015 08:55:14 -0600 Subject: [PATCH 030/175] Move to env variables for repo. The repo is passed as environment variables to other jobs, then there is no leak with the RepoPasser --- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 4 +-- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 3 +- .../ghprb/upstream/GhprbUpstreamStatus.java | 2 +- .../upstream/GhprbUpstreamStatusListener.java | 20 ++++++++++--- .../GhprbUpstreamStatusRepoPasser.java | 28 ------------------- 5 files changed, 20 insertions(+), 37 deletions(-) delete mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusRepoPasser.java diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 42c3340f4..e9ae0ce78 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -13,7 +13,6 @@ import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatus; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; -import org.jenkinsci.plugins.ghprb.upstream.GhprbCustomStatusRepoPasser; import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GHIssueState; import org.kohsuke.github.GHPullRequest; @@ -59,9 +58,8 @@ public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) logger.log(Level.SEVERE, "Job did not start"); } } - + public void onStarted(AbstractBuild build, TaskListener listener) { - GhprbCustomStatusRepoPasser.addRepo(build.getFullDisplayName(), repo.getGitHubRepo()); PrintStream logger = listener.getLogger(); GhprbCause c = Ghprb.getCause(build); if (c == null) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index c0a03848b..8a843c7dc 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -260,7 +260,8 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbPullLink", String.valueOf(cause.getUrl()))); values.add(new StringParameterValue("ghprbPullLongDescription", String.valueOf(cause.getDescription()))); values.add(new StringParameterValue("ghprbCommentBody", String.valueOf(cause.getCommentBody()))); - values.add(new StringParameterValue("ghprbTriggerJob", this.job.getFullDisplayName() + " #" + this.job.getNextBuildNumber())); + values.add(new StringParameterValue("ghprbGhRepository", repo.getName())); + values.add(new StringParameterValue("ghprbCredentialsId", this.getGitHubApiAuth().getCredentialsId())); // add the previous pr BuildData as an action so that the correct change log is generated by the GitSCM plugin // note that this will be removed from the Actions list after the job is completed so that the old (and incorrect) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java index b7a48f263..e1c7f2573 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java @@ -112,7 +112,7 @@ public static final class DescriptorImpl extends Descriptor { @Override public String getDisplayName() { - return "Set GitHub commit status with custom context and message (Must configure upstream job using GHPRB)"; + return "Set GitHub commit status with custom context and message (Must configure upstream job using GHPRB trigger)"; } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusListener.java b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusListener.java index 7221244fc..b9beaa09c 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusListener.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusListener.java @@ -10,11 +10,14 @@ import org.apache.commons.lang.StringUtils; import org.jenkinsci.plugins.ghprb.Ghprb; +import org.jenkinsci.plugins.ghprb.GhprbGitHubAuth; +import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; import org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus; import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GitHub; import java.util.ArrayList; import java.util.List; @@ -34,7 +37,6 @@ public class GhprbUpstreamStatusListener extends RunListener private GhprbSimpleStatus statusUpdater; - private String upstreamJob = ""; private GHRepository repo; // Gets all the custom env vars needed to send information to GitHub @@ -65,9 +67,19 @@ private boolean updateEnvironmentVars(AbstractBuild build, TaskListener li statusUpdater = new GhprbSimpleStatus(envVars.get("ghprbCommitStatusContext"), envVars.get("ghprbStatusUrl"), envVars.get("ghprbTriggeredStatus"), envVars.get("ghprbStartedStatus"), statusMessages); - upstreamJob = envVars.get("ghprbTriggerJob"); - repo = GhprbUpstreamStatusRepoPasser.getRepo(upstreamJob); - return true; + String credentialsId = envVars.get("ghprbCredentialsId"); + String repoName = envVars.get("ghprbGhRepository"); + + GhprbGitHubAuth auth = GhprbTrigger.getDscp().getGitHubAuth(credentialsId); + try { + GitHub gh = auth.getConnection(build.getProject()); + repo = gh.getRepository(repoName); + return true; + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to connect to GitHub repo", e); + return false; + } + } // Sets the status as pending when the job starts and then calls the createCommitStatus method to send it to GitHub diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusRepoPasser.java b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusRepoPasser.java deleted file mode 100644 index 39f8e892f..000000000 --- a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatusRepoPasser.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.jenkinsci.plugins.ghprb.upstream; - -import org.kohsuke.github.GHRepository; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author Kevin Suwala - * This class is responsible for storing the GHRepository for each job and making - * it accesible for other classes - */ - -public class GhprbUpstreamStatusRepoPasser { - private static Map repoMap = new HashMap(); - - public static GHRepository addRepo(String name, GHRepository repo) { - return repoMap.put(name, repo); - } - - public static GHRepository removeRepo(String name) { - return repoMap.remove(name); - } - - public static GHRepository getRepo(String name) { - return repoMap.get(name); - } -} From cb8447f991aebe3de688d3548c451dd128e16900 Mon Sep 17 00:00:00 2001 From: Felix Belzunce Arcos Date: Wed, 16 Sep 2015 11:31:15 +0200 Subject: [PATCH 031/175] Allow to work with CSR protection --- .../plugins/ghprb/GhprbCrumbExclusion.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbCrumbExclusion.java diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCrumbExclusion.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCrumbExclusion.java new file mode 100644 index 000000000..e95e2328b --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbCrumbExclusion.java @@ -0,0 +1,33 @@ +package org.jenkinsci.plugins.ghprb; + +import hudson.Extension; +import hudson.security.csrf.CrumbExclusion; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Excludes {@link GhprbRootAction} from the CSRF protection. + * @since 1.28 + */ +@Extension +public class GhprbCrumbExclusion extends CrumbExclusion { + + @Override + public boolean process(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) + throws IOException, ServletException { + final String pathInfo = req.getPathInfo(); + if (pathInfo != null && pathInfo.startsWith(getExclusionPath())) { + chain.doFilter(req, resp); + return true; + } + return false; + } + + public String getExclusionPath() { + return "/" + GhprbRootAction.URL + "/"; + } +} \ No newline at end of file From 47453af5d8a3e9e13c96e4fca967370e4912bcdb Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 21 Sep 2015 11:52:18 -0600 Subject: [PATCH 032/175] Remove old constructor, add logger statements for own code --- .../plugins/ghprb/GhprbPullRequestMerge.java | 14 ++----------- .../ghprb/GhprbPullRequestMergeTest.java | 21 +++++++------------ 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index f76110ce4..90ad74576 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -21,7 +21,6 @@ import hudson.FilePath; import hudson.Launcher; import hudson.model.BuildListener; -import hudson.model.Cause; import hudson.model.Result; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; @@ -56,17 +55,6 @@ public GhprbPullRequestMerge( this.deleteOnMerge = deleteOnMerge; } - public GhprbPullRequestMerge( - String mergeComment, - boolean onlyTriggerPhrase, - boolean onlyAdminsMerge, - boolean disallowOwnCode, - boolean failOnNonMerge, - boolean deleteOnMerge) { - - this(mergeComment, onlyAdminsMerge, disallowOwnCode, failOnNonMerge, deleteOnMerge); - } - public String getMergeComment() { return mergeComment; } @@ -243,6 +231,7 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { GHUser prUser = pr.getUser(); if (prUser.getLogin().equals(commentorLogin)) { + logger.println(commentorName + " (" + commentorLogin + ") has commits in PR[" + pr.getId() + "] that is to be merged"); return true; } @@ -257,6 +246,7 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { isSame |= commentorName != null && commentorName.equals(committerName); isSame |= commentorEmail != null && commentorEmail.equals(committerEmail); + logger.println(commentorName + " (" + commentorEmail + ") has commits in PR[" + pr.getId() + "] that is to be merged"); return isSame; } } catch (IOException e) { diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index d7f5227d7..3f1961d75 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -195,7 +195,6 @@ private void setupConditions(String triggerLogin, String committerName, String c } private GhprbPullRequestMerge setupMerger( - boolean onlyTriggerPhrase, boolean onlyAdminsMerge, boolean disallowOwnCode, boolean failOnNonMerge, @@ -204,7 +203,6 @@ private GhprbPullRequestMerge setupMerger( GhprbPullRequestMerge merger = spy(new GhprbPullRequestMerge( mergeComment, - onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode, failOnNonMerge, @@ -216,20 +214,19 @@ private GhprbPullRequestMerge setupMerger( return merger; } - private GhprbPullRequestMerge setupMerger(boolean onlyTriggerPhrase, + private GhprbPullRequestMerge setupMerger( boolean onlyAdminsMerge, boolean disallowOwnCode) { - return setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode, false, false); + return setupMerger(onlyAdminsMerge, disallowOwnCode, false, false); } @Test public void testApproveMerge() throws Exception { - boolean onlyTriggerPhrase = false; boolean onlyAdminsMerge = false; boolean disallowOwnCode = false; - GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); + GhprbPullRequestMerge merger = setupMerger(onlyAdminsMerge, disallowOwnCode); setupConditions(nonAdminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); @@ -267,11 +264,10 @@ public void testApproveMerge() throws Exception { @Test public void testAdminMerge() throws Exception { - boolean onlyTriggerPhrase = false; boolean onlyAdminsMerge = true; boolean disallowOwnCode = false; - GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); + GhprbPullRequestMerge merger = setupMerger(onlyAdminsMerge, disallowOwnCode); setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); @@ -285,11 +281,10 @@ public void testAdminMerge() throws Exception { @Test public void testTriggerMerge() throws Exception { - boolean onlyTriggerPhrase = true; boolean onlyAdminsMerge = false; boolean disallowOwnCode = false; - GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); + GhprbPullRequestMerge merger = setupMerger(onlyAdminsMerge, disallowOwnCode); setupConditions(adminLogin, committerName, committerEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); @@ -303,11 +298,10 @@ public void testTriggerMerge() throws Exception { @Test public void testOwnCodeMerge() throws Exception { - boolean onlyTriggerPhrase = false; boolean onlyAdminsMerge = false; boolean disallowOwnCode = true; - GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); + GhprbPullRequestMerge merger = setupMerger(onlyAdminsMerge, disallowOwnCode); setupConditions(adminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(true); @@ -321,11 +315,10 @@ public void testOwnCodeMerge() throws Exception { @Test public void testDenyMerge() throws Exception { - boolean onlyTriggerPhrase = true; boolean onlyAdminsMerge = true; boolean disallowOwnCode = true; - GhprbPullRequestMerge merger = setupMerger(onlyTriggerPhrase, onlyAdminsMerge, disallowOwnCode); + GhprbPullRequestMerge merger = setupMerger(onlyAdminsMerge, disallowOwnCode); setupConditions(nonAdminLogin, nonAdminLogin, nonCommitterName, nonCommitterEmail, triggerPhrase); assertThat(merger.perform(build, null, listener)).isEqualTo(false); From 1b40569567e551286918ad1a199367ba6709e93c Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 21 Sep 2015 14:08:38 -0600 Subject: [PATCH 033/175] Fixed #165 Move the checkSignature function to after the repo matches. --- .../org/jenkinsci/plugins/ghprb/GhprbWebHook.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java index db8b0848d..97830dba5 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java @@ -25,9 +25,6 @@ public GhprbWebHook(GhprbTrigger trigger) { } public void handleWebHook(String event, String payload, String body, String signature) { - if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())){ - return; - } GhprbRepository repo = trigger.getRepository(); String repoName = repo.getName(); @@ -47,6 +44,10 @@ public void handleWebHook(String event, String payload, String body, String sign } if (matchRepo(repo, issueComment.getRepository())) { + if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())){ + return; + } + logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", new Object[] { issueComment.getComment(), repoName } ); @@ -58,6 +59,10 @@ public void handleWebHook(String event, String payload, String body, String sign new StringReader(payload), GHEventPayload.PullRequest.class); if (matchRepo(repo, pr.getPullRequest().getRepository())) { + if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())){ + return; + } + logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repoName, pr.getNumber() }); repo.onPullRequestHook(pr); } From 8c5988e3d61dea26112c8e300c0ce524c184a5e2 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 21 Sep 2015 15:13:49 -0600 Subject: [PATCH 034/175] Replace newline chars in some env variables Fixes janinko/ghprb#322 Fixes #166 --- .../java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 01756d5ad..9f7ccf44c 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -252,15 +252,17 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbTargetBranch", String.valueOf(cause.getTargetBranch()))); values.add(new StringParameterValue("ghprbSourceBranch", String.valueOf(cause.getSourceBranch()))); values.add(new StringParameterValue("GIT_BRANCH", String.valueOf(cause.getSourceBranch()))); + // it's possible the GHUser doesn't have an associated email address values.add(new StringParameterValue("ghprbPullAuthorEmail", getString(cause.getAuthorEmail(), ""))); values.add(new StringParameterValue("ghprbPullAuthorLogin", String.valueOf(cause.getPullRequestAuthor().getLogin()))); values.add(new StringParameterValue("ghprbPullAuthorLoginMention", "@" + cause.getPullRequestAuthor().getLogin())); - values.add(new StringParameterValue("ghprbPullDescription", String.valueOf(cause.getShortDescription()))); + + values.add(new StringParameterValue("ghprbPullDescription", String.valueOf(cause.getShortDescription()).replace("\n", "\\n"))); values.add(new StringParameterValue("ghprbPullTitle", String.valueOf(cause.getTitle()))); values.add(new StringParameterValue("ghprbPullLink", String.valueOf(cause.getUrl()))); - values.add(new StringParameterValue("ghprbPullLongDescription", String.valueOf(cause.getDescription()))); - values.add(new StringParameterValue("ghprbCommentBody", String.valueOf(cause.getCommentBody()))); + values.add(new StringParameterValue("ghprbPullLongDescription", String.valueOf(cause.getDescription()).replace("\n", "\\n"))); + values.add(new StringParameterValue("ghprbCommentBody", String.valueOf(cause.getCommentBody()).replace("\n", "\\n"))); // add the previous pr BuildData as an action so that the correct change log is generated by the GitSCM plugin // note that this will be removed from the Actions list after the job is completed so that the old (and incorrect) From 7690154b8c94be9d2d1a56ce7f0b866efc730842 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 21 Sep 2015 15:15:01 -0600 Subject: [PATCH 035/175] Fix credentials list so it returns the selected value Fixes janinko/ghprb#319 --- .../plugins/ghprb/GhprbGitHubAuth.java | 29 +++++++++++++------ .../ghprb/GhprbGitHubAuth/config.groovy | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java index 819aa60f5..863d823bb 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java @@ -24,6 +24,7 @@ import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.export.Exported; +import com.cloudbees.plugins.credentials.CredentialsMatcher; import com.cloudbees.plugins.credentials.CredentialsMatchers; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.IdCredentials; @@ -174,20 +175,30 @@ public String getDisplayName() { * @return list box model. * @throws URISyntaxException */ - public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context, @QueryParameter String serverAPIUrl) throws URISyntaxException { + public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context, @QueryParameter String serverAPIUrl, @QueryParameter String credentialsId) throws URISyntaxException { List domainRequirements = URIRequirementBuilder.fromUri(serverAPIUrl).build(); + List matchers = new ArrayList(3); + if (!StringUtils.isEmpty(credentialsId)) { + matchers.add(0, CredentialsMatchers.withId(credentialsId)); + } + + matchers.add(CredentialsMatchers.instanceOf(StandardUsernamePasswordCredentials.class)); + matchers.add(CredentialsMatchers.instanceOf(StringCredentials.class)); + + List credentials = CredentialsProvider.lookupCredentials( + StandardCredentials.class, + context, + ACL.SYSTEM, + domainRequirements + ); + return new StandardListBoxModel() - .withEmptySelection() .withMatching( CredentialsMatchers.anyOf( - CredentialsMatchers.instanceOf(StandardUsernamePasswordCredentials.class), - CredentialsMatchers.instanceOf(StringCredentials.class)), - CredentialsProvider.lookupCredentials(StandardCredentials.class, - context, - ACL.SYSTEM, - domainRequirements) - ); + matchers.toArray(new CredentialsMatcher[0])), + credentials + ); } diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy index 1f2e759f5..8d3f4efab 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy @@ -12,7 +12,7 @@ f.entry(title:_("Shared secret"), field:"secret") { f.entry(title:_("Credentials"), field:"credentialsId") { c.select(onchange="""{ var self = this.targetElement ? this.targetElement : this; - var r = findPreviousFormItem(self,'serverAPIUrl'); + var r = findPreviousFormItem(self,'serverAPIUrl','credentialsId'); r.onchange(r); self = null; r = null; From f684bfed7d1452189e8b05f67472eca6adc64bc3 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 15 Sep 2015 12:56:57 -0400 Subject: [PATCH 036/175] use equals() and fix onBuildTriggered() We weren't checking for the "--none--" magic string in onBuildTriggered(), which caused the the commit status updating to fail. Also use String.equals() to check the actual content of the string. --- .../plugins/ghprb/extensions/status/GhprbSimpleStatus.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index 0c03ff04c..e4a768ec4 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -109,6 +109,9 @@ public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHReposi } String url = Ghprb.replaceMacros(project, statusUrl); + if (statusUrl.equals("--none--")) { + url = ""; + } String message = sb.toString(); try { @@ -169,7 +172,7 @@ private void createCommitStatus(AbstractBuild build, TaskListener listener String sha1 = cause.getCommit(); String url = Jenkins.getInstance().getRootUrl() + build.getUrl(); - if (statusUrl == "--none--") { + if (statusUrl.equals("--none--")) { url = ""; } else if (!StringUtils.isEmpty(statusUrl)) { url = Ghprb.replaceMacros(build, listener, statusUrl); From a890fe34d0e2e7edfc22df1a7e67f3f984238557 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Thu, 17 Sep 2015 10:14:03 -0400 Subject: [PATCH 037/175] add support for disabling certain commit status updates Right now the GhprbNoCommitStatus extension can be used to completely disable status updates during the build. However, it would be nice to have finer control so that users can choose for which events they would like the commit to be updated. This patch adds support for this by adding detection for the "--none--" key string in the triggeredStatus, startedStatus, and completedStatus fields. For completedStatus, it depends on the result chosen, e.g. we may want to update the build if it failed, but not if it succeeded. --- .../comments/GhprbBuildResultMessage.java | 4 +++- .../extensions/status/GhprbSimpleStatus.java | 18 ++++++++++++++++-- .../GhprbBuildResultMessage/help-message.html | 4 +++- .../help-completedStatus.html | 2 +- .../GhprbSimpleStatus/help-startedStatus.html | 3 ++- .../help-triggeredStatus.html | 3 ++- 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildResultMessage.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildResultMessage.java index 1726892f5..be52e1817 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildResultMessage.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildResultMessage.java @@ -44,7 +44,9 @@ public String postBuildComment(AbstractBuild build, TaskListener listener) if (state == result) { buildMessage = message; if (StringUtils.isEmpty(buildMessage)) { - return ""; + return ""; // will use default + } else if (buildMessage.equals("--none--")) { + return buildMessage; // will skip update } String message = Ghprb.replaceMacros(build, listener, buildMessage); // Only Append the build's custom message if it has been set. diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index e4a768ec4..df7f1336d 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -86,9 +86,15 @@ public List getCompletedStatus() { public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHRepository ghRepository) throws GhprbCommitStatusException { String triggeredStatus = getDescriptor().getTriggeredStatusDefault(this); + + // check if we even need to update + if (triggeredStatus.equals("--none--")) { + return; + } + String statusUrl = getDescriptor().getStatusUrlDefault(this); String commitStatusContext = getDescriptor().getCommitStatusContextDefault(this); - + StringBuilder sb = new StringBuilder(); GHCommitState state = GHCommitState.PENDING; @@ -123,7 +129,12 @@ public void onBuildTriggered(GhprbTrigger trigger, GhprbPullRequest pr, GHReposi public void onBuildStart(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { String startedStatus = getDescriptor().getStartedStatusDefault(this); - + + // check if we even need to update + if (startedStatus.equals("--none--")) { + return; + } + GhprbCause c = Ghprb.getCause(build); StringBuilder sb = new StringBuilder(); if (StringUtils.isEmpty(startedStatus)) { @@ -148,6 +159,9 @@ public void onBuildComplete(AbstractBuild build, TaskListener listener, GH for (GhprbBuildResultMessage buildStatus : completedStatus) { sb.append(buildStatus.postBuildComment(build, listener)); } + if (sb.toString().equals("--none--")) { + return; + } } sb.append(" "); diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildResultMessage/help-message.html b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildResultMessage/help-message.html index a86712a55..f06228927 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildResultMessage/help-message.html +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildResultMessage/help-message.html @@ -1,3 +1,5 @@
The message that is appended to a comment when a build finishes with the desired build status. -
\ No newline at end of file + If no status updates should be made when a build finishes with the indicated + build status, use "--none--" to alert the trigger. + diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-completedStatus.html b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-completedStatus.html index 0301c9968..9d4442d6a 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-completedStatus.html +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-completedStatus.html @@ -1,4 +1,4 @@
Use a custom status on the commit for when a build is completed. If the field is left blank then the default value is used instead. -
\ No newline at end of file + diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-startedStatus.html b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-startedStatus.html index 4b6235478..b4e1c9fbb 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-startedStatus.html +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-startedStatus.html @@ -1,4 +1,5 @@
Use a custom status for when a build is started. If the field is left blank then the default value is used instead. -
\ No newline at end of file + If no status updates should be made when a build is started, use "--none--" to alert the trigger. + diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-triggeredStatus.html b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-triggeredStatus.html index f942bd38c..4c32d7185 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-triggeredStatus.html +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus/help-triggeredStatus.html @@ -1,4 +1,5 @@
Use a custom status for when a build is triggered. If the field is left blank then the default value is used instead. -
\ No newline at end of file + If no status updates should be made when a build is triggered, use "--none--" to alert the trigger. + From 81e8b837544b04560c2ee766f6438ec22fd22cd0 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 09:38:55 -0600 Subject: [PATCH 038/175] Refix issue with == --- .../plugins/ghprb/extensions/status/GhprbSimpleStatus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index c11ee81d8..21ae0be60 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -190,7 +190,7 @@ private void createCommitStatus(AbstractBuild build, TaskListener listener url = envVars.get("JOB_URL"); } - if (statusUrl == "--none--") { + if (statusUrl.equals("--none--")) { url = ""; } else if (!StringUtils.isEmpty(statusUrl)) { url = Ghprb.replaceMacros(build, listener, statusUrl); From a1323919c94c0b615e6648e59e1883a2c05d3096 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 10:03:35 -0600 Subject: [PATCH 039/175] Update Readme --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index f5e3cd91b..538d2d2bc 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,16 @@ If you want to manually build the job, in the job setting check ``This build is ### Updates +#### -> 1.28 +* Fixed [JENKINS-29850] Add author github repo URL +* Fixed NPE and other errors in merge logic +* Removed only trigger phrase, trigger is expected always now +* Fixed [JENKINS-30115] Downstream jobs can now attach GitHub status messages +* Fixed SHA1 for Matrix builds +* Global defaults are now used if the local value isn't set. +* Fixed issues with CSR protection +* Commit updates can be skipped all together or individual steps can be skipped using --none-- + #### -> 1.27 * Trigger is now a regex term * Phrases are no matched agains multiple lines properly From 01710c7a186669819bf30525d0b8943241102390 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 10:07:02 -0600 Subject: [PATCH 040/175] [maven-release-plugin] prepare release ghprb-1.28 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 62955caf1..f36ed4d8a 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.28-SNAPSHOT + 1.28 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.28 From 0a4aa1bd09209e33b8c915869f08edbf553c4c25 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 10:07:06 -0600 Subject: [PATCH 041/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f36ed4d8a..d69742fd4 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.28 + 1.29-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.28 + HEAD From ddcf9788fe056d6f997121900189857b4db3d695 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Tue, 22 Sep 2015 18:54:51 -0400 Subject: [PATCH 042/175] NPEs in 1.28 fixes #184, connected to #184 --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 2 +- .../plugins/ghprb/extensions/status/GhprbSimpleStatus.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index b23b1387d..a975a4b2b 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -241,7 +241,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { } catch (Exception e) {} setCommitAuthor(cause, values); - values.add(new StringParameterValue("ghprbAuthorRepoGitUrl", cause.getAuthorRepoGitUrl())); + values.add(new StringParameterValue("ghprbAuthorRepoGitUrl", getString(cause.getAuthorRepoGitUrl(), ""))); values.add(new StringParameterValue("ghprbTriggerAuthor", triggerAuthor)); values.add(new StringParameterValue("ghprbTriggerAuthorEmail", triggerAuthorEmail)); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index 21ae0be60..60689e49a 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -111,7 +111,7 @@ public void onBuildTriggered(AbstractProject project, String commitSha, bo } String url = Ghprb.replaceMacros(project, statusUrl); - if (statusUrl.equals("--none--")) { + if ("--none--".equals(statusUrl) || statusUrl == null) { url = ""; } @@ -190,7 +190,7 @@ private void createCommitStatus(AbstractBuild build, TaskListener listener url = envVars.get("JOB_URL"); } - if (statusUrl.equals("--none--")) { + if ("--none--".equals(statusUrl) || statusUrl == null) { url = ""; } else if (!StringUtils.isEmpty(statusUrl)) { url = Ghprb.replaceMacros(build, listener, statusUrl); From e730ece9eb0a7d886e3ec7262e0a78582db56e5f Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 17:17:22 -0600 Subject: [PATCH 043/175] More places for NPE error --- .../plugins/ghprb/extensions/status/GhprbSimpleStatus.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index 60689e49a..0a30f0552 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -89,7 +89,7 @@ public void onBuildTriggered(AbstractProject project, String commitSha, bo String triggeredStatus = getDescriptor().getTriggeredStatusDefault(this); // check if we even need to update - if (triggeredStatus.equals("--none--")) { + if (triggeredStatus != null && triggeredStatus.equals("--none--")) { return; } @@ -131,7 +131,7 @@ public void onBuildStart(AbstractBuild build, TaskListener listener, GHRep String startedStatus = getDescriptor().getStartedStatusDefault(this); // check if we even need to update - if (startedStatus.equals("--none--")) { + if (startedStatus != null && startedStatus.equals("--none--")) { return; } From e2feb7e8c23f11437e68a5ce3c1fff55b4f911b6 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 18:11:35 -0600 Subject: [PATCH 044/175] [maven-release-plugin] prepare release ghprb-1.28.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d69742fd4..83baf568f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29-SNAPSHOT + 1.28.1 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.28.1 From 984460f3502ce3a34beb7ce529516d08accc731a Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 18:11:38 -0600 Subject: [PATCH 045/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 83baf568f..d69742fd4 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.28.1 + 1.29-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.28.1 + HEAD From 038038b40b998b4d742b6ae0ea784c17a8a7f7f6 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 22 Sep 2015 18:48:10 -0400 Subject: [PATCH 046/175] Fix NPE due to inverted logic in GhprbUpstreamStatus.java It's when the key is *not* in the map that we should create a new one, not the other way around. --- .../jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java index e1c7f2573..f02e957d2 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java @@ -42,7 +42,7 @@ public void makeBuildVariables(@SuppressWarnings("rawtypes") AbstractBuild build for (GhprbBuildResultMessage message : completedStatus) { GHCommitState state = message.getResult(); StringBuilder sb; - if (statusMessages.containsKey(state)){ + if (!statusMessages.containsKey(state)) { sb = new StringBuilder(); statusMessages.put(state, sb); } else { From eb2aa4b68986751d97b22c8e5b1366de40fe1a52 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 22 Sep 2015 21:44:15 -0400 Subject: [PATCH 047/175] Make sure build was caused by ghprb before doing onEnvironmentSetup() --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 99658b3c1..35135860a 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -215,6 +215,11 @@ private void commentOnBuildResult(AbstractBuild build, TaskListener listen } public void onEnvironmentSetup(@SuppressWarnings("rawtypes") AbstractBuild build, Launcher launcher, BuildListener listener) { + GhprbCause c = Ghprb.getCause(build); + if (c == null) { + return; + } + logger.log(Level.FINE, "Job: " + build.getFullDisplayName() + " Attempting to send GitHub commit status"); for (GhprbExtension ext : Ghprb.getJobExtensions(trigger, GhprbCommitStatus.class)) { From 9c62cc632f1c57e29fcb119e540fa98cf048705e Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 20:35:49 -0600 Subject: [PATCH 048/175] [maven-release-plugin] prepare release ghprb-1.28.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d69742fd4..8bb0b30a1 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29-SNAPSHOT + 1.28.2 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.28.2 From 955dbf684b8503659ffdd7c1087a13efd0a66b5b Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 20:35:52 -0600 Subject: [PATCH 049/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8bb0b30a1..d69742fd4 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.28.2 + 1.29-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.28.2 + HEAD From 70d7615773596f971b434610d64130fa96d01eee Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 21:02:27 -0600 Subject: [PATCH 050/175] Fix credentialsId being null --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index a975a4b2b..f6b0490b0 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -267,7 +267,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbCommentBody", String.valueOf(cause.getCommentBody()).replace("\n", "\\n"))); values.add(new StringParameterValue("ghprbGhRepository", repo.getName())); - values.add(new StringParameterValue("ghprbCredentialsId", this.getGitHubApiAuth().getCredentialsId())); + values.add(new StringParameterValue("ghprbCredentialsId", getString(getGitHubApiAuth().getCredentialsId(), ""))); // add the previous pr BuildData as an action so that the correct change log is generated by the GitSCM plugin // note that this will be removed from the Actions list after the job is completed so that the old (and incorrect) From d7b9118f78ca93f9c39772d430459e47c03340d7 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 21:11:16 -0600 Subject: [PATCH 051/175] use getters so we get empty string instead of null --- .../plugins/ghprb/upstream/GhprbUpstreamStatus.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java index f02e957d2..84c54be83 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java @@ -32,10 +32,10 @@ public class GhprbUpstreamStatus extends BuildWrapper { @Override public void makeBuildVariables(@SuppressWarnings("rawtypes") AbstractBuild build, Map variables){ variables.put("ghprbUpstreamStatus", "true"); - variables.put("ghprbCommitStatusContext", commitStatusContext); - variables.put("ghprbTriggeredStatus", triggeredStatus); - variables.put("ghprbStartedStatus", startedStatus); - variables.put("ghprbStatusUrl", statusUrl); + variables.put("ghprbCommitStatusContext", getCommitStatusContext()); + variables.put("ghprbTriggeredStatus", getTriggeredStatus()); + variables.put("ghprbStartedStatus", getStartedStatus()); + variables.put("ghprbStatusUrl", getStatusUrl()); Map statusMessages = new HashMap(5); From 90fa3d276a54355b0d26dbfa6d85e64516024c49 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 21:25:49 -0600 Subject: [PATCH 052/175] Remove unnecessary check --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index f6b0490b0..46c849855 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -290,10 +290,6 @@ public GhprbGitHubAuth getGitHubApiAuth() { public GitHub getGitHub() throws IOException { GhprbGitHubAuth auth = getGitHubApiAuth(); - if (auth == null) { - return null; - } - return auth.getConnection(getActualProject()); } From 683cad07a5950d13b8765b7bd86227e07dcd8564 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 22:17:54 -0600 Subject: [PATCH 053/175] [maven-release-plugin] prepare release ghprb-1.28.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d69742fd4..e26fa8725 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29-SNAPSHOT + 1.28.3 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.28.3 From 77ddcc140fe3ab2bfc16b7756a1150beee0fa870 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Sep 2015 22:17:58 -0600 Subject: [PATCH 054/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e26fa8725..d69742fd4 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.28.3 + 1.29-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.28.3 + HEAD From 628ae016a756a6a9ecc5b0a46640ecc5e5fe2053 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Wed, 23 Sep 2015 09:47:25 -0400 Subject: [PATCH 055/175] Don't create a commit status in onEnvironmentSetup() The commit status that would be created in onEnvironmentSetup() would happen right after the one from onBuildStart() and thus would wipe whatever the user wanted to have set there as their startedStatus string (or e.g. if the user had specified "--none--" to avoid any update at all). Remove that status update since it is superfluous. --- .../plugins/ghprb/extensions/status/GhprbSimpleStatus.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index 0a30f0552..e2da2c57e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -122,9 +122,10 @@ public void onBuildTriggered(AbstractProject project, String commitSha, bo throw new GhprbCommitStatusException(e, state, message, prId); } } - + public void onEnvironmentSetup(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { - createCommitStatus(build, listener, "Build has started, please wait for results...", repo, GHCommitState.PENDING); + // no need to create a commit here -- the onBuildStart() event will fire + // soon and will respect's the user's settings for startedStatus. } public void onBuildStart(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { From 268aed517ac4ca9384da8cd72e1a2e1f18e632fd Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 23 Sep 2015 09:38:28 -0600 Subject: [PATCH 056/175] Reduce noise of webhook handling for many jobs --- .../plugins/ghprb/GhprbRepository.java | 26 +++-- .../plugins/ghprb/GhprbRootAction.java | 52 ++++++++-- .../jenkinsci/plugins/ghprb/GhprbWebHook.java | 95 +++++++------------ 3 files changed, 98 insertions(+), 75 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 38239fd6b..1421b341c 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -253,24 +253,34 @@ public GHPullRequest getPullRequest(int id) throws IOException { return getGitHubRepo().getPullRequest(id); } - void onIssueCommentHook(IssueComment issueComment) throws IOException { + void onIssueCommentHook(IssueComment issueComment) { if (helper.isProjectDisabled()) { logger.log(Level.FINE, "Not checking comments since build is disabled"); return; } + int id = issueComment.getIssue().getNumber(); - logger.log(Level.FINER, "Comment on issue #{0} from {1}: {2}", new Object[] { id, issueComment.getComment().getUser(), issueComment.getComment().getBody() }); + try { + logger.log(Level.FINER, "Comment on issue #{0} from {1}: {2}", new Object[] { id, issueComment.getComment().getUser().getLogin(), issueComment.getComment().getBody() }); + } catch (IOException e) { + logger.log(Level.FINER, "Comment on issue #{0} unable to get user: {2}", new Object[] { id, issueComment.getComment().getBody() }); + } if (!"created".equals(issueComment.getAction())) { return; } - GhprbPullRequest pull = pulls.get(id); - if (pull == null) { - pull = new GhprbPullRequest(getGitHubRepo().getPullRequest(id), helper, this); - pulls.put(id, pull); + try { + GhprbPullRequest pull = pulls.get(id); + + if (pull == null) { + pull = new GhprbPullRequest(getGitHubRepo().getPullRequest(id), helper, this); + pulls.put(id, pull); + } + pull.check(issueComment.getComment()); + GhprbTrigger.getDscp().save(); + } catch (IOException e) { + logger.log(Level.WARNING, "Unable to get pull request #{0} from GitHub for repo {1}!!", new Object[] {id, issueComment.getRepository().getFullName()}); } - pull.check(issueComment.getComment()); - GhprbTrigger.getDscp().save(); } void onPullRequestHook(PullRequest pr) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 217d8d1c4..053c65be4 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -10,6 +10,9 @@ import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContextHolder; import org.apache.commons.io.IOUtils; +import org.kohsuke.github.GHEventPayload; +import org.kohsuke.github.GHIssueState; +import org.kohsuke.github.GitHub; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -84,15 +87,52 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { new Object[] { type }); return; } + - for (GhprbWebHook webHook : getWebHooks()) { - try { - webHook.handleWebHook(event, payload, body, signature); - } catch (Exception e) { - logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); + logger.log(Level.INFO, "Got payload event: {0}", event); + + try { + GitHub gh = GitHub.connectAnonymously(); + + if ("issue_comment".equals(event)) { + GHEventPayload.IssueComment issueComment = gh.parseEventPayload( + new StringReader(payload), + GHEventPayload.IssueComment.class); + GHIssueState state = issueComment.getIssue().getState(); + if (state == GHIssueState.CLOSED) { + logger.log(Level.INFO, "Skip comment on closed PR"); + return; + } + + + for (GhprbWebHook webHook : getWebHooks()) { + try { + webHook.handleComment(issueComment, body, signature); + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); + } + } + + + } else if ("pull_request".equals(event)) { + GHEventPayload.PullRequest pr = gh.parseEventPayload( + new StringReader(payload), + GHEventPayload.PullRequest.class); + + for (GhprbWebHook webHook : getWebHooks()) { + try { + webHook.handlePR(pr, body, signature); + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); + } + } + } else { + logger.log(Level.WARNING, "Request not known"); } + + } catch (IOException e1) { + e1.printStackTrace(); } - } private String extractRequestBody(StaplerRequest req) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java index 97830dba5..af1ee5b9b 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java @@ -1,7 +1,5 @@ package org.jenkinsci.plugins.ghprb; -import java.io.IOException; -import java.io.StringReader; import java.util.logging.Level; import java.util.logging.Logger; @@ -11,75 +9,50 @@ import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang.StringUtils; import org.kohsuke.github.GHEventPayload; -import org.kohsuke.github.GHIssueState; import org.kohsuke.github.GHRepository; -import org.kohsuke.github.GitHub; public class GhprbWebHook { private static final Logger logger = Logger.getLogger(GhprbWebHook.class.getName()); - + private final GhprbTrigger trigger; - + public GhprbWebHook(GhprbTrigger trigger) { this.trigger = trigger; } - - public void handleWebHook(String event, String payload, String body, String signature) { + public void handleComment(GHEventPayload.IssueComment issueComment, String body, String signature) { GhprbRepository repo = trigger.getRepository(); String repoName = repo.getName(); - logger.log(Level.INFO, "Got payload event: {0}", event); - try { - GitHub gh = trigger.getGitHub(); - - if ("issue_comment".equals(event)) { - GHEventPayload.IssueComment issueComment = gh.parseEventPayload( - new StringReader(payload), - GHEventPayload.IssueComment.class); - GHIssueState state = issueComment.getIssue().getState(); - if (state == GHIssueState.CLOSED) { - logger.log(Level.INFO, "Skip comment on closed PR"); - return; - } - - if (matchRepo(repo, issueComment.getRepository())) { - if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())){ - return; - } - - logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", - new Object[] { issueComment.getComment(), repoName } - ); - repo.onIssueCommentHook(issueComment); - } + if (matchRepo(repo, issueComment.getRepository())) { + if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())) { + return; + } - } else if ("pull_request".equals(event)) { - GHEventPayload.PullRequest pr = gh.parseEventPayload( - new StringReader(payload), - GHEventPayload.PullRequest.class); - if (matchRepo(repo, pr.getPullRequest().getRepository())) { - if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())){ - return; - } - - logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repoName, pr.getNumber() }); - repo.onPullRequestHook(pr); - } - - } else { - logger.log(Level.WARNING, "Request not known"); + logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", new Object[] { issueComment.getComment(), repoName }); + repo.onIssueCommentHook(issueComment); + } + } + + public void handlePR(GHEventPayload.PullRequest pr, String body, String signature) { + GhprbRepository repo = trigger.getRepository(); + String repoName = repo.getName(); + + if (matchRepo(repo, pr.getPullRequest().getRepository())) { + if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())) { + return; } - } catch (IOException ex) { - logger.log(Level.SEVERE, "Failed to parse github hook payload for " + trigger.getProject(), ex); + + logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repoName, pr.getNumber() }); + repo.onPullRequestHook(pr); } } - + public static boolean checkSignature(String body, String signature, String secret) { if (StringUtils.isEmpty(secret)) { return true; } - + if (signature != null && signature.startsWith("sha1=")) { String expected = signature.substring(5); String algorithm = "HmacSHA1"; @@ -89,28 +62,28 @@ public static boolean checkSignature(String body, String signature, String secre mac.init(keySpec); byte[] localSignatureBytes = mac.doFinal(body.getBytes("UTF-8")); String localSignature = Hex.encodeHexString(localSignatureBytes); - if (! localSignature.equals(expected)) { - logger.log(Level.SEVERE, "Local signature {0} does not match external signature {1}", - new Object[] {localSignature, expected}); + if (!localSignature.equals(expected)) { + logger.log(Level.SEVERE, "Local signature {0} does not match external signature {1}", new Object[] { localSignature, expected }); return false; } + + logger.log(Level.INFO, "Signatures checking OK"); + return true; } catch (Exception e) { logger.log(Level.SEVERE, "Couldn't match both signatures"); return false; } - } else { - logger.log(Level.SEVERE, "Request doesn't contain a signature. Check that github has a secret that should be attached to the hook"); - return false; } + + logger.log(Level.SEVERE, "Request doesn't contain a signature. Check that github has a secret that should be attached to the hook"); + return false; - logger.log(Level.INFO, "Signatures checking OK"); - return true; } - + private boolean matchRepo(GhprbRepository ghprbRepo, GHRepository ghRepo) { String jobRepoName = ghprbRepo.getName(); String hookRepoName = ghRepo.getFullName(); - logger.log(Level.FINE, "Comparing repository names: {0} to {1}, case is ignored", new Object[]{jobRepoName, hookRepoName}); + logger.log(Level.FINE, "Comparing repository names: {0} to {1}, case is ignored", new Object[] { jobRepoName, hookRepoName }); return jobRepoName.equalsIgnoreCase(hookRepoName); } From e87cc06d23a1be20d4f8cebdcdec863a4f489787 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 23 Sep 2015 10:59:00 -0600 Subject: [PATCH 057/175] Change comment to FINE level --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 053c65be4..2e4131fe9 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -89,7 +89,7 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { } - logger.log(Level.INFO, "Got payload event: {0}", event); + logger.log(Level.FINE, "Got payload event: {0}", event); try { GitHub gh = GitHub.connectAnonymously(); From 0ae773be5706e02b44b5bfd0ade8bbbd72c8bd62 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 23 Sep 2015 11:29:10 -0600 Subject: [PATCH 058/175] [maven-release-plugin] prepare release ghprb-1.28.4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d69742fd4..cd6810032 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29-SNAPSHOT + 1.28.4 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.28.4 From 2bc0ba6bf7029e826c55ccc3bafbae59f2e038c4 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 23 Sep 2015 11:29:13 -0600 Subject: [PATCH 059/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index cd6810032..d69742fd4 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.28.4 + 1.29-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.28.4 + HEAD From 0f5abf5d8ae52dcca4e405095710c037d1fc2362 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Wed, 23 Sep 2015 17:22:45 -0400 Subject: [PATCH 060/175] GhprbPullRequestMerge must NOT persist and serialize logger #192 fixes #192, connected to #192 --- .../java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 90ad74576..bacc53045 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -32,7 +32,7 @@ public class GhprbPullRequestMerge extends Recorder { - private PrintStream logger; + private transient PrintStream logger; private final Boolean onlyAdminsMerge; private final Boolean disallowOwnCode; From 67b92d252ecc3c155dc056d072fa199cd3787993 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Wed, 23 Sep 2015 18:08:24 -0400 Subject: [PATCH 061/175] [maven-release-plugin] prepare release ghprb-1.28.5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d69742fd4..f0f4e1403 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29-SNAPSHOT + 1.28.5 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.28.5 From 806fc21f526e101ff320318fc8b4dd7e3af8727d Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Wed, 23 Sep 2015 18:08:26 -0400 Subject: [PATCH 062/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f0f4e1403..d69742fd4 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.28.5 + 1.29-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.28.5 + HEAD From fdb2639f9985a335f6d06ea75dc33fc8ef63a781 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 24 Sep 2015 11:06:55 -0600 Subject: [PATCH 063/175] Save the trigger on start. This fixes the issue where fields are updated, but the changes don't get saved to the config because the job is never saved again manually. Fixes an issue with trigger regex conversion --- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 24 +++++++++++++++++++ .../GhprbTriggerBackwardsCompatible.java | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 46c849855..6f1b6b735 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -154,6 +154,27 @@ private void checkGitHubApiAuth() { public static DescriptorImpl getDscp() { return DESCRIPTOR; } + + /** + * Save any updates that may have been made inside the plugin that would affect the config.xml + */ + public void save() { + if (_project != null) { + String xmlConfig = ""; + try { + xmlConfig = _project.getConfigFile().asString(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to save load config file", e); + } + if (!xmlConfig.contains("" + configVersion)) { + try { + _project.save(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to save config updates", e); + } + } + } + } @Override public void start(AbstractProject project, boolean newInstance) { @@ -162,6 +183,8 @@ public void start(AbstractProject project, boolean newInstance) { this._project = project; this.project = project.getFullName(); + save(); + if (project.isDisabled()) { logger.log(Level.FINE, "Project is disabled, not starting trigger for job " + this.project); return; @@ -180,6 +203,7 @@ public void start(AbstractProject project, boolean newInstance) { logger.log(Level.INFO, "Starting the ghprb trigger for the {0} job; newInstance is {1}", new String[] { this.project, String.valueOf(newInstance) }); helper.init(); + } Ghprb createGhprb(AbstractProject project) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java index 3becaa477..fdd120340 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java @@ -50,7 +50,7 @@ protected void convertPropertiesToExtensions() { if (configVersion == null) { configVersion = 0; } - if (configVersion <= 2 && !StringUtils.isEmpty(triggerPhrase)) { + if (configVersion < 3 && !StringUtils.isEmpty(triggerPhrase)) { triggerPhrase = Pattern.quote(triggerPhrase); } From 159aa48428ad3f0c5bd8f2302b8703652fa32a40 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 24 Sep 2015 17:47:35 -0600 Subject: [PATCH 064/175] [maven-release-plugin] prepare release ghprb-1.28.6 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d69742fd4..d35f0e18f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29-SNAPSHOT + 1.28.6 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.28.6 From 5b2e8adbf8fa15e7f116f0a677feeeca12f5d252 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 24 Sep 2015 17:47:39 -0600 Subject: [PATCH 065/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d35f0e18f..d69742fd4 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.28.6 + 1.29-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.28.6 + HEAD From adfe7612b358c6c07f79a7c4799a1a9f0f122c04 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Fri, 25 Sep 2015 23:34:15 -0400 Subject: [PATCH 066/175] Revert "Reduce noise of webhook handling for many jobs" --- .../plugins/ghprb/GhprbRepository.java | 26 ++--- .../plugins/ghprb/GhprbRootAction.java | 52 ++-------- .../jenkinsci/plugins/ghprb/GhprbWebHook.java | 95 ++++++++++++------- 3 files changed, 75 insertions(+), 98 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 1421b341c..38239fd6b 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -253,34 +253,24 @@ public GHPullRequest getPullRequest(int id) throws IOException { return getGitHubRepo().getPullRequest(id); } - void onIssueCommentHook(IssueComment issueComment) { + void onIssueCommentHook(IssueComment issueComment) throws IOException { if (helper.isProjectDisabled()) { logger.log(Level.FINE, "Not checking comments since build is disabled"); return; } - int id = issueComment.getIssue().getNumber(); - try { - logger.log(Level.FINER, "Comment on issue #{0} from {1}: {2}", new Object[] { id, issueComment.getComment().getUser().getLogin(), issueComment.getComment().getBody() }); - } catch (IOException e) { - logger.log(Level.FINER, "Comment on issue #{0} unable to get user: {2}", new Object[] { id, issueComment.getComment().getBody() }); - } + logger.log(Level.FINER, "Comment on issue #{0} from {1}: {2}", new Object[] { id, issueComment.getComment().getUser(), issueComment.getComment().getBody() }); if (!"created".equals(issueComment.getAction())) { return; } - try { - GhprbPullRequest pull = pulls.get(id); - - if (pull == null) { - pull = new GhprbPullRequest(getGitHubRepo().getPullRequest(id), helper, this); - pulls.put(id, pull); - } - pull.check(issueComment.getComment()); - GhprbTrigger.getDscp().save(); - } catch (IOException e) { - logger.log(Level.WARNING, "Unable to get pull request #{0} from GitHub for repo {1}!!", new Object[] {id, issueComment.getRepository().getFullName()}); + GhprbPullRequest pull = pulls.get(id); + if (pull == null) { + pull = new GhprbPullRequest(getGitHubRepo().getPullRequest(id), helper, this); + pulls.put(id, pull); } + pull.check(issueComment.getComment()); + GhprbTrigger.getDscp().save(); } void onPullRequestHook(PullRequest pr) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 2e4131fe9..217d8d1c4 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -10,9 +10,6 @@ import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContextHolder; import org.apache.commons.io.IOUtils; -import org.kohsuke.github.GHEventPayload; -import org.kohsuke.github.GHIssueState; -import org.kohsuke.github.GitHub; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -87,52 +84,15 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { new Object[] { type }); return; } - - logger.log(Level.FINE, "Got payload event: {0}", event); - - try { - GitHub gh = GitHub.connectAnonymously(); - - if ("issue_comment".equals(event)) { - GHEventPayload.IssueComment issueComment = gh.parseEventPayload( - new StringReader(payload), - GHEventPayload.IssueComment.class); - GHIssueState state = issueComment.getIssue().getState(); - if (state == GHIssueState.CLOSED) { - logger.log(Level.INFO, "Skip comment on closed PR"); - return; - } - - - for (GhprbWebHook webHook : getWebHooks()) { - try { - webHook.handleComment(issueComment, body, signature); - } catch (Exception e) { - logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); - } - } - - - } else if ("pull_request".equals(event)) { - GHEventPayload.PullRequest pr = gh.parseEventPayload( - new StringReader(payload), - GHEventPayload.PullRequest.class); - - for (GhprbWebHook webHook : getWebHooks()) { - try { - webHook.handlePR(pr, body, signature); - } catch (Exception e) { - logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); - } - } - } else { - logger.log(Level.WARNING, "Request not known"); + for (GhprbWebHook webHook : getWebHooks()) { + try { + webHook.handleWebHook(event, payload, body, signature); + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); } - - } catch (IOException e1) { - e1.printStackTrace(); } + } private String extractRequestBody(StaplerRequest req) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java index af1ee5b9b..97830dba5 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java @@ -1,5 +1,7 @@ package org.jenkinsci.plugins.ghprb; +import java.io.IOException; +import java.io.StringReader; import java.util.logging.Level; import java.util.logging.Logger; @@ -9,50 +11,75 @@ import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang.StringUtils; import org.kohsuke.github.GHEventPayload; +import org.kohsuke.github.GHIssueState; import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GitHub; public class GhprbWebHook { private static final Logger logger = Logger.getLogger(GhprbWebHook.class.getName()); - + private final GhprbTrigger trigger; - + public GhprbWebHook(GhprbTrigger trigger) { this.trigger = trigger; } + + public void handleWebHook(String event, String payload, String body, String signature) { - public void handleComment(GHEventPayload.IssueComment issueComment, String body, String signature) { GhprbRepository repo = trigger.getRepository(); String repoName = repo.getName(); - if (matchRepo(repo, issueComment.getRepository())) { - if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())) { - return; - } - - logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", new Object[] { issueComment.getComment(), repoName }); - repo.onIssueCommentHook(issueComment); - } - } - - public void handlePR(GHEventPayload.PullRequest pr, String body, String signature) { - GhprbRepository repo = trigger.getRepository(); - String repoName = repo.getName(); + logger.log(Level.INFO, "Got payload event: {0}", event); + try { + GitHub gh = trigger.getGitHub(); + + if ("issue_comment".equals(event)) { + GHEventPayload.IssueComment issueComment = gh.parseEventPayload( + new StringReader(payload), + GHEventPayload.IssueComment.class); + GHIssueState state = issueComment.getIssue().getState(); + if (state == GHIssueState.CLOSED) { + logger.log(Level.INFO, "Skip comment on closed PR"); + return; + } + + if (matchRepo(repo, issueComment.getRepository())) { + if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())){ + return; + } + + logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", + new Object[] { issueComment.getComment(), repoName } + ); + repo.onIssueCommentHook(issueComment); + } - if (matchRepo(repo, pr.getPullRequest().getRepository())) { - if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())) { - return; + } else if ("pull_request".equals(event)) { + GHEventPayload.PullRequest pr = gh.parseEventPayload( + new StringReader(payload), + GHEventPayload.PullRequest.class); + if (matchRepo(repo, pr.getPullRequest().getRepository())) { + if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())){ + return; + } + + logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repoName, pr.getNumber() }); + repo.onPullRequestHook(pr); + } + + } else { + logger.log(Level.WARNING, "Request not known"); } - - logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repoName, pr.getNumber() }); - repo.onPullRequestHook(pr); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Failed to parse github hook payload for " + trigger.getProject(), ex); } } - + public static boolean checkSignature(String body, String signature, String secret) { if (StringUtils.isEmpty(secret)) { return true; } - + if (signature != null && signature.startsWith("sha1=")) { String expected = signature.substring(5); String algorithm = "HmacSHA1"; @@ -62,28 +89,28 @@ public static boolean checkSignature(String body, String signature, String secre mac.init(keySpec); byte[] localSignatureBytes = mac.doFinal(body.getBytes("UTF-8")); String localSignature = Hex.encodeHexString(localSignatureBytes); - if (!localSignature.equals(expected)) { - logger.log(Level.SEVERE, "Local signature {0} does not match external signature {1}", new Object[] { localSignature, expected }); + if (! localSignature.equals(expected)) { + logger.log(Level.SEVERE, "Local signature {0} does not match external signature {1}", + new Object[] {localSignature, expected}); return false; } - - logger.log(Level.INFO, "Signatures checking OK"); - return true; } catch (Exception e) { logger.log(Level.SEVERE, "Couldn't match both signatures"); return false; } + } else { + logger.log(Level.SEVERE, "Request doesn't contain a signature. Check that github has a secret that should be attached to the hook"); + return false; } - - logger.log(Level.SEVERE, "Request doesn't contain a signature. Check that github has a secret that should be attached to the hook"); - return false; + logger.log(Level.INFO, "Signatures checking OK"); + return true; } - + private boolean matchRepo(GhprbRepository ghprbRepo, GHRepository ghRepo) { String jobRepoName = ghprbRepo.getName(); String hookRepoName = ghRepo.getFullName(); - logger.log(Level.FINE, "Comparing repository names: {0} to {1}, case is ignored", new Object[] { jobRepoName, hookRepoName }); + logger.log(Level.FINE, "Comparing repository names: {0} to {1}, case is ignored", new Object[]{jobRepoName, hookRepoName}); return jobRepoName.equalsIgnoreCase(hookRepoName); } From f34aaa41b2044193f54aff9d434643728f8b0ac1 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 26 Sep 2015 00:26:20 -0600 Subject: [PATCH 067/175] Fix issues with authentication for hooks. This allows webhooks to be parsed at most twice. Responsibility is placed on GhprbRootAction to see that the event applies to the job --- .../plugins/ghprb/GhprbRootAction.java | 69 +++++++++++++-- .../jenkinsci/plugins/ghprb/GhprbWebHook.java | 88 ++++++------------- .../plugins/ghprb/GhprbRepositoryTest.java | 10 ++- .../plugins/ghprb/GhprbTestUtil.java | 5 ++ 4 files changed, 104 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 217d8d1c4..680634b6e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -10,6 +10,10 @@ import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContextHolder; import org.apache.commons.io.IOUtils; +import org.kohsuke.github.GHEventPayload.IssueComment; +import org.kohsuke.github.GHEventPayload.PullRequest; +import org.kohsuke.github.GHIssueState; +import org.kohsuke.github.GitHub; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -85,14 +89,67 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { return; } - for (GhprbWebHook webHook : getWebHooks()) { - try { - webHook.handleWebHook(event, payload, body, signature); - } catch (Exception e) { - logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); + logger.log(Level.FINE, "Got payload event: {0}", event); + + try { + GitHub gh = GitHub.connectAnonymously(); + + if ("issue_comment".equals(event)) { + IssueComment issueComment = getIssueComment(payload, gh); + GHIssueState state = issueComment.getIssue().getState(); + if (state == GHIssueState.CLOSED) { + logger.log(Level.INFO, "Skip comment on closed PR"); + return; + } + + String repoName = issueComment.getRepository().getFullName(); + + logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", new Object[] { issueComment.getComment(), repoName }); + + for (GhprbWebHook webHook : getWebHooks()) { + try { + if (webHook.matchRepo(repoName) && webHook.checkSignature(body, signature)) { + IssueComment authedComment = getIssueComment(payload, webHook.getGitHub()); + webHook.handleComment(authedComment); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); + } + } + + } else if ("pull_request".equals(event)) { + PullRequest pr = getPullRequest(payload, gh); + String repoName = pr.getRepository().getFullName(); + + logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repoName, pr.getNumber() }); + + for (GhprbWebHook webHook : getWebHooks()) { + try { + if (webHook.matchRepo(repoName) && webHook.checkSignature(body, signature)) { + PullRequest authedPr = getPullRequest(payload, webHook.getGitHub()); + webHook.handlePR(authedPr); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); + } + } + } else { + logger.log(Level.WARNING, "Request not known"); } + + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to connect to GitHub anonymously", e); } - + } + + private PullRequest getPullRequest(String payload, GitHub gh) throws IOException { + PullRequest pr = gh.parseEventPayload(new StringReader(payload), PullRequest.class); + return pr; + } + + private IssueComment getIssueComment(String payload, GitHub gh) throws IOException { + IssueComment issueComment = gh.parseEventPayload(new StringReader(payload), IssueComment.class); + return issueComment; } private String extractRequestBody(StaplerRequest req) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java index 97830dba5..e0f29fb57 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java @@ -1,7 +1,6 @@ package org.jenkinsci.plugins.ghprb; import java.io.IOException; -import java.io.StringReader; import java.util.logging.Level; import java.util.logging.Logger; @@ -10,9 +9,8 @@ import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang.StringUtils; -import org.kohsuke.github.GHEventPayload; -import org.kohsuke.github.GHIssueState; -import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GHEventPayload.IssueComment; +import org.kohsuke.github.GHEventPayload.PullRequest; import org.kohsuke.github.GitHub; public class GhprbWebHook { @@ -24,58 +22,39 @@ public GhprbWebHook(GhprbTrigger trigger) { this.trigger = trigger; } - public void handleWebHook(String event, String payload, String body, String signature) { + public GitHub getGitHub() throws IOException { + return trigger.getGitHub(); + } + public boolean matchRepo(String hookRepoName) { + GhprbRepository ghprbRepo = trigger.getRepository(); + String jobRepoName = ghprbRepo.getName(); + logger.log(Level.FINE, "Comparing repository names: {0} to {1}, case is ignored", new Object[] { jobRepoName, hookRepoName }); + return jobRepoName.equalsIgnoreCase(hookRepoName); + } + + public String getProjectName() { + return trigger.getActualProject().getFullName(); + } + + public void handleComment(IssueComment issueComment) throws IOException { GhprbRepository repo = trigger.getRepository(); - String repoName = repo.getName(); + + logger.log(Level.INFO, "Checking comment on PR #{0} for job {1}", new Object[] {issueComment.getIssue().getNumber(), getProjectName()}); - logger.log(Level.INFO, "Got payload event: {0}", event); - try { - GitHub gh = trigger.getGitHub(); - - if ("issue_comment".equals(event)) { - GHEventPayload.IssueComment issueComment = gh.parseEventPayload( - new StringReader(payload), - GHEventPayload.IssueComment.class); - GHIssueState state = issueComment.getIssue().getState(); - if (state == GHIssueState.CLOSED) { - logger.log(Level.INFO, "Skip comment on closed PR"); - return; - } - - if (matchRepo(repo, issueComment.getRepository())) { - if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())){ - return; - } + repo.onIssueCommentHook(issueComment); + } - logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", - new Object[] { issueComment.getComment(), repoName } - ); - repo.onIssueCommentHook(issueComment); - } + public void handlePR(PullRequest pr) { + GhprbRepository repo = trigger.getRepository(); - } else if ("pull_request".equals(event)) { - GHEventPayload.PullRequest pr = gh.parseEventPayload( - new StringReader(payload), - GHEventPayload.PullRequest.class); - if (matchRepo(repo, pr.getPullRequest().getRepository())) { - if (!checkSignature(body, signature, trigger.getGitHubApiAuth().getSecret())){ - return; - } + logger.log(Level.INFO, "Checking PR #{0} for job {1}", new Object[] {pr.getNumber(), getProjectName()}); - logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repoName, pr.getNumber() }); - repo.onPullRequestHook(pr); - } - - } else { - logger.log(Level.WARNING, "Request not known"); - } - } catch (IOException ex) { - logger.log(Level.SEVERE, "Failed to parse github hook payload for " + trigger.getProject(), ex); - } + repo.onPullRequestHook(pr); } - - public static boolean checkSignature(String body, String signature, String secret) { + + public boolean checkSignature(String body, String signature) { + String secret = trigger.getGitHubApiAuth().getSecret(); if (StringUtils.isEmpty(secret)) { return true; } @@ -106,16 +85,5 @@ public static boolean checkSignature(String body, String signature, String secre logger.log(Level.INFO, "Signatures checking OK"); return true; } - - private boolean matchRepo(GhprbRepository ghprbRepo, GHRepository ghRepo) { - String jobRepoName = ghprbRepo.getName(); - String hookRepoName = ghRepo.getFullName(); - logger.log(Level.FINE, "Comparing repository names: {0} to {1}, case is ignored", new Object[]{jobRepoName, hookRepoName}); - return jobRepoName.equalsIgnoreCase(hookRepoName); - } - - public String getProjectName() { - return trigger.getProject(); - } } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 2e4eb99c7..d0e6b064d 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -503,9 +503,15 @@ public void testSignature() throws IOException, InvalidKeyException, NoSuchAlgor String actualSignature = createSHA1Signature(actualSecret, body); String fakeSignature = createSHA1Signature("abc", body); + GhprbGitHubAuth ghAuth = Mockito.mock(GhprbGitHubAuth.class); + doReturn(ghAuth).when(trigger).getGitHubApiAuth(); + Assert.assertFalse(actualSignature.equals(fakeSignature)); - Assert.assertTrue(GhprbWebHook.checkSignature(body, actualSignature, actualSecret)); - Assert.assertFalse(GhprbWebHook.checkSignature(body, fakeSignature, actualSecret)); + + given(ghAuth.getSecret()).willReturn(actualSecret); + + Assert.assertTrue(trigger.getWebHook().checkSignature(body, actualSignature)); + Assert.assertFalse(trigger.getWebHook().checkSignature(body, fakeSignature)); } private String createSHA1Signature(String secret, String body) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException { diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java index c670fbeec..98e00bf91 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java @@ -346,6 +346,11 @@ public static GitSCM provideGitSCM() { null); } + + public static GhprbTrigger getTrigger() throws Exception { + return getTrigger(null); + } + public static GhprbTrigger getTrigger(Map values) throws Exception { setupReq(); if (values == null) { From f4f93158b8e69eca046d6039839e3d76d756fd9c Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Sat, 26 Sep 2015 04:40:13 -0400 Subject: [PATCH 068/175] Add debug statement to demonstrate anonymous GitHub root Fix ownCode issues now that the data does not come up with nulls --- .../plugins/ghprb/GhprbPullRequestMerge.java | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index bacc53045..1a683dda6 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -2,14 +2,18 @@ import java.io.IOException; import java.io.PrintStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.concurrent.ConcurrentMap; -import org.kohsuke.github.GHPullRequestCommitDetail.Commit; +import org.kohsuke.github.GHIssue; import org.kohsuke.github.GHPullRequest; import org.kohsuke.github.GHPullRequestCommitDetail; +import org.kohsuke.github.GHPullRequestCommitDetail.Commit; import org.kohsuke.github.GHRef; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHUser; +import org.kohsuke.github.GitHub; import org.kohsuke.github.GitUser; import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; @@ -20,10 +24,10 @@ import hudson.Extension; import hudson.FilePath; import hudson.Launcher; -import hudson.model.BuildListener; -import hudson.model.Result; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; +import hudson.model.BuildListener; +import hudson.model.Result; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; @@ -183,6 +187,17 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build if (intendToMerge && canMerge) { logger.println("Merging the pull request"); + try { + Field ghRootField = GHIssue.class.getDeclaredField("root"); + ghRootField.setAccessible(true); + Object ghRoot = ghRootField.get(pr); + Method anonMethod = GitHub.class.getMethod("isAnonymous"); + anonMethod.setAccessible(true); + Boolean isAnonymous = (Boolean) (anonMethod.invoke(ghRoot)); + logger.println("Merging PR[" + pr + "] is anonymous: " + isAnonymous); + } catch (Exception e) { + e.printStackTrace(logger); + } pr.merge(getMergeComment()); logger.println("Pull request successfully merged"); deleteBranch(build, launcher, listener); @@ -230,10 +245,11 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { String commentorLogin = commentor.getLogin(); GHUser prUser = pr.getUser(); - if (prUser.getLogin().equals(commentorLogin)) { - logger.println(commentorName + " (" + commentorLogin + ") has commits in PR[" + pr.getId() + "] that is to be merged"); - return true; - } + if (prUser.getLogin().equals(commentorLogin)) { + logger.println(commentorName + " (" + commentorLogin + ") has submitted the PR[" + pr.getNumber() + + "] that is to be merged"); + return true; + } for (GHPullRequestCommitDetail detail : pr.listCommits()) { Commit commit = detail.getCommit(); @@ -245,9 +261,11 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { isSame |= commentorName != null && commentorName.equals(committerName); isSame |= commentorEmail != null && commentorEmail.equals(committerEmail); - - logger.println(commentorName + " (" + commentorEmail + ") has commits in PR[" + pr.getId() + "] that is to be merged"); - return isSame; + if (isSame) { + logger.println(commentorName + " (" + commentorEmail + ") has commits in PR[" + pr.getNumber() + + "] that is to be merged"); + return isSame; + } } } catch (IOException e) { logger.println("Unable to get committer name"); From 4d4bcbb077b8f3d6ad9396fb35a176fc5e85d85c Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 26 Sep 2015 08:10:40 -0600 Subject: [PATCH 069/175] Don't use job context when looking up creds for GitHub connections. --- src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 64a134484..0ae949361 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -448,13 +448,8 @@ public static StandardCredentials lookupCredentials(Item context, String credent List credentials; - if (context == null) { - credentials = CredentialsProvider.lookupCredentials(StandardCredentials.class, Jenkins.getInstance(), ACL.SYSTEM, - URIRequirementBuilder.fromUri(uri).build()); - } else { - credentials = CredentialsProvider.lookupCredentials(StandardCredentials.class, context, ACL.SYSTEM, - URIRequirementBuilder.fromUri(uri).build()); - } + credentials = CredentialsProvider.lookupCredentials(StandardCredentials.class, (Item) null, ACL.SYSTEM, + URIRequirementBuilder.fromUri(uri).build()); logger.log(Level.FINE, "Found {0} credentials", new Object[]{credentials.size()}); From 1f6d7839d72232df6c3b656be3ec3b32bc164798 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Sat, 26 Sep 2015 13:04:15 -0400 Subject: [PATCH 070/175] Fix ownCode verification --- .../plugins/ghprb/GhprbPullRequestMerge.java | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index bacc53045..20bec7bfe 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -229,26 +229,30 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { String commentorEmail = commentor.getEmail(); String commentorLogin = commentor.getLogin(); - GHUser prUser = pr.getUser(); - if (prUser.getLogin().equals(commentorLogin)) { - logger.println(commentorName + " (" + commentorLogin + ") has commits in PR[" + pr.getId() + "] that is to be merged"); - return true; - } - - for (GHPullRequestCommitDetail detail : pr.listCommits()) { - Commit commit = detail.getCommit(); - GitUser committer = commit.getCommitter(); - String committerName = committer.getName(); - String committerEmail = committer.getEmail(); - - boolean isSame = false; - - isSame |= commentorName != null && commentorName.equals(committerName); - isSame |= commentorEmail != null && commentorEmail.equals(committerEmail); - - logger.println(commentorName + " (" + commentorEmail + ") has commits in PR[" + pr.getId() + "] that is to be merged"); - return isSame; - } + GHUser prUser = pr.getUser(); + if (prUser.getLogin().equals(commentorLogin)) { + logger.println(commentorName + " (" + commentorLogin + ") is attempting to commi own PR[" + + pr.getNumber() + "]"); + return true; + } + + for (GHPullRequestCommitDetail detail : pr.listCommits()) { + Commit commit = detail.getCommit(); + GitUser committer = commit.getCommitter(); + String committerName = committer.getName(); + String committerEmail = committer.getEmail(); + + boolean isSame = false; + + isSame |= commentorName != null && commentorName.equals(committerName); + isSame |= commentorEmail != null && commentorEmail.equals(committerEmail); + + if (isSame) { + logger.println(commentorName + " (" + commentorEmail + ") has commits in PR[" + pr.getNumber() + + "] that is to be merged"); + return isSame; + } + } } catch (IOException e) { logger.println("Unable to get committer name"); e.printStackTrace(logger); From 66acd9420f4428da0ebc188c0924e6cb242b3be1 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 23 Sep 2015 10:52:51 -0600 Subject: [PATCH 071/175] initial work to remove the concurrent map if possible --- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 6 +--- .../plugins/ghprb/GhprbPullRequestMerge.java | 10 +------ .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 30 +++++++++---------- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 35135860a..62b0c8740 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -22,7 +22,6 @@ import java.io.PrintStream; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -68,11 +67,8 @@ public void onStarted(AbstractBuild build, TaskListener listener) { GhprbTrigger trigger = Ghprb.extractTrigger(build); - ConcurrentMap pulls = trigger.getDescriptor().getPullRequests(build.getProject().getFullName()); - - GHPullRequest pr = pulls.get(c.getPullID()).getPullRequest(); - try { + GHPullRequest pr = trigger.getRepository().getPullRequest(c.getPullID()); int counter = 0; // If the PR is being resolved by GitHub then getMergeable will return null Boolean isMergeable = pr.getMergeable(); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 20bec7bfe..911d2ce87 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -109,15 +109,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build return true; } - ConcurrentMap pulls = trigger.getDescriptor().getPullRequests(project.getFullName()); - - pr = pulls.get(cause.getPullID()).getPullRequest(); - - if (pr == null) { - logger.println("Pull request is null for ID: " + cause.getPullID()); - logger.println("" + pulls.toString()); - return false; - } + pr = trigger.getRepository().getPullRequest(cause.getPullID()); if (helper == null) { helper = new Ghprb(project, trigger, pulls); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 6f1b6b735..f372b689a 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -733,21 +733,21 @@ public ListBoxModel doFillGitHubAuthIdItems(@QueryParameter("gitHubAuthId") Stri } - public ConcurrentMap getPullRequests(String projectName) { - ConcurrentMap ret; - if (jobs.containsKey(projectName)) { - Map map = jobs.get(projectName); - if (!(map instanceof ConcurrentMap)) { - map = new ConcurrentHashMap(map); - } - jobs.put(projectName, (ConcurrentMap) map); - ret = (ConcurrentMap) map; - } else { - ret = new ConcurrentHashMap(); - jobs.put(projectName, ret); - } - return ret; - } +// public ConcurrentMap getPullRequests(String projectName) { +// ConcurrentMap ret; +// if (jobs.containsKey(projectName)) { +// Map map = jobs.get(projectName); +// if (!(map instanceof ConcurrentMap)) { +// map = new ConcurrentHashMap(map); +// } +// jobs.put(projectName, (ConcurrentMap) map); +// ret = (ConcurrentMap) map; +// } else { +// ret = new ConcurrentHashMap(); +// jobs.put(projectName, ret); +// } +// return ret; +// } public List getWhiteListTargetBranches() { return whiteListTargetBranches; From 89582102514f3274c3ce5e8616a0b9ae121502c3 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 24 Sep 2015 09:52:03 -0600 Subject: [PATCH 072/175] Minimize the PullRequest object so the xml file isn't so huge --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 4 +- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 16 +- .../plugins/ghprb/GhprbPullRequest.java | 148 +++++++++--------- .../plugins/ghprb/GhprbPullRequestMerge.java | 5 +- .../plugins/ghprb/GhprbRepository.java | 18 ++- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 37 +++-- .../ghprb/GhprbPullRequestMergeTest.java | 12 +- .../plugins/ghprb/GhprbPullRequestTest.java | 22 ++- .../plugins/ghprb/GhprbRepositoryTest.java | 47 +++--- .../plugins/ghprb/GhprbTestUtil.java | 7 + 10 files changed, 182 insertions(+), 134 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 64a134484..f794a1589 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -62,7 +62,7 @@ public class Ghprb { private GhprbRepository repository; private GhprbBuilds builds; - public Ghprb(AbstractProject project, GhprbTrigger trigger, ConcurrentMap pulls) { + public Ghprb(AbstractProject project, GhprbTrigger trigger) { this.project = project; final GithubProjectProperty ghpp = project.getProperty(GithubProjectProperty.class); @@ -79,7 +79,7 @@ public Ghprb(AbstractProject project, GhprbTrigger trigger, ConcurrentMap< this.trigger = trigger; - this.repository = new GhprbRepository(user, repo, this, pulls); + this.repository = new GhprbRepository(user, repo, this); this.builds = new GhprbBuilds(trigger, repository); } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 62b0c8740..aaf8fc73b 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -40,8 +40,20 @@ public GhprbBuilds(GhprbTrigger trigger, GhprbRepository repo) { public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) { - GhprbCause cause = new GhprbCause(pr.getHead(), pr.getId(), pr.isMergeable(), pr.getTarget(), pr.getSource(), pr.getAuthorEmail(), pr.getTitle(), pr.getUrl(), triggerSender, commentBody, - pr.getCommitAuthor(), pr.getPullRequestAuthor(), pr.getDescription(), pr.getAuthorRepoGitUrl()); + GhprbCause cause = new GhprbCause(pr.getHead(), + pr.getId(), + pr.isMergeable(), + pr.getTarget(), + pr.getSource(), + pr.getAuthorEmail(), + pr.getTitle(), + pr.getUrl(), + triggerSender, + commentBody, + pr.getCommitAuthor(), + pr.getPullRequestAuthor(), + pr.getDescription(), + pr.getAuthorRepoGitUrl()); for (GhprbExtension ext : Ghprb.getJobExtensions(trigger, GhprbCommitStatus.class)) { if (ext instanceof GhprbCommitStatus) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index da06067a8..30b01838b 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -8,7 +8,6 @@ import org.kohsuke.github.GHIssueComment; import org.kohsuke.github.GHPullRequest; import org.kohsuke.github.GHPullRequestCommitDetail; -import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHUser; import org.kohsuke.github.GitUser; @@ -27,31 +26,35 @@ public class GhprbPullRequest { private static final Logger logger = Logger.getLogger(GhprbPullRequest.class.getName()); + + @Deprecated @SuppressWarnings("unused") private transient GHUser author; + @Deprecated @SuppressWarnings("unused") private transient String title; + @Deprecated @SuppressWarnings("unused") private transient String reponame; + @Deprecated @SuppressWarnings("unused") private transient String authorEmail; + @Deprecated @SuppressWarnings("unused") private transient URL url; + @Deprecated @SuppressWarnings("unused") private transient String description; private final int id; - private final GHUser author; - private final GHPullRequest pr; - private String title; - private Date updated; - private String head; - private String authorRepoGitUrl; - private boolean mergeable; - private String reponame; + + private Date updated; // Needed to track when the PR was updated private String target; private String source; - private String authorEmail; - private URL url; - private String description; + private String head; + + private boolean accepted = false; // Needed to see if the PR has been added to the accepted list - private GHUser triggerSender; - private GitUser commitAuthor; - private boolean shouldRun = false; - private boolean accepted = false; - private boolean triggered = false; + private transient String authorRepoGitUrl; // Can be refreshed as needed. + private transient Ghprb helper; // will be refreshed each time GhprbRepository.init() is called + private transient GhprbRepository repo; // will be refreshed each time GhprbRepository.init() is called + private transient GHPullRequest pr; // will be refreshed each time GhprbRepository.init() is called - private transient Ghprb helper; - private transient GhprbRepository repo; + private transient GHUser triggerSender; // Only needed for a single build + private transient GitUser commitAuthor; // Only needed for a single build + + private transient boolean shouldRun = false; // Declares if we should run the build this time. + private transient boolean triggered = false; // Only lets us know if the trigger phrase was used for this run + private transient boolean mergeable = false; // Only works as an easy way to pass the value around for the start of this build private String commentBody; @@ -63,26 +66,25 @@ public GhprbPullRequest(GHPullRequest pr, Ghprb helper, GhprbRepository repo) { e.printStackTrace(); updated = new Date(); } - GHCommitPointer commitPointer = pr.getHead(); - head = commitPointer.getSha(); - title = pr.getTitle(); - author = pr.getUser(); - GHRepository repository = commitPointer.getRepository(); - if (repository != null) { - authorRepoGitUrl = repository.gitHttpTransportUrl(); - } - reponame = repo.getName(); + GHCommitPointer prHead = pr.getHead(); + head = prHead.getSha(); + source = prHead.getRef(); target = pr.getBase().getRef(); - source = commitPointer.getRef(); - url = pr.getHtmlUrl(); + this.pr = pr; - obtainAuthorEmail(pr); this.helper = helper; this.repo = repo; - this.description = pr.getBody(); + + GHUser author = pr.getUser(); + String reponame = repo.getName(); + + + if (prHead != null && prHead.getRepository() != null) { + authorRepoGitUrl = prHead.getRepository().gitHttpTransportUrl(); + } - if (helper.isWhitelisted(author)) { + if (helper.isWhitelisted(getPullRequestAuthor())) { accepted = true; shouldRun = true; } else { @@ -91,15 +93,19 @@ public GhprbPullRequest(GHPullRequest pr, Ghprb helper, GhprbRepository repo) { } logger.log(Level.INFO, "Created Pull Request #{0} on {1} by {2} ({3}) updated at: {4} SHA: {5}", - new Object[] { id, reponame, author.getLogin(), authorEmail, updated, head } + new Object[] { id, reponame, author.getLogin(), getAuthorEmail(), updated, prHead.getRef() } ); } - public void init(Ghprb helper, GhprbRepository repo) { + public void init(Ghprb helper, GhprbRepository repo) throws IOException { this.helper = helper; this.repo = repo; - if (reponame == null) { - reponame = repo.getName(); // If this instance was created before v1.8, it can be null. + pr = repo.getPullRequest(id); + + GHCommitPointer prHead = pr.getHead(); + + if (prHead != null && prHead.getRepository() != null) { + authorRepoGitUrl = prHead.getRepository().gitHttpTransportUrl(); } } @@ -113,14 +119,8 @@ public void check(GHPullRequest pr) { logger.log(Level.FINE, "Project is disabled, ignoring pull request"); return; } - if (target == null) { - target = pr.getBase().getRef(); // If this instance was created before target was introduced (before v1.8), it can be null. - } - if (source == null) { - source = pr.getHead().getRef(); // If this instance was created before target was introduced (before v1.8), it can be null. - } - updatePR(pr, author); + updatePR(pr, pr.getUser()); checkSkipBuild(pr); tryBuild(pr); @@ -158,10 +158,11 @@ public void check(GHIssueComment comment) { tryBuild(pr); } - private void updatePR(GHPullRequest pr, GHUser author) { + private void updatePR(GHPullRequest pr, GHUser user) { + Date lastUpdateTime = updated; if (pr != null && isUpdated(pr)) { - logger.log(Level.INFO, "Pull request #{0} was updated on {1} at {2} by {3}", new Object[] { id, reponame, updated, author }); + logger.log(Level.INFO, "Pull request #{0} was updated on {1} at {2} by {3}", new Object[] { id, repo.getName(), updated, user }); // the author of the PR could have been whitelisted since its creation if (!accepted && helper.isWhitelisted(pr.getUser())) { @@ -169,16 +170,13 @@ private void updatePR(GHPullRequest pr, GHUser author) { accepted = true; } - // the title or description could have been updated since the original PR was opened - title = pr.getTitle(); - description = pr.getBody(); int commentsChecked = checkComments(pr, lastUpdateTime); - boolean newCommit = checkCommit(pr.getHead().getSha()); + boolean newCommit = checkCommit(pr.getHead()); if (!newCommit && commentsChecked == 0) { logger.log(Level.INFO, "Pull request #{0} was updated on repo {1} but there aren''t any new comments nor commits; " + "that may mean that commit status was updated.", - new Object[] { id, reponame } + new Object[] { id, repo.getName() } ); } } @@ -190,6 +188,8 @@ public boolean isWhiteListedTargetBranch() { // no branches in white list means we should test all return true; } + + String target = getTarget(); for (GhprbBranch b : branches) { if (b.matches(target)) { // the target branch is in the whitelist! @@ -235,12 +235,6 @@ private void tryBuild(GHPullRequest pr) { if (shouldRun) { logger.log(Level.FINEST, "Running the build"); - if (authorEmail == null) { - // If this instance was create before authorEmail was introduced (before v1.10), it can be null. - obtainAuthorEmail(pr); - logger.log(Level.FINEST, "Author email was not set, trying to set it to {0}", authorEmail); - } - if (pr != null) { logger.log(Level.FINEST, "PR is not null, checking if mergable"); checkMergeable(pr); @@ -270,12 +264,12 @@ private void build() { } // returns false if no new commit - private boolean checkCommit(String sha) { - if (head.equals(sha)) { + private boolean checkCommit(GHCommitPointer sha) { + if (head.equals(sha.getSha())) { return false; } - logger.log(Level.FINE, "New commit. Sha: {0} => {1}", new Object[] { head, sha }); - head = sha; + logger.log(Level.FINE, "New commit. Sha: {0} => {1}", new Object[] { head, sha.getSha() }); + head = sha.getSha(); if (accepted) { shouldRun = true; } @@ -285,6 +279,7 @@ private boolean checkCommit(String sha) { private void checkComment(GHIssueComment comment) throws IOException { GHUser sender = comment.getUser(); String body = comment.getBody(); + GHUser author = pr.getUser(); // Disabled until more advanced configs get set up // ignore comments from bot user, this fixes an issue where the bot would auto-whitelist @@ -353,7 +348,7 @@ private int checkComments(GHPullRequest pr, Date lastUpdatedTime) { return count; } - private void checkMergeable(GHPullRequest pr) { + public boolean checkMergeable(GHPullRequest pr) { try { int r = 5; Boolean isMergeable = pr.getMergeable(); @@ -368,17 +363,9 @@ private void checkMergeable(GHPullRequest pr) { } mergeable = isMergeable != null && isMergeable; } catch (IOException e) { - mergeable = false; logger.log(Level.SEVERE, "Couldn't obtain mergeable status.", e); } - } - - private void obtainAuthorEmail(GHPullRequest pr) { - try { - authorEmail = pr.getUser().getEmail(); - } catch (Exception e) { - logger.log(Level.WARNING, "Couldn't obtain author email.", e); - } + return mergeable; } @Override @@ -396,7 +383,7 @@ public int hashCode() { hash = 89 * hash + this.id; return hash; } - + public int getId() { return id; } @@ -422,11 +409,16 @@ public String getSource() { } public String getAuthorEmail() { - return authorEmail; + try { + return pr.getUser().getEmail(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to fetch author info for " + id); + } + return ""; } public String getTitle() { - return title; + return pr.getTitle(); } /** @@ -435,15 +427,15 @@ public String getTitle() { * @return the Github Pull Request URL */ public URL getUrl() { - return url; + return pr.getHtmlUrl(); } - + public GitUser getCommitAuthor() { return commitAuthor; } public GHUser getPullRequestAuthor() { - return author; + return pr.getUser(); } public GHPullRequest getPullRequest() { @@ -451,6 +443,6 @@ public GHPullRequest getPullRequest() { } public String getDescription() { - return description; + return pr.getBody(); } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 911d2ce87..12d73a9a6 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -2,7 +2,6 @@ import java.io.IOException; import java.io.PrintStream; -import java.util.concurrent.ConcurrentMap; import org.kohsuke.github.GHPullRequestCommitDetail.Commit; import org.kohsuke.github.GHPullRequest; @@ -112,7 +111,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build pr = trigger.getRepository().getPullRequest(cause.getPullID()); if (helper == null) { - helper = new Ghprb(project, trigger, pulls); + helper = new Ghprb(project, trigger); helper.init(); } @@ -260,7 +259,7 @@ public String getDisplayName() { } @Override - public boolean isApplicable(Class jobType) { + public boolean isApplicable(@SuppressWarnings("rawtypes") Class jobType) { return true; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 38239fd6b..6bab427bb 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -32,21 +32,16 @@ public class GhprbRepository { private static final EnumSet HOOK_EVENTS = EnumSet.of(GHEvent.ISSUE_COMMENT, GHEvent.PULL_REQUEST); private final String reponame; - private final ConcurrentMap pulls; private GHRepository ghRepository; private Ghprb helper; - public GhprbRepository(String user, String repository, Ghprb helper, ConcurrentMap pulls) { + public GhprbRepository(String user, String repository, Ghprb helper) { this.reponame = user + "/" + repository; this.helper = helper; - this.pulls = pulls; } public void init() { - for (GhprbPullRequest pull : pulls.values()) { - pull.init(helper, this); - } // make the initial check call to populate our data structures initGhRepository(); } @@ -101,6 +96,9 @@ public void check() { logger.log(Level.SEVERE, "Could not retrieve open pull requests.", ex); return; } + + ConcurrentMap pulls = helper.getTrigger().getPulls(); + Set closedPulls = new HashSet(pulls.keySet()); for (GHPullRequest pr : openPulls) { @@ -115,6 +113,7 @@ public void check() { check(pr); closedPulls.remove(pr.getNumber()); } + // remove closed pulls so we don't check them again for (Integer id : closedPulls) { @@ -123,6 +122,8 @@ public void check() { } private void check(GHPullRequest pr) { + ConcurrentMap pulls = helper.getTrigger().getPulls(); + final Integer id = pr.getNumber(); GhprbPullRequest pull; if (pulls.containsKey(id)) { @@ -264,6 +265,8 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { return; } + ConcurrentMap pulls = helper.getTrigger().getPulls(); + GhprbPullRequest pull = pulls.get(id); if (pull == null) { pull = new GhprbPullRequest(getGitHubRepo().getPullRequest(id), helper, this); @@ -274,6 +277,9 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { } void onPullRequestHook(PullRequest pr) { + + ConcurrentMap pulls = helper.getTrigger().getPulls(); + if ("closed".equals(pr.getAction())) { pulls.remove(pr.getNumber()); } else if (helper.isProjectDisabled()) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index f372b689a..277c366b5 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -207,7 +207,11 @@ public void start(AbstractProject project, boolean newInstance) { } Ghprb createGhprb(AbstractProject project) { - return new Ghprb(project, this, getDescriptor().getPullRequests(project.getFullName())); + return new Ghprb(project, this); + } + + public ConcurrentMap getPulls() { + return getDescriptor().getPullRequests(_project.getFullName()); } @Override @@ -733,21 +737,21 @@ public ListBoxModel doFillGitHubAuthIdItems(@QueryParameter("gitHubAuthId") Stri } -// public ConcurrentMap getPullRequests(String projectName) { -// ConcurrentMap ret; -// if (jobs.containsKey(projectName)) { -// Map map = jobs.get(projectName); -// if (!(map instanceof ConcurrentMap)) { -// map = new ConcurrentHashMap(map); -// } -// jobs.put(projectName, (ConcurrentMap) map); -// ret = (ConcurrentMap) map; -// } else { -// ret = new ConcurrentHashMap(); -// jobs.put(projectName, ret); -// } -// return ret; -// } + public ConcurrentMap getPullRequests(String projectName) { + ConcurrentMap ret; + if (jobs.containsKey(projectName)) { + Map map = jobs.get(projectName); + if (!(map instanceof ConcurrentMap)) { + map = new ConcurrentHashMap(map); + } + jobs.put(projectName, (ConcurrentMap) map); + ret = (ConcurrentMap) map; + } else { + ret = new ConcurrentHashMap(); + jobs.put(projectName, ret); + } + return ret; + } public List getWhiteListTargetBranches() { return whiteListTargetBranches; @@ -846,4 +850,5 @@ private void addIfMissing(GhprbExtension ext) { } + } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 3f1961d75..67a27ea48 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -26,6 +26,7 @@ import org.kohsuke.github.GHPullRequest; import org.kohsuke.github.GHPullRequestCommitDetail; import org.kohsuke.github.GHPullRequestCommitDetail.Commit; +import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHUser; import org.kohsuke.github.GitUser; import org.kohsuke.github.PagedIterable; @@ -73,6 +74,8 @@ public class GhprbPullRequestMergeTest { private Ghprb helper; @Mock private GhprbRepository repo; + @Mock + private GHRepository ghRepo; @Mock private StreamBuildListener listener; @@ -109,10 +112,16 @@ public void beforeTest() throws Exception { GhprbTrigger trigger = GhprbTestUtil.getTrigger(triggerValues); ConcurrentMap pulls = new ConcurrentHashMap(1); + pulls.put(pullId, pullRequest); Map> jobs = new HashMap>(1); jobs.put("project", pulls); + Mockito.doReturn(pulls).when(trigger).getPulls(); + Mockito.doReturn(repo).when(trigger).getRepository(); + Mockito.doReturn(pr).when(repo).getPullRequest(pullId); + + GithubProjectProperty projectProperty = new GithubProjectProperty("https://github.com/jenkinsci/ghprb-plugin"); DescriptorImpl descriptor = trigger.getDescriptor(); @@ -150,7 +159,8 @@ public void beforeTest() throws Exception { jobsField.setAccessible(true); jobsField.set(descriptor, jobs); - helper = spy(new Ghprb(project, trigger, pulls)); + helper = spy(new Ghprb(project, trigger)); + given(trigger.getPulls()).willReturn(pulls); trigger.setHelper(helper); given(helper.getRepository()).willReturn(repo); given(helper.isBotUser(any(GHUser.class))).willReturn(false); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java index 2914aa549..b8812b472 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java @@ -1,5 +1,6 @@ package org.jenkinsci.plugins.ghprb; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.kohsuke.github.GHCommitPointer; @@ -7,6 +8,7 @@ import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHUser; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import java.io.IOException; @@ -34,6 +36,16 @@ public class GhprbPullRequestTest { private Ghprb helper; @Mock private GhprbRepository repo; + @Mock + private GHCommitPointer head; + @Mock + private GhprbRepository ghprbRepository; + + @Before + public void setup() throws IOException { + given(ghprbRepository.getPullRequest(10)).willReturn(pr); + given(pr.getHead()).willReturn(head); + } @Test public void testConstructorWhenAuthorIsWhitelisted() throws IOException { @@ -41,6 +53,7 @@ public void testConstructorWhenAuthorIsWhitelisted() throws IOException { GHUser ghUser = mock(GHUser.class); GHCommitPointer head = mock(GHCommitPointer.class); GHCommitPointer base = mock(GHCommitPointer.class); + given(head.getSha()).willReturn("some sha"); given(base.getRef()).willReturn("some ref"); @@ -96,15 +109,15 @@ public void testInitRepoNameNull() throws IOException { // Mocks for Ghprb given(helper.isWhitelisted(ghUser)).willReturn(true); - GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); - GhprbRepository ghprbRepository = mock(GhprbRepository.class); + GhprbPullRequest ghprbPullRequest = Mockito.spy(new GhprbPullRequest(pr, helper, repo)); given(ghprbRepository.getName()).willReturn("name"); // WHEN ghprbPullRequest.init(helper, ghprbRepository); // THEN - verify(ghprbRepository, times(1)).getName(); + verify(ghprbRepository, times(1)).getPullRequest(10); + verify(pr, times(2)).getHead(); } @@ -134,7 +147,6 @@ public void testInitRepoNameNotNull() throws IOException { given(helper.isWhitelisted(ghUser)).willReturn(true); GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); - GhprbRepository ghprbRepository = mock(GhprbRepository.class); given(ghprbRepository.getName()).willReturn("name"); // WHEN @@ -170,7 +182,6 @@ public void authorRepoGitUrlShouldBeNullWhenNoRepository() throws Exception { given(helper.isWhitelisted(ghUser)).willReturn(true); GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); - GhprbRepository ghprbRepository = mock(GhprbRepository.class); given(ghprbRepository.getName()).willReturn("name"); // WHEN @@ -210,7 +221,6 @@ public void authorRepoGitUrlShouldBeSetWhenRepository() throws Exception { given(helper.isWhitelisted(ghUser)).willReturn(true); GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); - GhprbRepository ghprbRepository = mock(GhprbRepository.class); given(ghprbRepository.getName()).willReturn("name"); // WHEN diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index d0e6b064d..9fead02b3 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -107,6 +107,7 @@ public void setUp() throws Exception { // Mock github API given(helper.getGitHub()).willReturn(gitHub); + given(helper.getTrigger()).willReturn(trigger); given(gitHub.get()).willReturn(gt); given(gt.getRepository(anyString())).willReturn(ghRepository); @@ -178,16 +179,17 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { verifyNoMoreInteractions(ghRepository); /** GH PR verifications */ - verify(ghPullRequest, times(3)).getHead(); - verify(ghPullRequest, times(1)).getBase(); + verify(ghPullRequest, times(2)).getHead(); verify(ghPullRequest, times(2)).getNumber(); verify(ghPullRequest, times(1)).getUpdatedAt(); + verify(ghPullRequest, times(1)).getUser(); verifyNoMoreInteractions(ghPullRequest); verify(helper).ifOnlyTriggerPhrase(); verify(helper).getWhiteListTargetBranches(); verify(helper, times(3)).isProjectDisabled(); verify(helper).checkSkipBuild(eq(ghPullRequest)); + verify(helper, times(2)).getTrigger(); verifyNoMoreInteractions(helper); verifyNoMoreInteractions(gt); @@ -236,10 +238,10 @@ public void testCheckMethodWithNewPR() throws IOException { verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(1)).getTitle(); - verify(ghPullRequest, times(2)).getUser(); + verify(ghPullRequest, times(7)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(7)).getHead(); - verify(ghPullRequest, times(3)).getBase(); + verify(ghPullRequest, times(5)).getHead(); + verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(3)).getUpdatedAt(); verify(ghPullRequest, times(1)).getHtmlUrl(); @@ -253,9 +255,10 @@ public void testCheckMethodWithNewPR() throws IOException { verify(helper, times(2)).getWhiteListTargetBranches(); verify(helper, times(5)).isProjectDisabled(); verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); + verify(helper, times(3)).getTrigger(); verifyNoMoreInteractions(helper); - verify(ghUser, times(1)).getEmail(); // Call to Github API + verify(ghUser, times(2)).getEmail(); // Call to Github API verify(ghUser, times(1)).getLogin(); verifyNoMoreInteractions(ghUser); } @@ -312,24 +315,25 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(ghRepository, times(1)).createCommitStatus(eq("head sha"), eq(PENDING), eq(""), eq(msg), eq("default")); // Call to Github API verifyNoMoreInteractions(ghRepository); - verify(ghPullRequest, times(2)).getTitle(); - verify(ghPullRequest, times(2)).getUser(); + verify(ghPullRequest, times(1)).getTitle(); + verify(ghPullRequest, times(8)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(7)).getHead(); - verify(ghPullRequest, times(3)).getBase(); + verify(ghPullRequest, times(5)).getHead(); + verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(1)).getHtmlUrl(); verify(ghPullRequest, times(3)).getUpdatedAt(); verify(ghPullRequest, times(1)).getComments(); verify(ghPullRequest, times(1)).listCommits(); - verify(ghPullRequest, times(2)).getBody(); + verify(ghPullRequest, times(1)).getBody(); verifyNoMoreInteractions(ghPullRequest); verify(helper, times(1)).isWhitelisted(eq(ghUser)); // Call to Github API verify(helper, times(2)).ifOnlyTriggerPhrase(); verify(helper, times(1)).getBuilds(); verify(helper, times(2)).getWhiteListTargetBranches(); + verify(helper, times(4)).getTrigger(); // verify(helper).isBotUser(eq(ghUser)); verify(helper).isWhitelistPhrase(eq("comment body")); @@ -340,7 +344,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); - verify(ghUser, times(1)).getEmail(); // Call to Github API + verify(ghUser, times(2)).getEmail(); // Call to Github API verify(ghUser, times(1)).getLogin(); verifyNoMoreInteractions(ghUser); } @@ -398,13 +402,13 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(2)).getTitle(); - verify(ghPullRequest, times(2)).getUser(); + verify(ghPullRequest, times(10)).getUser(); verify(ghPullRequest, times(2)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(7)).getHead(); - verify(ghPullRequest, times(3)).getBase(); + verify(ghPullRequest, times(5)).getHead(); + verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(3)).getUpdatedAt(); - verify(ghPullRequest, times(1)).getHtmlUrl(); + verify(ghPullRequest, times(2)).getHtmlUrl(); verify(ghPullRequest, times(1)).getComments(); verify(ghPullRequest, times(2)).listCommits(); @@ -423,9 +427,10 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(helper).isAdmin(eq(ghUser)); verify(helper, times(6)).isProjectDisabled(); verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); + verify(helper, times(4)).getTrigger(); verifyNoMoreInteractions(helper); - verify(ghUser, times(1)).getEmail(); // Call to Github API + verify(ghUser, times(3)).getEmail(); // Call to Github API verify(ghUser, times(1)).getLogin(); verifyNoMoreInteractions(ghUser); @@ -475,8 +480,8 @@ public void testCheckMethodWithNoPR() throws IOException { verifyNoMoreInteractions(gt); verify(ghRepository, times(1)).getPullRequests(OPEN); // Call to Github API - verifyNoMoreInteractions(ghRepository); - verifyZeroInteractions(helper); + verify(helper, times(1)).getTrigger(); + verifyNoMoreInteractions(helper, ghRepository); } @Test @@ -540,8 +545,10 @@ private void initGHPRWithTestData() throws IOException { given(head.getSha()).willReturn("head sha"); pulls = new ConcurrentHashMap(); - ghprbRepository = new GhprbRepository(TEST_USER_NAME, TEST_REPO_NAME, helper, pulls); + ghprbRepository = new GhprbRepository(TEST_USER_NAME, TEST_REPO_NAME, helper); ghprbPullRequest = new GhprbPullRequest(ghPullRequest, helper, ghprbRepository); + + given(trigger.getPulls()).willReturn(pulls); // Reset mocks not to mix init data invocations with tests reset(ghPullRequest, ghUser, helper, head, base); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java index 98e00bf91..0e541af32 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java @@ -21,6 +21,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.joda.time.DateTime; import org.kohsuke.github.GHCommitPointer; @@ -38,6 +40,7 @@ import net.sf.json.JSONObject; import static org.mockito.Matchers.any; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; public class GhprbTestUtil { @@ -377,6 +380,10 @@ public static GhprbTrigger getTrigger(Map values) throws Excepti GhprbTrigger trigger = spy(req.bindJSON(GhprbTrigger.class, defaults)); + + ConcurrentMap pulls = new ConcurrentHashMap(1); + Mockito.doReturn(pulls).when(trigger).getPulls(); + return trigger; } From 0ad0d9bea6b253388994cbf6487c00b197f38b46 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 24 Sep 2015 12:02:35 -0600 Subject: [PATCH 073/175] Fix formatting --- .../java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 30b01838b..73d42e406 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -383,7 +383,7 @@ public int hashCode() { hash = 89 * hash + this.id; return hash; } - + public int getId() { return id; } @@ -429,7 +429,7 @@ public String getTitle() { public URL getUrl() { return pr.getHtmlUrl(); } - + public GitUser getCommitAuthor() { return commitAuthor; } From a5713e36bc09708b144bcebd05296ed00612c64a Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Sat, 26 Sep 2015 16:22:35 -0400 Subject: [PATCH 074/175] Helper being transient the PRs MUST be reinitialized with it --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 1 - .../plugins/ghprb/GhprbRepository.java | 25 ++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index f794a1589..8e3d5aa8e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -42,7 +42,6 @@ import java.net.URI; import java.util.*; -import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 6bab427bb..46185fb65 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -110,7 +110,12 @@ public void check() { return; } } - check(pr); + try { + check(pr); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Could not retrieve pr " + pr.getNumber(), ex); + return; + } closedPulls.remove(pr.getNumber()); } @@ -121,13 +126,14 @@ public void check() { } } - private void check(GHPullRequest pr) { + private void check(GHPullRequest pr) throws IOException { ConcurrentMap pulls = helper.getTrigger().getPulls(); - + final Integer id = pr.getNumber(); GhprbPullRequest pull; if (pulls.containsKey(id)) { pull = pulls.get(id); + pull.init(helper, this); } else { pulls.putIfAbsent(id, new GhprbPullRequest(pr, helper, this)); pull = pulls.get(id); @@ -260,7 +266,8 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { return; } int id = issueComment.getIssue().getNumber(); - logger.log(Level.FINER, "Comment on issue #{0} from {1}: {2}", new Object[] { id, issueComment.getComment().getUser(), issueComment.getComment().getBody() }); + logger.log(Level.FINER, "Comment on issue #{0} from {1}: {2}", + new Object[] { id, issueComment.getComment().getUser(), issueComment.getComment().getBody() }); if (!"created".equals(issueComment.getAction())) { return; } @@ -271,15 +278,17 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { if (pull == null) { pull = new GhprbPullRequest(getGitHubRepo().getPullRequest(id), helper, this); pulls.put(id, pull); + } else { + pull.init(helper, this); } pull.check(issueComment.getComment()); GhprbTrigger.getDscp().save(); } - void onPullRequestHook(PullRequest pr) { + void onPullRequestHook(PullRequest pr) throws IOException { ConcurrentMap pulls = helper.getTrigger().getPulls(); - + if ("closed".equals(pr.getAction())) { pulls.remove(pr.getNumber()); } else if (helper.isProjectDisabled()) { @@ -289,6 +298,8 @@ void onPullRequestHook(PullRequest pr) { if (pull == null) { pulls.putIfAbsent(pr.getNumber(), new GhprbPullRequest(pr.getPullRequest(), helper, this)); pull = pulls.get(pr.getNumber()); + } else { + pull.init(helper, this); } pull.check(pr.getPullRequest()); } else if ("synchronize".equals(pr.getAction())) { @@ -296,6 +307,8 @@ void onPullRequestHook(PullRequest pr) { if (pull == null) { pulls.putIfAbsent(pr.getNumber(), new GhprbPullRequest(pr.getPullRequest(), helper, this)); pull = pulls.get(pr.getNumber()); + } else { + pull.init(helper, this); } if (pull == null) { logger.log(Level.SEVERE, "Pull Request #{0} doesn''t exist", pr.getNumber()); From 5bf4efcb3106d9b8865e4afc4ed0a9b9ac04a655 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Sat, 26 Sep 2015 17:05:16 -0400 Subject: [PATCH 075/175] Final cleanup --- .../plugins/ghprb/GhprbPullRequestMerge.java | 50 +++++++++---------- .../jenkinsci/plugins/ghprb/GhprbWebHook.java | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 12d73a9a6..b18f6f869 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -219,31 +219,31 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { String commentorName = commentor.getName(); String commentorEmail = commentor.getEmail(); String commentorLogin = commentor.getLogin(); - - GHUser prUser = pr.getUser(); - if (prUser.getLogin().equals(commentorLogin)) { - logger.println(commentorName + " (" + commentorLogin + ") is attempting to commi own PR[" - + pr.getNumber() + "]"); - return true; - } - - for (GHPullRequestCommitDetail detail : pr.listCommits()) { - Commit commit = detail.getCommit(); - GitUser committer = commit.getCommitter(); - String committerName = committer.getName(); - String committerEmail = committer.getEmail(); - - boolean isSame = false; - - isSame |= commentorName != null && commentorName.equals(committerName); - isSame |= commentorEmail != null && commentorEmail.equals(committerEmail); - - if (isSame) { - logger.println(commentorName + " (" + commentorEmail + ") has commits in PR[" + pr.getNumber() - + "] that is to be merged"); - return isSame; - } - } + + GHUser prUser = pr.getUser(); + if (prUser.getLogin().equals(commentorLogin)) { + logger.println(commentorName + " (" + commentorLogin + ") is attempting to commi own PR[" + + pr.getNumber() + "]"); + return true; + } + + for (GHPullRequestCommitDetail detail : pr.listCommits()) { + Commit commit = detail.getCommit(); + GitUser committer = commit.getCommitter(); + String committerName = committer.getName(); + String committerEmail = committer.getEmail(); + + boolean isSame = false; + + isSame |= commentorName != null && commentorName.equals(committerName); + isSame |= commentorEmail != null && commentorEmail.equals(committerEmail); + + if (isSame) { + logger.println(commentorName + " (" + commentorEmail + ") has commits in PR[" + pr.getNumber() + + "] that is to be merged"); + return isSame; + } + } } catch (IOException e) { logger.println("Unable to get committer name"); e.printStackTrace(logger); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java index e0f29fb57..246b815b2 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java @@ -45,7 +45,7 @@ public void handleComment(IssueComment issueComment) throws IOException { repo.onIssueCommentHook(issueComment); } - public void handlePR(PullRequest pr) { + public void handlePR(PullRequest pr) throws IOException { GhprbRepository repo = trigger.getRepository(); logger.log(Level.INFO, "Checking PR #{0} for job {1}", new Object[] {pr.getNumber(), getProjectName()}); From ce2a16498b8b25673d5684f58f8d2c950620bc50 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Sat, 26 Sep 2015 18:53:17 -0400 Subject: [PATCH 076/175] Fix test errors, pending - fix tests not passing --- .../plugins/ghprb/GhprbRepositoryTest.java | 18 ++++++++++++++---- .../plugins/ghprb/GhprbRootActionTest.java | 4 ++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 9fead02b3..adb27a94c 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -134,6 +134,7 @@ public void testCheckMethodWhenUsingGitHubEnterprise() throws IOException { given(gt.getRateLimit()).willThrow(new FileNotFoundException()); List ghPullRequests = createListWithMockPR(); given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(ghPullRequests); + given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); mockHeadAndBase(); mockCommitList(); @@ -157,6 +158,7 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { // GIVEN List ghPullRequests = createListWithMockPR(); given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(ghPullRequests); + given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); mockHeadAndBase(); mockCommitList(); @@ -216,7 +218,9 @@ public void testCheckMethodWithNewPR() throws IOException { given(ghPullRequest.getUser()).willReturn(ghUser); given(ghPullRequest.getHtmlUrl()).willReturn(new URL("https://github.com/org/repo/pull/100")); given(ghPullRequest.getApiURL()).willReturn(new URL("https://github.com/org/repo/pull/100")); - + given(ghPullRequest.getId()).willReturn(100); + given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); + given(ghUser.getEmail()).willReturn("email"); given(helper.ifOnlyTriggerPhrase()).willReturn(false); @@ -227,7 +231,6 @@ public void testCheckMethodWithNewPR() throws IOException { ghprbRepository.check(); // THEN - verifyGetGithub(1); verifyNoMoreInteractions(gt); @@ -284,6 +287,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(ghPullRequests); + given(ghPullRequest.getUpdatedAt()).willReturn(now).willReturn(now).willReturn(tomorrow); given(ghPullRequest.getNumber()).willReturn(100); given(ghPullRequest.getMergeable()).willReturn(true); @@ -291,7 +295,9 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException given(ghPullRequest.getUser()).willReturn(ghUser); given(ghPullRequest.getHtmlUrl()).willReturn(new URL("https://github.com/org/repo/pull/100")); given(ghPullRequest.getApiURL()).willReturn(new URL("https://github.com/org/repo/pull/100")); - + given(ghPullRequest.getId()).willReturn(100); + given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); + given(ghUser.getEmail()).willReturn("email"); given(ghUser.getLogin()).willReturn("login"); @@ -367,6 +373,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException GhprbBuilds builds = mockBuilds(); given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(ghPullRequests); + given(ghPullRequest.getUpdatedAt()).willReturn(now).willReturn(now).willReturn(tomorrow); given(ghPullRequest.getNumber()).willReturn(100); given(ghPullRequest.getMergeable()).willReturn(true); @@ -374,7 +381,9 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException given(ghPullRequest.getUser()).willReturn(ghUser); given(ghPullRequest.getHtmlUrl()).willReturn(new URL("https://github.com/org/repo/pull/100")); given(ghPullRequest.getApiURL()).willReturn(new URL("https://github.com/org/repo/pull/100")); - + given(ghPullRequest.getId()).willReturn(100); + given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); + given(ghUser.getEmail()).willReturn("email"); given(ghUser.getLogin()).willReturn("login"); @@ -470,6 +479,7 @@ public void testCheckMethodWithNoPR() throws IOException { // GIVEN List ghPullRequests = new ArrayList(); given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(ghPullRequests); + given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); // WHEN ghprbRepository.check(); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java index 0b7d64484..71bd18f88 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java @@ -97,7 +97,9 @@ public void testUrlEncoded() throws Exception { given(commitPointer.getSha()).willReturn("sha1"); GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); + given(ghPullRequest.getId()).willReturn(1); given(ghPullRequest.getNumber()).willReturn(1); + given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); Ghprb ghprb = spy(trigger.createGhprb(project)); doReturn(ghprbGitHub).when(ghprb).getGitHub(); trigger.start(project, true); @@ -137,7 +139,9 @@ public void disabledJobsDontBuild() throws Exception { given(commitPointer.getSha()).willReturn("sha1"); GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); + given(ghPullRequest.getId()).willReturn(1); given(ghPullRequest.getNumber()).willReturn(1); + given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); Ghprb ghprb = spy(trigger.createGhprb(project)); doReturn(ghprbGitHub).when(ghprb).getGitHub(); trigger.start(project, true); From 939c0b6f6dfed1a1e93d390fdf44dd46745fd23e Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 26 Sep 2015 22:16:23 -0600 Subject: [PATCH 077/175] Missed uploading fixed tests --- .../java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index adb27a94c..0d3eed1f2 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -185,6 +185,7 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { verify(ghPullRequest, times(2)).getNumber(); verify(ghPullRequest, times(1)).getUpdatedAt(); verify(ghPullRequest, times(1)).getUser(); + verify(ghPullRequest, times(1)).getId(); verifyNoMoreInteractions(ghPullRequest); verify(helper).ifOnlyTriggerPhrase(); @@ -250,6 +251,7 @@ public void testCheckMethodWithNewPR() throws IOException { verify(ghPullRequest, times(1)).getHtmlUrl(); verify(ghPullRequest, times(1)).listCommits(); verify(ghPullRequest, times(1)).getBody(); + verify(ghPullRequest, times(1)).getId(); verifyNoMoreInteractions(ghPullRequest); verify(helper, times(1)).isWhitelisted(eq(ghUser)); // Call to Github API @@ -333,6 +335,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(ghPullRequest, times(1)).getComments(); verify(ghPullRequest, times(1)).listCommits(); verify(ghPullRequest, times(1)).getBody(); + verify(ghPullRequest, times(1)).getId(); verifyNoMoreInteractions(ghPullRequest); verify(helper, times(1)).isWhitelisted(eq(ghUser)); // Call to Github API @@ -419,6 +422,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(ghPullRequest, times(3)).getUpdatedAt(); verify(ghPullRequest, times(2)).getHtmlUrl(); + verify(ghPullRequest, times(1)).getId(); verify(ghPullRequest, times(1)).getComments(); verify(ghPullRequest, times(2)).listCommits(); From 202be79b39bfd3c420dff922e465ff05298f154b Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 26 Sep 2015 22:17:07 -0600 Subject: [PATCH 078/175] Missed change to repo --- .../plugins/ghprb/GhprbRepository.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 46185fb65..edd23c77d 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -19,6 +19,7 @@ import java.io.PrintStream; import java.net.URL; import java.util.*; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -44,6 +45,15 @@ public GhprbRepository(String user, String repository, Ghprb helper) { public void init() { // make the initial check call to populate our data structures initGhRepository(); + for (Entry next : helper.getTrigger().getPulls().entrySet()) { + GhprbPullRequest pull = next.getValue(); + try { + pull.init(helper, this); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to initialize pull request #{0} for repo {1}, job {2}", new Object[]{next.getKey(), reponame, helper.getTrigger().getActualProject().getFullName()}); + e.printStackTrace(); + } + } } private boolean initGhRepository() { @@ -133,7 +143,6 @@ private void check(GHPullRequest pr) throws IOException { GhprbPullRequest pull; if (pulls.containsKey(id)) { pull = pulls.get(id); - pull.init(helper, this); } else { pulls.putIfAbsent(id, new GhprbPullRequest(pr, helper, this)); pull = pulls.get(id); @@ -278,8 +287,6 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { if (pull == null) { pull = new GhprbPullRequest(getGitHubRepo().getPullRequest(id), helper, this); pulls.put(id, pull); - } else { - pull.init(helper, this); } pull.check(issueComment.getComment()); GhprbTrigger.getDscp().save(); @@ -298,8 +305,6 @@ void onPullRequestHook(PullRequest pr) throws IOException { if (pull == null) { pulls.putIfAbsent(pr.getNumber(), new GhprbPullRequest(pr.getPullRequest(), helper, this)); pull = pulls.get(pr.getNumber()); - } else { - pull.init(helper, this); } pull.check(pr.getPullRequest()); } else if ("synchronize".equals(pr.getAction())) { @@ -307,8 +312,6 @@ void onPullRequestHook(PullRequest pr) throws IOException { if (pull == null) { pulls.putIfAbsent(pr.getNumber(), new GhprbPullRequest(pr.getPullRequest(), helper, this)); pull = pulls.get(pr.getNumber()); - } else { - pull.init(helper, this); } if (pull == null) { logger.log(Level.SEVERE, "Pull Request #{0} doesn''t exist", pr.getNumber()); From 037c5e6c37dc075c721f4b277a49575572d8e645 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 26 Sep 2015 22:30:53 -0600 Subject: [PATCH 079/175] Add comment about not using context --- src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index e61fd7c4f..7db951fb5 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -447,6 +447,8 @@ public static StandardCredentials lookupCredentials(Item context, String credent List credentials; + logger.log(Level.FINE, "Using null context because of issues not getting all credentias"); + credentials = CredentialsProvider.lookupCredentials(StandardCredentials.class, (Item) null, ACL.SYSTEM, URIRequirementBuilder.fromUri(uri).build()); From 2dd65219322995c8941c1ca8c05be3b7fd0d26b5 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 28 Sep 2015 10:31:09 -0600 Subject: [PATCH 080/175] Replace magic number in test --- .../plugins/ghprb/GhprbRootActionTest.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java index 71bd18f88..4bfa0296d 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java @@ -66,6 +66,9 @@ public class GhprbRootActionTest { private StaplerRequest req; private BufferedReader br; + + + private final int prId = 1; @Before public void setup() throws Exception { @@ -97,9 +100,9 @@ public void testUrlEncoded() throws Exception { given(commitPointer.getSha()).willReturn("sha1"); GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); - given(ghPullRequest.getId()).willReturn(1); - given(ghPullRequest.getNumber()).willReturn(1); - given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); + given(ghPullRequest.getId()).willReturn(prId); + given(ghPullRequest.getNumber()).willReturn(prId); + given(ghRepository.getPullRequest(prId)).willReturn(ghPullRequest); Ghprb ghprb = spy(trigger.createGhprb(project)); doReturn(ghprbGitHub).when(ghprb).getGitHub(); trigger.start(project, true); @@ -139,9 +142,9 @@ public void disabledJobsDontBuild() throws Exception { given(commitPointer.getSha()).willReturn("sha1"); GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); - given(ghPullRequest.getId()).willReturn(1); - given(ghPullRequest.getNumber()).willReturn(1); - given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); + given(ghPullRequest.getId()).willReturn(prId); + given(ghPullRequest.getNumber()).willReturn(prId); + given(ghRepository.getPullRequest(prId)).willReturn(ghPullRequest); Ghprb ghprb = spy(trigger.createGhprb(project)); doReturn(ghprbGitHub).when(ghprb).getGitHub(); trigger.start(project, true); From 8d9bd0ee263ef96c8cb11903d73e80f99c74a5f3 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 28 Sep 2015 16:03:38 -0600 Subject: [PATCH 081/175] Update readme for release --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 538d2d2bc..f92e93483 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,11 @@ If you want to manually build the job, in the job setting check ``This build is ### Updates +#### -> 1.29 +* Reduced the size of the plugin .xml file drastically. +* Fixed issues with persistance store credentials. +* Reduced the noise caused by webhook logic, and reduced amount of work for webhooks + #### -> 1.28 * Fixed [JENKINS-29850] Add author github repo URL * Fixed NPE and other errors in merge logic From 0a095ec7ba8b08a7ba86cd3e4d6a87b79dde047d Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 28 Sep 2015 16:07:11 -0600 Subject: [PATCH 082/175] [maven-release-plugin] prepare release ghprb-1.29 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d69742fd4..e4490112e 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29-SNAPSHOT + 1.29 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.29 From c2f0273b36ff1df08109e5f0206a4a87275073fe Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 28 Sep 2015 16:07:14 -0600 Subject: [PATCH 083/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e4490112e..4b41a7537 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29 + 1.30-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.29 + HEAD From 2d8d31cd88632fd5d6a6151925aaa1e999d618fe Mon Sep 17 00:00:00 2001 From: Andrey Baidarov Date: Sun, 11 Oct 2015 00:34:41 +0300 Subject: [PATCH 084/175] Prevent NPE when job started manually --- .../org/jenkinsci/plugins/ghprb/GhprbBuildListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuildListener.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuildListener.java index db20c2b81..19ef3db68 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuildListener.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuildListener.java @@ -20,7 +20,7 @@ public class GhprbBuildListener extends RunListener> { @Override public void onStarted(AbstractBuild build, TaskListener listener) { GhprbTrigger trigger = Ghprb.extractTrigger(build); - if (trigger != null) { + if (trigger != null && trigger.getBuilds() != null) { trigger.getBuilds().onStarted(build, listener); } } @@ -28,7 +28,7 @@ public void onStarted(AbstractBuild build, TaskListener listener) { @Override public void onCompleted(AbstractBuild build, TaskListener listener) { GhprbTrigger trigger = Ghprb.extractTrigger(build); - if (trigger != null) { + if (trigger != null && trigger.getBuilds() != null) { trigger.getBuilds().onCompleted(build, listener); } } @@ -36,7 +36,7 @@ public void onCompleted(AbstractBuild build, TaskListener listener) { @Override public Environment setUpEnvironment(@SuppressWarnings("rawtypes") AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException { GhprbTrigger trigger = Ghprb.extractTrigger(build); - if (trigger != null) { + if (trigger != null && trigger.getBuilds() != null) { trigger.getBuilds().onEnvironmentSetup(build, launcher, listener); } From b70d5736885534e0b018f334f32c0b292ee99c4a Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 12 Oct 2015 13:48:31 -0600 Subject: [PATCH 085/175] Use StringUtils for equals comparison, and add the old URL style if no env variables --- .../extensions/status/GhprbSimpleStatus.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index e2da2c57e..befefb18d 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -11,6 +11,8 @@ import java.util.List; import java.util.Map; +import jenkins.model.Jenkins; + import org.apache.commons.lang.StringUtils; import org.jenkinsci.plugins.ghprb.Ghprb; import org.jenkinsci.plugins.ghprb.GhprbCause; @@ -89,7 +91,7 @@ public void onBuildTriggered(AbstractProject project, String commitSha, bo String triggeredStatus = getDescriptor().getTriggeredStatusDefault(this); // check if we even need to update - if (triggeredStatus != null && triggeredStatus.equals("--none--")) { + if (StringUtils.equals(triggeredStatus, "--none--")) { return; } @@ -111,7 +113,7 @@ public void onBuildTriggered(AbstractProject project, String commitSha, bo } String url = Ghprb.replaceMacros(project, statusUrl); - if ("--none--".equals(statusUrl) || statusUrl == null) { + if (StringUtils.equals( statusUrl, "--none--")) { url = ""; } @@ -132,7 +134,7 @@ public void onBuildStart(AbstractBuild build, TaskListener listener, GHRep String startedStatus = getDescriptor().getStartedStatusDefault(this); // check if we even need to update - if (startedStatus != null && startedStatus.equals("--none--")) { + if (StringUtils.equals(startedStatus, "--none--")) { return; } @@ -160,7 +162,7 @@ public void onBuildComplete(AbstractBuild build, TaskListener listener, GH for (GhprbBuildResultMessage buildStatus : completedStatus) { sb.append(buildStatus.postBuildComment(build, listener)); } - if (sb.toString().equals("--none--")) { + if (StringUtils.equals(sb.toString(), "--none--")) { return; } } @@ -190,8 +192,11 @@ private void createCommitStatus(AbstractBuild build, TaskListener listener if (StringUtils.isEmpty(url)) { url = envVars.get("JOB_URL"); } + if (StringUtils.isEmpty(url)) { + url = Jenkins.getInstance().getRootUrl() + build.getUrl(); + } - if ("--none--".equals(statusUrl) || statusUrl == null) { + if (StringUtils.equals(statusUrl, "--none--")) { url = ""; } else if (!StringUtils.isEmpty(statusUrl)) { url = Ghprb.replaceMacros(build, listener, statusUrl); From 223a96898dd0061b279733a76eb2e8974763e29f Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 12 Oct 2015 13:53:24 -0600 Subject: [PATCH 086/175] Fix #212, Closes janinko/ghprb#341 --- .../java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java index 246b815b2..78d0b62d7 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java @@ -1,5 +1,7 @@ package org.jenkinsci.plugins.ghprb; +import hudson.model.AbstractProject; + import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -34,7 +36,12 @@ public boolean matchRepo(String hookRepoName) { } public String getProjectName() { - return trigger.getActualProject().getFullName(); + AbstractProject project = trigger.getActualProject(); + if (project != null) { + return project.getFullName(); + } else { + return "NOT STARTED"; + } } public void handleComment(IssueComment issueComment) throws IOException { From dd82bbe52cf9b18533db9e1bad205f5ff2a9ef63 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 14 Oct 2015 09:16:01 -0600 Subject: [PATCH 087/175] Update readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f92e93483..da090edaa 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,10 @@ If you want to manually build the job, in the job setting check ``This build is ### Updates +#### -> 1.29.1 +* Fix NPE for triggers without a project +* Add back default URL if env variables are missing + #### -> 1.29 * Reduced the size of the plugin .xml file drastically. * Fixed issues with persistance store credentials. From 349f4e981cdb0cc1242b11c639f38088bd210dc7 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 14 Oct 2015 09:19:55 -0600 Subject: [PATCH 088/175] [maven-release-plugin] prepare release ghprb-1.29.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4b41a7537..8398592b9 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30-SNAPSHOT + 1.29.1 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.29.1 From 05bb5ebe402b3014d9bce8cf6633f6d8ed93e3aa Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 14 Oct 2015 09:19:58 -0600 Subject: [PATCH 089/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8398592b9..4b41a7537 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29.1 + 1.30-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.29.1 + HEAD From d93a7a39cf27df868a016e1cce3fb048de7b0d45 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 14 Oct 2015 12:26:26 -0600 Subject: [PATCH 090/175] Fix configVersion to share latest value --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 2 +- .../plugins/ghprb/GhprbTriggerBackwardsCompatible.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 277c366b5..c540df369 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -133,7 +133,7 @@ public GhprbTrigger(String adminlist, this.allowMembersOfWhitelistedOrgsAsAdmin = allowMembersOfWhitelistedOrgsAsAdmin; this.buildDescTemplate = buildDescTemplate; setExtensions(extensions); - configVersion = 1; + configVersion = latestVersion; } @Override diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java index fdd120340..a2b8f8e32 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java @@ -23,6 +23,8 @@ public abstract class GhprbTriggerBackwardsCompatible extends Trigger getExtensions(); + protected final int latestVersion = 3; + protected String triggerPhrase; protected Integer configVersion; @@ -58,7 +60,7 @@ protected void convertPropertiesToExtensions() { checkBuildStatusMessages(); checkCommitStatusContext(); - configVersion = 3; + configVersion = latestVersion; } private void checkBuildStatusMessages() { From 6cc03ca97c963484861340e9b318552c0e3cbf54 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 14 Oct 2015 13:54:36 -0600 Subject: [PATCH 091/175] [maven-release-plugin] prepare release ghprb-1.29.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4b41a7537..0a978d35f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30-SNAPSHOT + 1.29.2 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.29.2 From b4ec71347b3548fe9759eeb44ac33ed5ee87ea22 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 14 Oct 2015 13:54:41 -0600 Subject: [PATCH 092/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0a978d35f..4b41a7537 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29.2 + 1.30-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.29.2 + HEAD From 5f6e6d4b27e6270e4547979274b7b80e503e1b68 Mon Sep 17 00:00:00 2001 From: Adrian Bridgett Date: Tue, 20 Oct 2015 21:58:03 +0100 Subject: [PATCH 093/175] first attempt at adding alternative JenkinsURL --- README.md | 1 + .../java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java | 8 ++++++++ .../java/org/jenkinsci/plugins/ghprb/GhprbRepository.java | 6 +++++- .../jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy | 4 ++++ .../plugins/ghprb/GhprbGitHubAuth/help-jenkinsUrl.html | 3 +++ 5 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/help-jenkinsUrl.html diff --git a/README.md b/README.md index da090edaa..f0a1582e6 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ For more details, see https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+re ### Credentials * If you are using Enterprise GitHub set the server api URL in ``GitHub server api URL``. Otherwise leave there ``https://api.github.com``. +* Set the Jenkins URL if you need to override the default (e.g. it's behind a firewall) * A GitHub API token or username password can be used for access to the GitHub API * To setup credentials for a given GitHub Server API URL: * Click Add next to the ``Credentials`` drop down diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java index 863d823bb..4a728c610 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java @@ -53,6 +53,7 @@ public class GhprbGitHubAuth extends AbstractDescribableImpl { public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); private final String serverAPIUrl; + private final String jenkinsUrl; private final String credentialsId; private final String id; private final String description; @@ -61,6 +62,7 @@ public class GhprbGitHubAuth extends AbstractDescribableImpl { @DataBoundConstructor public GhprbGitHubAuth( String serverAPIUrl, + String jenkinsUrl, String credentialsId, String description, String id, @@ -70,6 +72,7 @@ public GhprbGitHubAuth( serverAPIUrl = "https://api.github.com"; } this.serverAPIUrl = fixEmptyAndTrim(serverAPIUrl); + this.jenkinsUrl = fixEmptyAndTrim(jenkinsUrl); this.credentialsId = fixEmpty(credentialsId); if (StringUtils.isEmpty(id)) { id = UUID.randomUUID().toString(); @@ -85,6 +88,11 @@ public String getServerAPIUrl() { return serverAPIUrl; } + @Exported + public String getJenkinsUrl() { + return jenkinsUrl; + } + @Exported public String getCredentialsId() { return credentialsId; diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index edd23c77d..c6f4871b9 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -262,7 +262,11 @@ public boolean createHook() { } private static String getHookUrl() { - return Jenkins.getInstance().getRootUrl() + GhprbRootAction.URL + "/"; + String baseUrl = helper.getTrigger().getGitHubApiAuth().getJenkinsURL(); + if (baseUrl == null) { + baseUrl = Jenkins.getInstance().getRootUrl(); + } + return baseUrl + GhprbRootAction.URL + "/"; } public GHPullRequest getPullRequest(int id) throws IOException { diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy index 8d3f4efab..80ea38eff 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy @@ -5,6 +5,10 @@ f.entry(title:_("GitHub Server API URL"), field:"serverAPIUrl") { f.textbox() } +ff.entry(title:_("Jenkins URL override"), field:"jenkinsUrl") { + f.textbox() +} + f.entry(title:_("Shared secret"), field:"secret") { f.password() } diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/help-jenkinsUrl.html b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/help-jenkinsUrl.html new file mode 100644 index 000000000..361b94778 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/help-jenkinsUrl.html @@ -0,0 +1,3 @@ +
+ Use this to override the Jenkins URL that GitHub should call. +
\ No newline at end of file From a4be236027d4e422206da12252d2908d44855fef Mon Sep 17 00:00:00 2001 From: Adrian Bridgett Date: Tue, 20 Oct 2015 22:44:00 +0100 Subject: [PATCH 094/175] adjustments due to jenkinsUrl --- .../java/org/jenkinsci/plugins/ghprb/GhprbRepository.java | 4 ++-- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index c6f4871b9..f3a0e4342 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -261,8 +261,8 @@ public boolean createHook() { } } - private static String getHookUrl() { - String baseUrl = helper.getTrigger().getGitHubApiAuth().getJenkinsURL(); + private String getHookUrl() { + String baseUrl = helper.getTrigger().getGitHubApiAuth().getJenkinsUrl(); if (baseUrl == null) { baseUrl = Jenkins.getInstance().getRootUrl(); } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index c540df369..38fdf5363 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -555,7 +555,7 @@ public GhprbGitHubAuth getGitHubAuth(String gitHubAuthId) { public List getGithubAuth() { if (githubAuth == null || githubAuth.size() == 0) { githubAuth = new ArrayList(1); - githubAuth.add(new GhprbGitHubAuth(null, null, "Anonymous connection", null, null)); + githubAuth.add(new GhprbGitHubAuth(null, null, null, "Anonymous connection", null, null)); } return githubAuth; } @@ -811,7 +811,7 @@ public void readBackFromLegacy() { if (!StringUtils.isEmpty(accessToken)) { try { - GhprbGitHubAuth auth = new GhprbGitHubAuth(serverAPIUrl, Ghprb.createCredentials(serverAPIUrl, accessToken), "Pre credentials Token", null, null); + GhprbGitHubAuth auth = new GhprbGitHubAuth(serverAPIUrl, null, Ghprb.createCredentials(serverAPIUrl, accessToken), "Pre credentials Token", null, null); if (githubAuth == null) { githubAuth = new ArrayList(1); } @@ -825,7 +825,7 @@ public void readBackFromLegacy() { if (!StringUtils.isEmpty(username) || !StringUtils.isEmpty(password)) { try { - GhprbGitHubAuth auth = new GhprbGitHubAuth(serverAPIUrl, Ghprb.createCredentials(serverAPIUrl, username, password), "Pre credentials username and password", null, null); + GhprbGitHubAuth auth = new GhprbGitHubAuth(serverAPIUrl, null, Ghprb.createCredentials(serverAPIUrl, username, password), "Pre credentials username and password", null, null); if (githubAuth == null) { githubAuth = new ArrayList(1); } From 2e46031be3d6e03d20cd6a5f886271abcda4ea3c Mon Sep 17 00:00:00 2001 From: Adrian Bridgett Date: Wed, 21 Oct 2015 14:14:52 +0100 Subject: [PATCH 095/175] correct typo --- .../org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy index 80ea38eff..8bd491efb 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy @@ -5,7 +5,7 @@ f.entry(title:_("GitHub Server API URL"), field:"serverAPIUrl") { f.textbox() } -ff.entry(title:_("Jenkins URL override"), field:"jenkinsUrl") { +f.entry(title:_("Jenkins URL override"), field:"jenkinsUrl") { f.textbox() } From c74cd080ac184abb4883b8b21310c23d3babcf7f Mon Sep 17 00:00:00 2001 From: Adrian Bridgett Date: Mon, 26 Oct 2015 14:44:01 +0000 Subject: [PATCH 096/175] set shared secret in webhook --- .../java/org/jenkinsci/plugins/ghprb/GhprbRepository.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index edd23c77d..49872a7eb 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -251,8 +251,12 @@ public boolean createHook() { return true; } Map config = new HashMap(); + String secret = getSecret(); config.put("url", new URL(getHookUrl()).toExternalForm()); config.put("insecure_ssl", "1"); + if (secret != "") { + config.put("secret",secret); + } ghRepository.createHook("web", config, HOOK_EVENTS, true); return true; } catch (IOException ex) { @@ -261,6 +265,10 @@ public boolean createHook() { } } + private String getSecret() { + return helper.getTrigger().getGitHubApiAuth().getSecret(); + } + private static String getHookUrl() { return Jenkins.getInstance().getRootUrl() + GhprbRootAction.URL + "/"; } From 97d73e02d0087eb46ca8c7881d5e0932b8499779 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Fri, 30 Oct 2015 08:43:52 -0700 Subject: [PATCH 097/175] During init, we should check whether initGhRepository returns false If it returns false, then ghRepository will not be set, which will cause us to eventually loop around and attempt to call init again (and again) --- .../java/org/jenkinsci/plugins/ghprb/GhprbRepository.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index edd23c77d..bd910759f 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -44,7 +44,12 @@ public GhprbRepository(String user, String repository, Ghprb helper) { public void init() { // make the initial check call to populate our data structures - initGhRepository(); + if (!initGhRepository()) { + // We could have hit the rate limit while initializing. If we + // continue, then we will loop back around and attempt to re-init. + return; + } + for (Entry next : helper.getTrigger().getPulls().entrySet()) { GhprbPullRequest pull = next.getValue(); try { From 6bbe759bbacfa3f006c0fb0c3eae6cf789a9194a Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 30 Oct 2015 10:21:38 -0600 Subject: [PATCH 098/175] [maven-release-plugin] prepare release ghprb-1.29.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4b41a7537..372b70f48 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30-SNAPSHOT + 1.29.3 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.29.3 From bcface5164437e43d99ebc26ebd60dceb20e84e7 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 30 Oct 2015 10:21:42 -0600 Subject: [PATCH 099/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 372b70f48..4b41a7537 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29.3 + 1.30-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.29.3 + HEAD From b7c30744fe21dcda1c4cec4d0219401b5df3d153 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 30 Oct 2015 15:06:44 -0600 Subject: [PATCH 100/175] [maven-release-plugin] prepare release ghprb-1.29.4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4b41a7537..7d89ee9d9 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30-SNAPSHOT + 1.29.4 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.29.4 From d85a8f522fe6e350d0c96697e04b746c698b411c Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 30 Oct 2015 15:06:48 -0600 Subject: [PATCH 101/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7d89ee9d9..4b41a7537 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29.4 + 1.30-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.29.4 + HEAD From 882bbd79f73e2099c7c1125ce5994d0952cf4464 Mon Sep 17 00:00:00 2001 From: Daniel Spilker Date: Thu, 5 Nov 2015 17:37:07 +0100 Subject: [PATCH 102/175] added Job DSL for GhprbTrigger [FIXES JENKINS-31214] --- pom.xml | 6 + .../jobdsl/GhprbContextExtensionPoint.java | 47 +++++ .../ghprb/jobdsl/GhprbExtensionContext.java | 29 ++++ .../jobdsl/GhprbSimpleStatusContext.java | 55 ++++++ .../ghprb/jobdsl/GhprbTriggerContext.java | 161 ++++++++++++++++++ 5 files changed, 298 insertions(+) create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbExtensionContext.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbSimpleStatusContext.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbTriggerContext.java diff --git a/pom.xml b/pom.xml index 4b41a7537..7617fa99d 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,12 @@ ssh-agent 1.3
+ + org.jenkins-ci.plugins + job-dsl + 1.39 + true + junit junit diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java new file mode 100644 index 000000000..72a2504d0 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java @@ -0,0 +1,47 @@ +package org.jenkinsci.plugins.ghprb.jobdsl; + +import antlr.ANTLRException; +import com.google.common.base.Joiner; +import hudson.Extension; +import javaposse.jobdsl.dsl.DslException; +import javaposse.jobdsl.dsl.helpers.triggers.TriggerContext; +import javaposse.jobdsl.plugin.ContextExtensionPoint; +import javaposse.jobdsl.plugin.DslExtensionMethod; +import org.jenkinsci.plugins.ghprb.GhprbBranch; +import org.jenkinsci.plugins.ghprb.GhprbTrigger; + +import java.util.ArrayList; + +@Extension(optional = true) +public class GhprbContextExtensionPoint extends ContextExtensionPoint { + @DslExtensionMethod(context = TriggerContext.class) + public Object githubPullRequest(Runnable closure) { + GhprbTriggerContext context = new GhprbTriggerContext(); + executeInContext(closure, context); + try { + return new GhprbTrigger( + Joiner.on("\n").join(context.admins), + Joiner.on("\n").join(context.userWhitelist), + Joiner.on("\n").join(context.orgWhitelist), + context.cron, + context.triggerPhrase, + context.onlyTriggerPhrase, + context.useGitHubHooks, + context.permitAll, + context.autoCloseFailedPullRequests, + null, + null, + new ArrayList(), + context.allowMembersOfWhitelistedOrgsAsAdmin, + null, + null, + null, + null, + null, + context.extensionContext.extensions + ); + } catch (ANTLRException e) { + throw new DslException("invalid cron tab", e); + } + } +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbExtensionContext.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbExtensionContext.java new file mode 100644 index 000000000..70e02c7fb --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbExtensionContext.java @@ -0,0 +1,29 @@ +package org.jenkinsci.plugins.ghprb.jobdsl; + +import javaposse.jobdsl.dsl.Context; +import javaposse.jobdsl.plugin.ContextExtensionPoint; +import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; +import org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus; + +import java.util.ArrayList; +import java.util.List; + +class GhprbExtensionContext implements Context { + List extensions = new ArrayList(); + + /** + * Updates the commit status during the build. + */ + void commitStatus(Runnable closure) { + GhprbSimpleStatusContext context = new GhprbSimpleStatusContext(); + ContextExtensionPoint.executeInContext(closure, context); + + extensions.add(new GhprbSimpleStatus( + context.context, + context.statusUrl, + context.triggeredStatus, + context.startedStatus, + context.completedStatus + )); + } +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbSimpleStatusContext.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbSimpleStatusContext.java new file mode 100644 index 000000000..0d71cd06f --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbSimpleStatusContext.java @@ -0,0 +1,55 @@ +package org.jenkinsci.plugins.ghprb.jobdsl; + +import javaposse.jobdsl.dsl.Context; +import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; +import org.kohsuke.github.GHCommitState; + +import java.util.ArrayList; +import java.util.List; + +class GhprbSimpleStatusContext implements Context { + String context; + String triggeredStatus; + String startedStatus; + String statusUrl; + List completedStatus = new ArrayList(); + + /** + * A string label to differentiate this status from the status of other systems. + */ + void context(String context) { + this.context = context; + } + + /** + * Use a custom status for when a build is triggered. + */ + void triggeredStatus(String triggeredStatus) { + this.triggeredStatus = triggeredStatus; + } + + /** + * Use a custom status for when a build is started. + */ + void startedStatus(String startedStatus) { + this.startedStatus = startedStatus; + } + + /** + * Use a custom URL instead of the job default. + */ + void statusUrl(String statusUrl) { + this.statusUrl = statusUrl; + } + + /** + * Use a custom status for when a build is completed. Can be called multiple times to set messages for different + * build results. Valid build results are {@code 'SUCCESS'}, {@code 'FAILURE'}, and {@code 'ERROR'}. + */ + void completedStatus(String buildResult, String message) { + completedStatus.add(new GhprbBuildResultMessage( + GHCommitState.valueOf(buildResult), + message + )); + } +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbTriggerContext.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbTriggerContext.java new file mode 100644 index 000000000..d4fc4ccca --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbTriggerContext.java @@ -0,0 +1,161 @@ +package org.jenkinsci.plugins.ghprb.jobdsl; + +import javaposse.jobdsl.dsl.Context; +import javaposse.jobdsl.dsl.helpers.triggers.GitHubPullRequestBuilderExtensionContext; +import javaposse.jobdsl.plugin.ContextExtensionPoint; + +import java.util.ArrayList; +import java.util.List; + +class GhprbTriggerContext implements Context { + List admins = new ArrayList(); + List userWhitelist = new ArrayList(); + List orgWhitelist = new ArrayList(); + String cron = "H/5 * * * *"; + String triggerPhrase; + boolean onlyTriggerPhrase; + boolean useGitHubHooks; + boolean permitAll; + boolean autoCloseFailedPullRequests; + boolean allowMembersOfWhitelistedOrgsAsAdmin; + GhprbExtensionContext extensionContext = new GhprbExtensionContext(); + + /** + * Adds admins for this job. + */ + public void admin(String admin) { + admins.add(admin); + } + + /** + * Adds admins for this job. + */ + public void admins(Iterable admins) { + for (String admin : admins) { + admin(admin); + } + } + + /** + * Adds whitelisted users for this job. + */ + public void userWhitelist(String user) { + userWhitelist.add(user); + } + + /** + * Adds whitelisted users for this job. + */ + public void userWhitelist(Iterable users) { + for (String user : users) { + userWhitelist(user); + } + } + + /** + * Adds organisation names whose members are considered whitelisted for this specific job. + */ + public void orgWhitelist(String organization) { + orgWhitelist.add(organization); + } + + /** + * Adds organisation names whose members are considered whitelisted for this specific job. + */ + public void orgWhitelist(Iterable organizations) { + for (String organization : organizations) { + orgWhitelist(organization); + } + } + + /** + * This schedules polling to GitHub for new changes in pull requests. + */ + public void cron(String cron) { + this.cron = cron; + } + + /** + * When filled, commenting this phrase in the pull request will trigger a build. + */ + public void triggerPhrase(String triggerPhrase) { + this.triggerPhrase = triggerPhrase; + } + + /** + * When set, only commenting the trigger phrase in the pull request will trigger a build. + */ + public void onlyTriggerPhrase(boolean onlyTriggerPhrase) { + this.onlyTriggerPhrase = onlyTriggerPhrase; + } + + /** + * When set, only commenting the trigger phrase in the pull request will trigger a build. + */ + public void onlyTriggerPhrase() { + onlyTriggerPhrase(true); + } + + /** + * Checking this option will disable regular polling for changes in GitHub and will try to create a GitHub hook. + */ + public void useGitHubHooks(boolean useGitHubHooks) { + this.useGitHubHooks = useGitHubHooks; + } + + /** + * Checking this option will disable regular polling for changes in GitHub and will try to create a GitHub hook. + */ + public void useGitHubHooks() { + useGitHubHooks(true); + } + + /** + * Build every pull request automatically without asking. + */ + public void permitAll(boolean permitAll) { + this.permitAll = permitAll; + } + + /** + * Build every pull request automatically without asking. + */ + public void permitAll() { + permitAll(true); + } + + /** + * Close pull request automatically when the build fails. + */ + public void autoCloseFailedPullRequests(boolean autoCloseFailedPullRequests) { + this.autoCloseFailedPullRequests = autoCloseFailedPullRequests; + } + + /** + * Close pull request automatically when the build fails. + */ + public void autoCloseFailedPullRequests() { + autoCloseFailedPullRequests(true); + } + + /** + * Allows members of whitelisted organisations to behave like admins. + */ + public void allowMembersOfWhitelistedOrgsAsAdmin(boolean allowMembersOfWhitelistedOrgsAsAdmin) { + this.allowMembersOfWhitelistedOrgsAsAdmin = allowMembersOfWhitelistedOrgsAsAdmin; + } + + /** + * Allows members of whitelisted organisations to behave like admins. + */ + public void allowMembersOfWhitelistedOrgsAsAdmin() { + allowMembersOfWhitelistedOrgsAsAdmin(true); + } + + /** + * Adds additional trigger options. + */ + public void extensions(Runnable closure) { + ContextExtensionPoint.executeInContext(closure, extensionContext); + } +} From 74d70ebcfb821086726ef7721c5ff1a447f10f24 Mon Sep 17 00:00:00 2001 From: Daniel Spilker Date: Thu, 5 Nov 2015 19:10:23 +0100 Subject: [PATCH 103/175] it's OK for a @DslExtensionMethod to throw an exception --- .../jobdsl/GhprbContextExtensionPoint.java | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java index 72a2504d0..f0f4f0ae5 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java @@ -3,7 +3,6 @@ import antlr.ANTLRException; import com.google.common.base.Joiner; import hudson.Extension; -import javaposse.jobdsl.dsl.DslException; import javaposse.jobdsl.dsl.helpers.triggers.TriggerContext; import javaposse.jobdsl.plugin.ContextExtensionPoint; import javaposse.jobdsl.plugin.DslExtensionMethod; @@ -15,33 +14,29 @@ @Extension(optional = true) public class GhprbContextExtensionPoint extends ContextExtensionPoint { @DslExtensionMethod(context = TriggerContext.class) - public Object githubPullRequest(Runnable closure) { + public Object githubPullRequest(Runnable closure) throws ANTLRException { GhprbTriggerContext context = new GhprbTriggerContext(); executeInContext(closure, context); - try { - return new GhprbTrigger( - Joiner.on("\n").join(context.admins), - Joiner.on("\n").join(context.userWhitelist), - Joiner.on("\n").join(context.orgWhitelist), - context.cron, - context.triggerPhrase, - context.onlyTriggerPhrase, - context.useGitHubHooks, - context.permitAll, - context.autoCloseFailedPullRequests, - null, - null, - new ArrayList(), - context.allowMembersOfWhitelistedOrgsAsAdmin, - null, - null, - null, - null, - null, - context.extensionContext.extensions - ); - } catch (ANTLRException e) { - throw new DslException("invalid cron tab", e); - } + return new GhprbTrigger( + Joiner.on("\n").join(context.admins), + Joiner.on("\n").join(context.userWhitelist), + Joiner.on("\n").join(context.orgWhitelist), + context.cron, + context.triggerPhrase, + context.onlyTriggerPhrase, + context.useGitHubHooks, + context.permitAll, + context.autoCloseFailedPullRequests, + null, + null, + new ArrayList(), + context.allowMembersOfWhitelistedOrgsAsAdmin, + null, + null, + null, + null, + null, + context.extensionContext.extensions + ); } } From 68b97e260d5ba1d202fcd57a8e14758dd5faa7e6 Mon Sep 17 00:00:00 2001 From: Sebastien Launay Date: Mon, 23 Nov 2015 11:00:20 -0800 Subject: [PATCH 104/175] Fix "No test results found" in Github build status - use AbstractTestResultAction instead of TestResultAction - see https://github.com/jenkinsci/jenkins/commit/37c5bc2fd8616dbf4525c3a816e316015b4ff99e --- .../plugins/ghprb/manager/impl/GhprbBaseBuildManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/manager/impl/GhprbBaseBuildManager.java b/src/main/java/org/jenkinsci/plugins/ghprb/manager/impl/GhprbBaseBuildManager.java index 97ad4acad..1a136d640 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/manager/impl/GhprbBaseBuildManager.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/manager/impl/GhprbBaseBuildManager.java @@ -12,8 +12,8 @@ import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Result; +import hudson.tasks.test.AbstractTestResultAction; import hudson.tasks.junit.TestResult; -import hudson.tasks.junit.TestResultAction; import hudson.tasks.junit.CaseResult; import hudson.tasks.test.AggregatedTestResultAction; import hudson.tasks.test.AggregatedTestResultAction.ChildReport; @@ -172,7 +172,7 @@ protected String getAggregatedTestResults(AbstractBuild build) { public String getOneLineTestResults() { - TestResultAction testResultAction = build.getAction(TestResultAction.class); + AbstractTestResultAction testResultAction = build.getAction(AbstractTestResultAction.class); if (testResultAction == null) { return "No test results found."; From 53f8e0fb4d703d329ba99007ee6a16743c7c89ba Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 23 Nov 2015 15:09:29 -0700 Subject: [PATCH 105/175] Update readme for release --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8159ce880..f96a42fd8 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,9 @@ If you want to manually build the job, in the job setting check ``This build is ### Updates +#### -> 1.29.5 +* Merge #232 fixes erronius no test cases found + #### -> 1.29.4 * Add secret when auto creating the web hook * Accomodate Jenkins being behind a firewall From 27a5da33c30c85d798a01af3de6653390806d968 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 23 Nov 2015 15:13:23 -0700 Subject: [PATCH 106/175] [maven-release-plugin] prepare release ghprb-1.29.5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4b41a7537..217273da2 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30-SNAPSHOT + 1.29.5 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.29.5 From cfd73439567cc555436bbb6bf070a201fa3e15c1 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 23 Nov 2015 15:13:26 -0700 Subject: [PATCH 107/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 217273da2..4b41a7537 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29.5 + 1.30-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.29.5 + HEAD From 789cee520192da490d1f7a4dc868c49ea6155a42 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 25 Nov 2015 09:10:50 -0700 Subject: [PATCH 108/175] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f96a42fd8..88930420d 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ If you want to manually build the job, in the job setting check ``This build is ### Updates #### -> 1.29.5 -* Merge #232 fixes erronius no test cases found +* Merge #232 fixes erroneous no test cases found #### -> 1.29.4 * Add secret when auto creating the web hook From 5134ded8eb0fe6ec498c4836853f7fb90f8b0c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Tue, 1 Dec 2015 15:25:26 +0100 Subject: [PATCH 109/175] [JENKINS-31827] Use default timeouts for URLConnections --- .../ghprb/HttpConnectorWithJenkinsProxy.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/HttpConnectorWithJenkinsProxy.java b/src/main/java/org/jenkinsci/plugins/ghprb/HttpConnectorWithJenkinsProxy.java index f44dacf67..256db4c78 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/HttpConnectorWithJenkinsProxy.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/HttpConnectorWithJenkinsProxy.java @@ -1,14 +1,24 @@ package org.jenkinsci.plugins.ghprb; -import hudson.ProxyConfiguration; -import org.kohsuke.github.HttpConnector; - import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; +import org.kohsuke.github.HttpConnector; + +import hudson.ProxyConfiguration; + public class HttpConnectorWithJenkinsProxy implements HttpConnector { public HttpURLConnection connect(URL url) throws IOException { - return (HttpURLConnection) ProxyConfiguration.open(url); + HttpURLConnection con = (HttpURLConnection) ProxyConfiguration.open(url); + + // Set default timeouts in case there are none + if (con.getConnectTimeout() == 0) { + con.setConnectTimeout(10000); + } + if (con.getReadTimeout() == 0) { + con.setReadTimeout(10000); + } + return con; } } From 426743c88427797f2746365103911be28a727dc5 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 1 Dec 2015 15:50:42 -0700 Subject: [PATCH 110/175] Make sure there is always a commit-status --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 38fdf5363..06001bcb7 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -631,6 +631,8 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc try { extensions.rebuildHetero(req, formData, getGlobalExtensionDescriptors(), "extensions"); + // Now make sure we have at least one of the types we need one of. + Ghprb.addIfMissing(this.extensions, new GhprbSimpleStatus(), GhprbCommitStatus.class); } catch (IOException e) { e.printStackTrace(); } From d104f877b89092f388a46d3515482fed8c8d0e8c Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 2 Dec 2015 09:53:39 -0700 Subject: [PATCH 111/175] [maven-release-plugin] prepare release ghprb-1.29.6 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4b41a7537..b7dd9af58 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30-SNAPSHOT + 1.29.6 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.29.6 From 2c25dce6ff6c287c68017edc6cb24f12ede389a4 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 2 Dec 2015 09:53:42 -0700 Subject: [PATCH 112/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b7dd9af58..4b41a7537 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29.6 + 1.30-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.29.6 + HEAD From 18e23557a99454a6750c449c19bd815df796bbd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Thu, 3 Dec 2015 13:48:07 +0100 Subject: [PATCH 113/175] [FIXED JENKINS-31827] Use github-api with explicit socket timeouts declared --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4b41a7537..5dee3ec84 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ org.jenkins-ci.plugins github-api - 1.66 + 1.71 org.jenkins-ci.plugins From 2e58f537d3214d16137d11b2d07970d810fe1de9 Mon Sep 17 00:00:00 2001 From: AtkinsChang Date: Sat, 5 Dec 2015 08:44:59 +0800 Subject: [PATCH 114/175] Fix logging in GhprbRootAction --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 680634b6e..56692a642 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -83,7 +83,7 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { } if (payload == null) { - logger.log(Level.SEVERE, "Payload is null, maybe content type '{0}' is not supported by this plugin. " + logger.log(Level.SEVERE, "Payload is null, maybe content type ''{0}'' is not supported by this plugin. " + "Please use 'application/json' or 'application/x-www-form-urlencoded'", new Object[] { type }); return; From ed22ff1534688a0705bf320a729d5d2aa55f621d Mon Sep 17 00:00:00 2001 From: AtkinsChang Date: Sat, 5 Dec 2015 09:21:41 +0800 Subject: [PATCH 115/175] Fix accept content type --- .../java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 56692a642..f1f956c4c 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -59,18 +59,20 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { String payload = null; String body = null; - if ("application/json".equals(type)) { + if (type.startsWith("application/json")) { body = extractRequestBody(req); if (body == null) { logger.log(Level.SEVERE, "Can't get request body for application/json."); + resp.setStatus(StaplerResponse.SC_BAD_REQUEST); return; } payload = body; - } else if ("application/x-www-form-urlencoded".equals(type)) { + } else if (type.startsWith("application/x-www-form-urlencoded")) { body = extractRequestBody(req); if (body == null || body.length() <= 8) { logger.log(Level.SEVERE, "Request doesn't contain payload. " + "You're sending url encoded request, so you should pass github payload through 'payload' request parameter"); + resp.setStatus(StaplerResponse.SC_BAD_REQUEST); return; } try { @@ -78,6 +80,7 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { payload = URLDecoder.decode(body.substring(8), encoding != null ? encoding : "UTF-8"); } catch (UnsupportedEncodingException e) { logger.log(Level.SEVERE, "Error while trying to decode the payload"); + resp.setStatus(StaplerResponse.SC_BAD_REQUEST); return; } } @@ -86,6 +89,7 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { logger.log(Level.SEVERE, "Payload is null, maybe content type ''{0}'' is not supported by this plugin. " + "Please use 'application/json' or 'application/x-www-form-urlencoded'", new Object[] { type }); + resp.setStatus(StaplerResponse.SC_UNSUPPORTED_MEDIA_TYPE); return; } From a53df9564f184e7f2d68de1e406562611a3ab25c Mon Sep 17 00:00:00 2001 From: AtkinsChang Date: Sat, 5 Dec 2015 16:16:02 +0800 Subject: [PATCH 116/175] Check the media type case-insensitively --- .../java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index f1f956c4c..f0aceb974 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -59,7 +59,7 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { String payload = null; String body = null; - if (type.startsWith("application/json")) { + if (type.toLowerCase().startsWith("application/json")) { body = extractRequestBody(req); if (body == null) { logger.log(Level.SEVERE, "Can't get request body for application/json."); @@ -67,7 +67,7 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { return; } payload = body; - } else if (type.startsWith("application/x-www-form-urlencoded")) { + } else if (type.toLowerCase().startsWith("application/x-www-form-urlencoded")) { body = extractRequestBody(req); if (body == null || body.length() <= 8) { logger.log(Level.SEVERE, "Request doesn't contain payload. " From d924dee94d8693e66be067081b27946970bcb631 Mon Sep 17 00:00:00 2001 From: Patrice Bouillet Date: Mon, 21 Dec 2015 15:12:28 +0100 Subject: [PATCH 117/175] Replace \r + " chars in addition in some env variables fixes #237 --- .../org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 06001bcb7..993e61a31 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -287,12 +287,12 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbPullAuthorLogin", String.valueOf(cause.getPullRequestAuthor().getLogin()))); values.add(new StringParameterValue("ghprbPullAuthorLoginMention", "@" + cause.getPullRequestAuthor().getLogin())); - values.add(new StringParameterValue("ghprbPullDescription", String.valueOf(cause.getShortDescription()).replace("\n", "\\n"))); + values.add(new StringParameterValue("ghprbPullDescription", escapeText(String.valueOf(cause.getShortDescription())))); values.add(new StringParameterValue("ghprbPullTitle", String.valueOf(cause.getTitle()))); values.add(new StringParameterValue("ghprbPullLink", String.valueOf(cause.getUrl()))); - values.add(new StringParameterValue("ghprbPullLongDescription", String.valueOf(cause.getDescription()).replace("\n", "\\n"))); + values.add(new StringParameterValue("ghprbPullLongDescription", escapeText(String.valueOf(cause.getDescription())))); - values.add(new StringParameterValue("ghprbCommentBody", String.valueOf(cause.getCommentBody()).replace("\n", "\\n"))); + values.add(new StringParameterValue("ghprbCommentBody", escapeText(String.valueOf(cause.getCommentBody())))); values.add(new StringParameterValue("ghprbGhRepository", repo.getName())); values.add(new StringParameterValue("ghprbCredentialsId", getString(getGitHubApiAuth().getCredentialsId(), ""))); @@ -302,7 +302,10 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { // one isn't there return this.job.scheduleBuild2(job.getQuietPeriod(), cause, new ParametersAction(values), findPreviousBuildForPullId(pullIdPv)); } - + + private String escapeText(String text) { + return text.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\\\""); + } public GhprbGitHubAuth getGitHubApiAuth() { if (gitHubAuthId == null) { From 66f14ce1c81f27472eeae8c9e5a097a9efc0cacf Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Dec 2015 10:30:43 -0700 Subject: [PATCH 118/175] Update readme and remove quoting of trigger phrase --- README.md | 6 ++++++ .../plugins/ghprb/GhprbTriggerBackwardsCompatible.java | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 88930420d..c3ae18c2e 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,12 @@ If you want to manually build the job, in the job setting check ``This build is ### Updates +#### -> 1.29.7 +* Remove quoting of trigger phrase +* Merged #242 replaces newline and quoted quotes +* Merged #229 Add job dsl +* Merged #238 Update github-api version + #### -> 1.29.5 * Merge #232 fixes erroneous no test cases found diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java index a2b8f8e32..4e0474d37 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java @@ -52,9 +52,6 @@ protected void convertPropertiesToExtensions() { if (configVersion == null) { configVersion = 0; } - if (configVersion < 3 && !StringUtils.isEmpty(triggerPhrase)) { - triggerPhrase = Pattern.quote(triggerPhrase); - } checkCommentsFile(); checkBuildStatusMessages(); From dc7ae9b0b1bfa265090a6e390adf1097b7f447c9 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Dec 2015 10:37:11 -0700 Subject: [PATCH 119/175] [maven-release-plugin] prepare release ghprb-1.29.7 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9d128cd63..70a7444f7 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30-SNAPSHOT + 1.29.7 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.29.7 From 070f9880db6c80bf3746b0b4db0c04a75053718b Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 22 Dec 2015 10:37:14 -0700 Subject: [PATCH 120/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 70a7444f7..9d128cd63 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29.7 + 1.30-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.29.7 + HEAD From 9a68cddd4c1cd851d28cb1a76543dd7e224cf257 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 6 Jan 2016 21:08:06 -0700 Subject: [PATCH 121/175] Remove webhook code, and integrate into trigger and auth --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 12 +- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 9 +- .../plugins/ghprb/GhprbGitHubAuth.java | 37 +++++ .../plugins/ghprb/GhprbPullRequest.java | 4 +- .../plugins/ghprb/GhprbPullRequestMerge.java | 55 +++---- .../plugins/ghprb/GhprbRepository.java | 8 +- .../plugins/ghprb/GhprbRootAction.java | 50 +++--- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 152 +++++++++++------- .../GhprbTriggerBackwardsCompatible.java | 1 - .../jenkinsci/plugins/ghprb/GhprbWebHook.java | 96 ----------- .../org/jenkinsci/plugins/ghprb/GhprbIT.java | 101 +++--------- .../plugins/ghprb/GhprbITBaseTestCase.java | 71 ++++++-- .../ghprb/GhprbPullRequestMergeTest.java | 3 +- .../plugins/ghprb/GhprbRepositoryTest.java | 15 +- .../plugins/ghprb/GhprbRootActionTest.java | 8 +- .../impl/GhprbDefaultBuildManagerTest.java | 48 ++---- .../BuildFlowBuildManagerTest.java | 82 +++------- 17 files changed, 312 insertions(+), 440 deletions(-) delete mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 7db951fb5..427161005 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -47,8 +47,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import jenkins.model.Jenkins; - /** * @author janinko */ @@ -57,14 +55,12 @@ public class Ghprb { private static final Pattern githubUserRepoPattern = Pattern.compile("^(http[s]?://[^/]*)/([^/]*)/([^/]*).*"); private final GhprbTrigger trigger; - private final AbstractProject project; private GhprbRepository repository; private GhprbBuilds builds; - public Ghprb(AbstractProject project, GhprbTrigger trigger) { - this.project = project; + public Ghprb(GhprbTrigger trigger) { - final GithubProjectProperty ghpp = project.getProperty(GithubProjectProperty.class); + final GithubProjectProperty ghpp = trigger.getActualProject().getProperty(GithubProjectProperty.class); if (ghpp == null || ghpp.getProjectUrl() == null) { throw new IllegalStateException("A GitHub project url is required."); } @@ -95,7 +91,7 @@ public void addWhitelist(String author) { } public boolean isProjectDisabled() { - return project.isDisabled(); + return trigger.getActualProject().isDisabled(); } public GhprbBuilds getBuilds() { @@ -115,7 +111,7 @@ public GhprbGitHub getGitHub() { } void run() { - repository.check(); + getRepository().check(); } void stop() { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index aaf8fc73b..426bef663 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -84,18 +84,11 @@ public void onStarted(AbstractBuild build, TaskListener listener) { int counter = 0; // If the PR is being resolved by GitHub then getMergeable will return null Boolean isMergeable = pr.getMergeable(); - Boolean isMerged = pr.isMerged(); - // Not sure if isMerged can return null, but adding if just in case - if (isMerged == null) { - isMerged = false; - } + boolean isMerged = pr.isMerged(); while (isMergeable == null && !isMerged && counter++ < 60) { Thread.sleep(1000); isMergeable = pr.getMergeable(); isMerged = pr.isMerged(); - if (isMerged == null) { - isMerged = false; - } } if (isMerged) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java index 4a728c610..e72a50ff2 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java @@ -12,6 +12,9 @@ import java.util.logging.Level; import java.util.logging.Logger; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + import org.kohsuke.github.GHAuthorization; import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GHIssue; @@ -35,6 +38,7 @@ import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder; import com.google.common.base.Joiner; +import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang.StringUtils; import org.jenkinsci.plugins.plaincredentials.StringCredentials; @@ -113,6 +117,39 @@ public String getId() { public String getSecret() { return secret; } + + + public boolean checkSignature(String body, String signature) { + if (StringUtils.isEmpty(secret)) { + return true; + } + + if (signature != null && signature.startsWith("sha1=")) { + String expected = signature.substring(5); + String algorithm = "HmacSHA1"; + try { + SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(), algorithm); + Mac mac = Mac.getInstance(algorithm); + mac.init(keySpec); + byte[] localSignatureBytes = mac.doFinal(body.getBytes("UTF-8")); + String localSignature = Hex.encodeHexString(localSignatureBytes); + if (! localSignature.equals(expected)) { + logger.log(Level.SEVERE, "Local signature {0} does not match external signature {1}", + new Object[] {localSignature, expected}); + return false; + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Couldn't match both signatures"); + return false; + } + } else { + logger.log(Level.SEVERE, "Request doesn't contain a signature. Check that github has a secret that should be attached to the hook"); + return false; + } + + logger.log(Level.INFO, "Signatures checking OK"); + return true; + } private static GitHubBuilder getBuilder(Item context, String serverAPIUrl, String credentialsId) { GitHubBuilder builder = new GitHubBuilder() diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 73d42e406..780b05928 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -215,7 +215,9 @@ private boolean isUpdated(GHPullRequest pr) { } catch (Exception e) { logger.log(Level.WARNING, "Unable to update last updated date", e); } - ret = ret || !pr.getHead().getSha().equals(head); + GHCommitPointer pointer = pr.getHead(); + String pointerSha = pointer.getSha(); + ret = ret || !pointerSha.equals(head); return ret; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 118be627f..b07777b9a 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -44,12 +44,7 @@ public class GhprbPullRequestMerge extends Recorder { private final Boolean deleteOnMerge; @DataBoundConstructor - public GhprbPullRequestMerge( - String mergeComment, - boolean onlyAdminsMerge, - boolean disallowOwnCode, - boolean failOnNonMerge, - boolean deleteOnMerge) { + public GhprbPullRequestMerge(String mergeComment, boolean onlyAdminsMerge, boolean disallowOwnCode, boolean failOnNonMerge, boolean deleteOnMerge) { this.mergeComment = mergeComment; this.onlyAdminsMerge = onlyAdminsMerge; @@ -69,12 +64,10 @@ public boolean isOnlyAdminsMerge() { public boolean isDisallowOwnCode() { return disallowOwnCode == null ? false : disallowOwnCode; } - public boolean isFailOnNonMerge() { return failOnNonMerge == null ? false : failOnNonMerge; } - public boolean isDeleteOnMerge() { return deleteOnMerge == null ? false : deleteOnMerge; @@ -115,11 +108,10 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build pr = trigger.getRepository().getPullRequest(cause.getPullID()); if (helper == null) { - helper = new Ghprb(project, trigger); + helper = new Ghprb(trigger); helper.init(); } - GHUser triggerSender = cause.getTriggerSender(); // ignore comments from bot user, this fixes an issue where the bot would auto-merge @@ -138,20 +130,16 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build // comment if (commentBody == null || !helper.isTriggerPhrase(commentBody)) { logger.println("The comment does not contain the required trigger phrase."); - } - else { + } else { intendToMerge = true; } // If there is no intention to merge there is no point checking if (intendToMerge && isOnlyAdminsMerge() && (triggerSender == null || !helper.isAdmin(triggerSender))) { canMerge = false; - logger.println("Only admins can merge this pull request, " - + (triggerSender != null ? triggerSender.getLogin() + " is not an admin" - : " and build was triggered via automation") + "."); + logger.println("Only admins can merge this pull request, " + (triggerSender != null ? triggerSender.getLogin() + " is not an admin" : " and build was triggered via automation") + "."); if (triggerSender != null) { - commentOnRequest(String.format("Code not merged because @%s (%s) is not in the Admin list.", - triggerSender.getLogin(), triggerSender.getName())); + commentOnRequest(String.format("Code not merged because @%s (%s) is not in the Admin list.", triggerSender.getLogin(), triggerSender.getName())); } } @@ -160,8 +148,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build canMerge = false; if (triggerSender != null) { logger.println("The commentor is also one of the contributors."); - commentOnRequest(String.format("Code not merged because @%s (%s) has committed code in the request.", - triggerSender.getLogin(), triggerSender.getName())); + commentOnRequest(String.format("Code not merged because @%s (%s) has committed code in the request.", triggerSender.getLogin(), triggerSender.getName())); } } @@ -178,17 +165,17 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build if (intendToMerge && canMerge) { logger.println("Merging the pull request"); - try { - Field ghRootField = GHIssue.class.getDeclaredField("root"); - ghRootField.setAccessible(true); - Object ghRoot = ghRootField.get(pr); - Method anonMethod = GitHub.class.getMethod("isAnonymous"); - anonMethod.setAccessible(true); - Boolean isAnonymous = (Boolean) (anonMethod.invoke(ghRoot)); - logger.println("Merging PR[" + pr + "] is anonymous: " + isAnonymous); - } catch (Exception e) { - e.printStackTrace(logger); - } + try { + Field ghRootField = GHIssue.class.getDeclaredField("root"); + ghRootField.setAccessible(true); + Object ghRoot = ghRootField.get(pr); + Method anonMethod = GitHub.class.getMethod("isAnonymous"); + anonMethod.setAccessible(true); + Boolean isAnonymous = (Boolean) (anonMethod.invoke(ghRoot)); + logger.println("Merging PR[" + pr + "] is anonymous: " + isAnonymous); + } catch (Exception e) { + e.printStackTrace(logger); + } pr.merge(getMergeComment()); logger.println("Pull request successfully merged"); deleteBranch(build, launcher, listener); @@ -204,7 +191,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build } private void deleteBranch(AbstractBuild build, Launcher launcher, final BuildListener listener) { - if (!isDeleteOnMerge()){ + if (!isDeleteOnMerge()) { return; } String branchName = pr.getHead().getRef(); @@ -237,8 +224,7 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { GHUser prUser = pr.getUser(); if (prUser.getLogin().equals(commentorLogin)) { - logger.println(commentorName + " (" + commentorLogin + ") has submitted the PR[" + pr.getNumber() - + pr.getNumber() + "] that is to be merged"); + logger.println(commentorName + " (" + commentorLogin + ") has submitted the PR[" + pr.getNumber() + pr.getNumber() + "] that is to be merged"); return true; } @@ -254,8 +240,7 @@ private boolean isOwnCode(GHPullRequest pr, GHUser commentor) { isSame |= commentorEmail != null && commentorEmail.equals(committerEmail); if (isSame) { - logger.println(commentorName + " (" + commentorEmail + ") has commits in PR[" + pr.getNumber() - + "] that is to be merged"); + logger.println(commentorName + " (" + commentorEmail + ") has commits in PR[" + pr.getNumber() + "] that is to be merged"); return isSame; } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 5d9ab6ba6..f8ba66267 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -218,7 +218,9 @@ public void addComment(int id, String comment, AbstractBuild build, TaskLi } try { - getGitHubRepo().getPullRequest(id).comment(comment); + GHRepository repo = getGitHubRepo(); + GHPullRequest pr = repo.getPullRequest(id); + pr.comment(comment); } catch (IOException ex) { logger.log(Level.SEVERE, "Couldn't add comment to pull request #" + id + ": '" + comment + "'", ex); } @@ -226,7 +228,9 @@ public void addComment(int id, String comment, AbstractBuild build, TaskLi public void closePullRequest(int id) { try { - getGitHubRepo().getPullRequest(id).close(); + GHRepository repo = getGitHubRepo(); + GHPullRequest pr = repo.getPullRequest(id); + pr.close(); } catch (IOException ex) { logger.log(Level.SEVERE, "Couldn't close the pull request #" + id + ": '", ex); } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index f0aceb974..2d917a2d4 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -70,8 +70,7 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { } else if (type.toLowerCase().startsWith("application/x-www-form-urlencoded")) { body = extractRequestBody(req); if (body == null || body.length() <= 8) { - logger.log(Level.SEVERE, "Request doesn't contain payload. " - + "You're sending url encoded request, so you should pass github payload through 'payload' request parameter"); + logger.log(Level.SEVERE, "Request doesn't contain payload. " + "You're sending url encoded request, so you should pass github payload through 'payload' request parameter"); resp.setStatus(StaplerResponse.SC_BAD_REQUEST); return; } @@ -86,18 +85,17 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { } if (payload == null) { - logger.log(Level.SEVERE, "Payload is null, maybe content type ''{0}'' is not supported by this plugin. " - + "Please use 'application/json' or 'application/x-www-form-urlencoded'", + logger.log(Level.SEVERE, "Payload is null, maybe content type ''{0}'' is not supported by this plugin. " + "Please use 'application/json' or 'application/x-www-form-urlencoded'", new Object[] { type }); resp.setStatus(StaplerResponse.SC_UNSUPPORTED_MEDIA_TYPE); return; } logger.log(Level.FINE, "Got payload event: {0}", event); - + try { GitHub gh = GitHub.connectAnonymously(); - + if ("issue_comment".equals(event)) { IssueComment issueComment = getIssueComment(payload, gh); GHIssueState state = issueComment.getIssue().getState(); @@ -105,19 +103,17 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { logger.log(Level.INFO, "Skip comment on closed PR"); return; } - + String repoName = issueComment.getRepository().getFullName(); logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", new Object[] { issueComment.getComment(), repoName }); - for (GhprbWebHook webHook : getWebHooks()) { + for (GhprbTrigger trigger : getTriggers(repoName, body, signature)) { try { - if (webHook.matchRepo(repoName) && webHook.checkSignature(body, signature)) { - IssueComment authedComment = getIssueComment(payload, webHook.getGitHub()); - webHook.handleComment(authedComment); - } + IssueComment authedComment = getIssueComment(payload, trigger.getGitHub()); + trigger.handleComment(authedComment); } catch (Exception e) { - logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); + logger.log(Level.SEVERE, "Unable to process web hook for: " + trigger.getProjectName(), e); } } @@ -127,14 +123,12 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repoName, pr.getNumber() }); - for (GhprbWebHook webHook : getWebHooks()) { + for (GhprbTrigger trigger : getTriggers(repoName, body, signature)) { try { - if (webHook.matchRepo(repoName) && webHook.checkSignature(body, signature)) { - PullRequest authedPr = getPullRequest(payload, webHook.getGitHub()); - webHook.handlePR(authedPr); - } + PullRequest authedPr = getPullRequest(payload, trigger.getGitHub()); + trigger.handlePR(authedPr); } catch (Exception e) { - logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); + logger.log(Level.SEVERE, "Unable to process web hook for: " + trigger.getProjectName(), e); } } } else { @@ -145,12 +139,12 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { logger.log(Level.SEVERE, "Unable to connect to GitHub anonymously", e); } } - + private PullRequest getPullRequest(String payload, GitHub gh) throws IOException { PullRequest pr = gh.parseEventPayload(new StringReader(payload), PullRequest.class); return pr; } - + private IssueComment getIssueComment(String payload, GitHub gh) throws IOException { IssueComment issueComment = gh.parseEventPayload(new StringReader(payload), IssueComment.class); return issueComment; @@ -170,10 +164,8 @@ private String extractRequestBody(StaplerRequest req) { return body; } - - private Set getWebHooks() { - final Set webHooks = new HashSet(); - + private Set getTriggers(String repoName, String body, String signature) { + final Set triggers = new HashSet(5); // We need this to get access to list of repositories Authentication old = SecurityContextHolder.getContext().getAuthentication(); SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); @@ -181,20 +173,20 @@ private Set getWebHooks() { try { for (AbstractProject job : Jenkins.getInstance().getAllItems(AbstractProject.class)) { GhprbTrigger trigger = job.getTrigger(GhprbTrigger.class); - if (trigger == null || trigger.getWebHook() == null) { + if (trigger == null || !(trigger.matchRepo(repoName) && trigger.matchSignature(body, signature))) { continue; } - webHooks.add(trigger.getWebHook()); + triggers.add(trigger); } } finally { SecurityContextHolder.getContext().setAuthentication(old); } - if (webHooks.size() == 0) { + if (triggers.isEmpty()) { logger.log(Level.WARNING, "No projects found using GitHub pull request trigger"); } - return webHooks; + return triggers; } @Extension diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 993e61a31..3b09eccf7 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -8,8 +8,15 @@ import hudson.Extension; import hudson.Util; import hudson.matrix.MatrixProject; -import hudson.model.*; import hudson.model.AbstractProject; +import hudson.model.Item; +import hudson.model.ParameterDefinition; +import hudson.model.ParameterValue; +import hudson.model.ParametersAction; +import hudson.model.ParametersDefinitionProperty; +import hudson.model.Run; +import hudson.model.Saveable; +import hudson.model.StringParameterValue; import hudson.model.queue.QueueTaskFuture; import hudson.plugins.git.util.BuildData; import hudson.triggers.TriggerDescriptor; @@ -30,6 +37,8 @@ import org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus; import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GitHub; +import org.kohsuke.github.GHEventPayload.IssueComment; +import org.kohsuke.github.GHEventPayload.PullRequest; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; @@ -37,15 +46,16 @@ import javax.servlet.ServletException; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; -import jenkins.model.Jenkins; - /** * @author Honza Brázdil */ @@ -66,11 +76,11 @@ public class GhprbTrigger extends GhprbTriggerBackwardsCompatible { private Boolean autoCloseFailedPullRequests; private Boolean displayBuildErrorsOnDownstreamBuilds; private List whiteListTargetBranches; - private transient Ghprb helper; - private String project; - private AbstractProject _project; private String gitHubAuthId; + + private transient Ghprb helper; + private DescribableList extensions = new DescribableList(Saveable.NOOP); @@ -159,16 +169,16 @@ public static DescriptorImpl getDscp() { * Save any updates that may have been made inside the plugin that would affect the config.xml */ public void save() { - if (_project != null) { + if (super.job != null) { String xmlConfig = ""; try { - xmlConfig = _project.getConfigFile().asString(); + xmlConfig = super.job.getConfigFile().asString(); } catch (IOException e) { logger.log(Level.SEVERE, "Unable to save load config file", e); } if (!xmlConfig.contains("" + configVersion)) { try { - _project.save(); + super.job.save(); } catch (IOException e) { logger.log(Level.SEVERE, "Unable to save config updates", e); } @@ -180,43 +190,40 @@ public void save() { public void start(AbstractProject project, boolean newInstance) { // We should always start the trigger, and handle cases where we don't run in the run function. super.start(project, newInstance); - this._project = project; - this.project = project.getFullName(); save(); + String name = project.getFullName(); + if (project.isDisabled()) { - logger.log(Level.FINE, "Project is disabled, not starting trigger for job " + this.project); + logger.log(Level.FINE, "Project is disabled, not starting trigger for job " + name); return; } if (project.getProperty(GithubProjectProperty.class) == null) { - logger.log(Level.INFO, "GitHub project property is missing the URL, cannot start ghprb trigger for job " + this.project); + logger.log(Level.INFO, "GitHub project property is missing the URL, cannot start ghprb trigger for job " + name); return; } try { - helper = createGhprb(project); + helper = new Ghprb(this); } catch (IllegalStateException ex) { logger.log(Level.SEVERE, "Can't start ghprb trigger", ex); return; } logger.log(Level.INFO, "Starting the ghprb trigger for the {0} job; newInstance is {1}", - new String[] { this.project, String.valueOf(newInstance) }); + new String[] { name, String.valueOf(newInstance) }); helper.init(); } - Ghprb createGhprb(AbstractProject project) { - return new Ghprb(project, this); - } - public ConcurrentMap getPulls() { - return getDescriptor().getPullRequests(_project.getFullName()); + return getDescriptor().getPullRequests(super.job.getFullName()); } @Override public void stop() { - logger.log(Level.INFO, "Stopping the ghprb trigger for project {0}", this.project); + String name = super.job != null ? super.job.getFullName(): "NOT STARTED"; + logger.log(Level.INFO, "Stopping the ghprb trigger for project {0}", name); if (helper != null) { helper.stop(); helper = null; @@ -232,18 +239,12 @@ public void run() { return; } - if ((helper != null && helper.isProjectDisabled()) || (_project != null && _project.isDisabled())) { - logger.log(Level.FINE, "Project is disabled, ignoring trigger run call for job {0}", this.project); - return; - } - - if (helper == null) { - logger.log(Level.SEVERE, "Helper is null and Project is not disabled, unable to run trigger"); + if (!isActive()) { return; } - logger.log(Level.FINE, "Running trigger for {0}", project); + logger.log(Level.FINE, "Running trigger for {0}", super.job.getFullName()); helper.run(); getDescriptor().save(); @@ -325,20 +326,7 @@ public GitHub getGitHub() throws IOException { } public AbstractProject getActualProject() { - - if (_project != null) { - return _project; - } - - @SuppressWarnings("rawtypes") - List projects = Jenkins.getInstance().getAllItems(AbstractProject.class); - - for (AbstractProject project : projects) { - if (project.getFullName().equals(this.project)) { - return project; - } - } - return null; + return super.job; } private void setCommitAuthor(GhprbCause cause, ArrayList values) { @@ -433,10 +421,6 @@ public String getCron() { return cron; } - public String getProject() { - return project; - } - public String getTriggerPhrase() { if (triggerPhrase == null) { return ""; @@ -479,11 +463,6 @@ public List getWhiteListTargetBranches() { return whiteListTargetBranches; } - public GhprbWebHook getWebHook() { - GhprbWebHook webHook = new GhprbWebHook(this); - return webHook; - } - @Override public DescriptorImpl getDescriptor() { return DESCRIPTOR; @@ -495,20 +474,69 @@ void setHelper(Ghprb helper) { } public GhprbBuilds getBuilds() { - if (helper == null) { - logger.log(Level.SEVERE, "The ghprb trigger for {0} wasn''t properly started - helper is null", this.project); - return null; - } - return helper.getBuilds(); + return isActive() ? helper.getBuilds() : null; } + public boolean isActive() { + String name = super.job != null ? super.job.getFullName() : "NOT STARTED"; + boolean isActive = true; + if (super.job == null) { + logger.log(Level.FINE, "Project was never set, start was never run"); + isActive = false; + } else if ((helper != null && helper.isProjectDisabled()) || (super.job != null && super.job.isDisabled())) { + logger.log(Level.FINE, "Project is disabled, ignoring trigger run call for job {0}", name); + isActive = false; + } else if (helper == null) { + logger.log(Level.SEVERE, "The ghprb trigger for {0} wasn''t properly started - helper is null", name); + isActive = false; + } + + return isActive; + } + public GhprbRepository getRepository() { - if (helper == null) { - logger.log(Level.SEVERE, "The ghprb trigger for {0} wasn''t properly started - helper is null", this.project); - return null; + return isActive() ? helper.getRepository() : null; + } + + public String getProjectName() { + String projectName = super.job == null ? "NOT_STARTED" : super.job.getFullName(); + return projectName; + } + + public boolean matchRepo(String hookRepoName) { + if (!isActive()) { + return false; } - return helper.getRepository(); + String repo = getRepository().getName(); + + logger.log(Level.FINE, "Comparing repository names: {0} to {1}, case is ignored", new Object[] { repo, hookRepoName }); + return repo.equalsIgnoreCase(hookRepoName); } + + public boolean matchSignature(String body, String signature) { + if (!isActive()) { + return false; + } + GhprbGitHubAuth auth = getGitHubApiAuth(); + return auth == null ? false : auth.checkSignature(body, signature); + } + + public void handleComment(IssueComment issueComment) throws IOException { + GhprbRepository repo = getRepository(); + + logger.log(Level.INFO, "Checking comment on PR #{0} for job {1}", new Object[] {issueComment.getIssue().getNumber(), getProjectName()}); + + repo.onIssueCommentHook(issueComment); + } + + public void handlePR(PullRequest pr) throws IOException { + GhprbRepository repo = getRepository(); + + logger.log(Level.INFO, "Checking PR #{0} for job {1}", new Object[] {pr.getNumber(), getProjectName()}); + + repo.onPullRequestHook(pr); + } + public static final class DescriptorImpl extends TriggerDescriptor { // GitHub username may only contain alphanumeric characters or dashes and cannot begin with a dash diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java index 4e0474d37..2c798071d 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java deleted file mode 100644 index 78d0b62d7..000000000 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.jenkinsci.plugins.ghprb; - -import hudson.model.AbstractProject; - -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.codec.binary.Hex; -import org.apache.commons.lang.StringUtils; -import org.kohsuke.github.GHEventPayload.IssueComment; -import org.kohsuke.github.GHEventPayload.PullRequest; -import org.kohsuke.github.GitHub; - -public class GhprbWebHook { - private static final Logger logger = Logger.getLogger(GhprbWebHook.class.getName()); - - private final GhprbTrigger trigger; - - public GhprbWebHook(GhprbTrigger trigger) { - this.trigger = trigger; - } - - public GitHub getGitHub() throws IOException { - return trigger.getGitHub(); - } - - public boolean matchRepo(String hookRepoName) { - GhprbRepository ghprbRepo = trigger.getRepository(); - String jobRepoName = ghprbRepo.getName(); - logger.log(Level.FINE, "Comparing repository names: {0} to {1}, case is ignored", new Object[] { jobRepoName, hookRepoName }); - return jobRepoName.equalsIgnoreCase(hookRepoName); - } - - public String getProjectName() { - AbstractProject project = trigger.getActualProject(); - if (project != null) { - return project.getFullName(); - } else { - return "NOT STARTED"; - } - } - - public void handleComment(IssueComment issueComment) throws IOException { - GhprbRepository repo = trigger.getRepository(); - - logger.log(Level.INFO, "Checking comment on PR #{0} for job {1}", new Object[] {issueComment.getIssue().getNumber(), getProjectName()}); - - repo.onIssueCommentHook(issueComment); - } - - public void handlePR(PullRequest pr) throws IOException { - GhprbRepository repo = trigger.getRepository(); - - logger.log(Level.INFO, "Checking PR #{0} for job {1}", new Object[] {pr.getNumber(), getProjectName()}); - - repo.onPullRequestHook(pr); - } - - public boolean checkSignature(String body, String signature) { - String secret = trigger.getGitHubApiAuth().getSecret(); - if (StringUtils.isEmpty(secret)) { - return true; - } - - if (signature != null && signature.startsWith("sha1=")) { - String expected = signature.substring(5); - String algorithm = "HmacSHA1"; - try { - SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(), algorithm); - Mac mac = Mac.getInstance(algorithm); - mac.init(keySpec); - byte[] localSignatureBytes = mac.doFinal(body.getBytes("UTF-8")); - String localSignature = Hex.encodeHexString(localSignatureBytes); - if (! localSignature.equals(expected)) { - logger.log(Level.SEVERE, "Local signature {0} does not match external signature {1}", - new Object[] {localSignature, expected}); - return false; - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Couldn't match both signatures"); - return false; - } - } else { - logger.log(Level.SEVERE, "Request doesn't contain a signature. Check that github has a secret that should be attached to the hook"); - return false; - } - - logger.log(Level.INFO, "Signatures checking OK"); - return true; - } - -} diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java index e79527e8d..d1fcf7e3d 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java @@ -1,10 +1,8 @@ package org.jenkinsci.plugins.ghprb; -import com.coravy.hudson.plugins.github.GithubProjectProperty; import com.google.common.collect.Lists; import hudson.model.FreeStyleProject; -import hudson.plugins.git.GitSCM; import org.joda.time.DateTime; import org.junit.Before; @@ -16,17 +14,13 @@ import org.kohsuke.github.GHIssueComment; import org.kohsuke.stapler.RequestImpl; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Matchers.any; +import static org.mockito.Mockito.any; @RunWith(MockitoJUnitRunner.class) public class GhprbIT extends GhprbITBaseTestCase { @@ -36,38 +30,23 @@ public class GhprbIT extends GhprbITBaseTestCase { @Mock private RequestImpl req; + @Mock + private GHIssueComment comment; + + + private FreeStyleProject project; + @Before - public void setUp() throws Exception { - // GhprbTestUtil.mockGithubUserPage(); - super.beforeTest(); + public void setUp() throws Exception {// GIVEN + project = jenkinsRule.createFreeStyleProject("PRJ"); + super.beforeTest(null, null, project); } @Test public void shouldBuildTriggersOnNewPR() throws Exception { - // GIVEN - FreeStyleProject project = jenkinsRule.createFreeStyleProject("PRJ"); - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); - given(commitPointer.getSha()).willReturn("sha"); - GhprbTestUtil.setupGhprbTriggerDescriptor(null); - project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); given(ghPullRequest.getNumber()).willReturn(1); - - // Creating spy on ghprb, configuring repo - Ghprb ghprb = spy(trigger.createGhprb(project)); - doReturn(ghprbGitHub).when(ghprb).getGitHub(); - ghprb.getRepository().setHelper(ghprb); - - // Configuring and adding Ghprb trigger - project.addTrigger(trigger); - - // Configuring Git SCM - GitSCM scm = GhprbTestUtil.provideGitSCM(); - project.setScm(scm); - - trigger.start(project, true); - trigger.setHelper(ghprb); - + GhprbTestUtil.triggerRunAndWait(10, trigger, project); assertThat(project.getBuilds().toArray().length).isEqualTo(1); @@ -76,22 +55,11 @@ public void shouldBuildTriggersOnNewPR() throws Exception { @Test public void shouldBuildTriggersOnUpdatingNewCommitsPR() throws Exception { // GIVEN - FreeStyleProject project = jenkinsRule.createFreeStyleProject("PRJ"); - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); - given(commitPointer.getSha()).willReturn("sha").willReturn("sha").willReturn("newOne").willReturn("newOne"); + given(commitPointer.getSha()).willReturn("sha").willReturn("newOne").willReturn("newOne"); given(ghPullRequest.getComments()).willReturn(Lists. newArrayList()); - GhprbTestUtil.setupGhprbTriggerDescriptor(null); - project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); + given(ghPullRequest.getNumber()).willReturn(2).willReturn(2).willReturn(3).willReturn(3); - Ghprb ghprb = spy(trigger.createGhprb(project)); - doReturn(ghprbGitHub).when(ghprb).getGitHub(); - trigger.start(project, true); - trigger.setHelper(ghprb); - ghprb.getRepository().setHelper(ghprb); - project.addTrigger(trigger); - GitSCM scm = GhprbTestUtil.provideGitSCM(); - project.setScm(scm); - + GhprbTestUtil.triggerRunAndWait(10, trigger, project); assertThat(project.getBuilds().toArray().length).isEqualTo(2); @@ -100,29 +68,16 @@ public void shouldBuildTriggersOnUpdatingNewCommitsPR() throws Exception { @Test public void shouldBuildTriggersOnUpdatingRetestMessagePR() throws Exception { // GIVEN - FreeStyleProject project = jenkinsRule.createFreeStyleProject("PRJ"); - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); - - given(commitPointer.getSha()).willReturn("sha"); - - GHIssueComment comment = mock(GHIssueComment.class); + GhprbTestUtil.triggerRunAndWait(10, trigger, project); + given(comment.getBody()).willReturn("retest this please"); given(comment.getUpdatedAt()).willReturn(new DateTime().plusDays(1).toDate()); given(comment.getUser()).willReturn(ghUser); + given(ghPullRequest.getComments()).willReturn(newArrayList(comment)); given(ghPullRequest.getNumber()).willReturn(5).willReturn(5); - GhprbTestUtil.setupGhprbTriggerDescriptor(null); - project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); - - Ghprb ghprb = spy(trigger.createGhprb(project)); - doReturn(ghprbGitHub).when(ghprb).getGitHub(); - trigger.start(project, true); - trigger.setHelper(ghprb); - ghprb.getRepository().setHelper(ghprb); - project.addTrigger(trigger); - GitSCM scm = GhprbTestUtil.provideGitSCM(); - project.setScm(scm); + GhprbTestUtil.triggerRunAndWait(10, trigger, project); assertThat(project.getBuilds().toArray().length).isEqualTo(2); } @@ -131,35 +86,21 @@ public void shouldBuildTriggersOnUpdatingRetestMessagePR() throws Exception { @Test public void shouldNotBuildDisabledBuild() throws Exception { // GIVEN - FreeStyleProject project = jenkinsRule.createFreeStyleProject("PRJ"); - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); - + given(commitPointer.getSha()).willReturn("sha"); - GHIssueComment comment = mock(GHIssueComment.class); given(comment.getBody()).willReturn("retest this please"); given(comment.getUpdatedAt()).willReturn(new DateTime().plusDays(1).toDate()); given(comment.getUser()).willReturn(ghUser); given(ghPullRequest.getComments()).willReturn(newArrayList(comment)); given(ghPullRequest.getNumber()).willReturn(5); - GhprbTestUtil.setupGhprbTriggerDescriptor(null); - project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); - - Ghprb ghprb = spy(trigger.createGhprb(project)); - doReturn(ghprbGitHub).when(ghprb).getGitHub(); - trigger.start(project, true); - trigger.setHelper(ghprb); - ghprb.getRepository().setHelper(ghprb); - project.addTrigger(trigger); - GitSCM scm = GhprbTestUtil.provideGitSCM(); - project.setScm(scm); project.disable(); GhprbTestUtil.triggerRunAndWait(10, trigger, project); assertThat(project.getBuilds().toArray().length).isEqualTo(0); - verify(ghRepository, times(0)).createCommitStatus(any(String.class), any(GHCommitState.class), any(String.class), any(String.class)); + Mockito.verify(ghRepository, Mockito.times(0)).createCommitStatus(any(String.class), any(GHCommitState.class), any(String.class), any(String.class)); } } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java index c0bb1a97b..ddba7ca5c 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java @@ -1,11 +1,17 @@ package org.jenkinsci.plugins.ghprb; import static com.google.common.collect.Lists.newArrayList; -import static org.kohsuke.github.GHIssueState.OPEN; import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; + +import java.util.Map; + +import hudson.model.AbstractBuild; import hudson.model.AbstractProject; +import hudson.model.TaskListener; +import hudson.plugins.git.GitSCM; import org.joda.time.DateTime; import org.kohsuke.github.GHCommitPointer; @@ -16,6 +22,9 @@ import org.kohsuke.github.GitHub; import org.mockito.Mock; import org.mockito.Mockito; +import org.kohsuke.github.GHIssueState; + +import com.coravy.hudson.plugins.github.GithubProjectProperty; /** * @author mdelapenya (Manuel de la Peña) @@ -34,42 +43,76 @@ public abstract class GhprbITBaseTestCase { protected GHUser ghUser; @Mock protected GitHub gitHub; + @Mock + protected Ghprb helper; + + + protected GhprbBuilds builds; + + protected GhprbTrigger trigger; // Stubs protected GHRateLimit ghRateLimit = new GHRateLimit(); - protected void beforeTest() throws Exception { + protected void beforeTest(Map globalConfig, Map triggerConfig, AbstractProject project) throws Exception { + project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); + GhprbTestUtil.setupGhprbTriggerDescriptor(globalConfig); + + trigger = GhprbTestUtil.getTrigger(triggerConfig); + given(ghprbGitHub.get()).willReturn(gitHub); + given(gitHub.getRateLimit()).willReturn(ghRateLimit); given(gitHub.getRepository(anyString())).willReturn(ghRepository); + + given(ghPullRequest.getHead()).willReturn(commitPointer); + given(ghPullRequest.getUser()).willReturn(ghUser); + given(commitPointer.getRef()).willReturn("ref"); + given(commitPointer.getSha()).willReturn("sha"); + given(ghRepository.getName()).willReturn("dropwizard"); GhprbTestUtil.mockPR(ghPullRequest, commitPointer, new DateTime(), new DateTime().plusDays(1)); + - given(ghRepository.getPullRequests(eq(OPEN))).willReturn(newArrayList(ghPullRequest)).willReturn(newArrayList(ghPullRequest)); + given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(newArrayList(ghPullRequest)).willReturn(newArrayList(ghPullRequest)); - given(ghPullRequest.getUser()).willReturn(ghUser); given(ghUser.getEmail()).willReturn("email@email.com"); given(ghUser.getLogin()).willReturn("user"); ghRateLimit.remaining = GhprbTestUtil.INITIAL_RATE_LIMIT; GhprbTestUtil.mockCommitList(ghPullRequest); - } + - protected void setRepositoryHelper(Ghprb ghprb) { - ghprb.getRepository().setHelper(ghprb); - } + GhprbRepository repo = Mockito.spy(new GhprbRepository("user", "dropwizard", helper)); + Mockito.doReturn(ghRepository).when(repo).getGitHubRepo(); + Mockito.doNothing().when(repo).addComment(Mockito.anyInt(), Mockito.anyString(), any(AbstractBuild.class), any(TaskListener.class)); + - protected void setTriggerHelper(GhprbTrigger trigger, Ghprb ghprb) { - trigger.setHelper(ghprb); - } + builds = new GhprbBuilds(trigger, repo); - protected Ghprb spyCreatingGhprb(GhprbTrigger trigger, AbstractProject project) { + // Creating spy on ghprb, configuring repo + given(helper.getGitHub()).willReturn(ghprbGitHub); + given(helper.getRepository()).willReturn(repo); + given(helper.getTrigger()).willReturn(trigger); + given(helper.isWhitelisted(ghUser)).willReturn(true); + given(helper.getBuilds()).willReturn(builds); + + + Mockito.doCallRealMethod().when(helper).run(); - return Mockito.spy(trigger.createGhprb(project)); - } + // Configuring and adding Ghprb trigger + project.addTrigger(trigger); + + // Configuring Git SCM + GitSCM scm = GhprbTestUtil.provideGitSCM(); + project.setScm(scm); + + trigger.start(project, true); + trigger.setHelper(helper); + } } \ No newline at end of file diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 67a27ea48..942be3a71 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -117,6 +117,7 @@ public void beforeTest() throws Exception { Map> jobs = new HashMap>(1); jobs.put("project", pulls); + Mockito.doReturn(project).when(trigger).getActualProject(); Mockito.doReturn(pulls).when(trigger).getPulls(); Mockito.doReturn(repo).when(trigger).getRepository(); Mockito.doReturn(pr).when(repo).getPullRequest(pullId); @@ -159,7 +160,7 @@ public void beforeTest() throws Exception { jobsField.setAccessible(true); jobsField.set(descriptor, jobs); - helper = spy(new Ghprb(project, trigger)); + helper = spy(new Ghprb(trigger)); given(trigger.getPulls()).willReturn(pulls); trigger.setHelper(helper); given(helper.getRepository()).willReturn(repo); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 0d3eed1f2..637ee6de5 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -326,7 +326,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(ghPullRequest, times(1)).getTitle(); verify(ghPullRequest, times(8)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(5)).getHead(); + verify(ghPullRequest, times(6)).getHead(); verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(1)).getHtmlUrl(); @@ -416,7 +416,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(ghPullRequest, times(2)).getTitle(); verify(ghPullRequest, times(10)).getUser(); verify(ghPullRequest, times(2)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(5)).getHead(); + verify(ghPullRequest, times(6)).getHead(); verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(3)).getUpdatedAt(); @@ -522,15 +522,16 @@ public void testSignature() throws IOException, InvalidKeyException, NoSuchAlgor String actualSignature = createSHA1Signature(actualSecret, body); String fakeSignature = createSHA1Signature("abc", body); - GhprbGitHubAuth ghAuth = Mockito.mock(GhprbGitHubAuth.class); + GhprbGitHubAuth ghAuth = Mockito.spy(new GhprbGitHubAuth("", "", "", "", "", actualSecret)); + doReturn(true).when(trigger).isActive(); + doReturn(ghAuth).when(trigger).getGitHubApiAuth(); Assert.assertFalse(actualSignature.equals(fakeSignature)); + Assert.assertTrue(actualSecret.equals(ghAuth.getSecret())); - given(ghAuth.getSecret()).willReturn(actualSecret); - - Assert.assertTrue(trigger.getWebHook().checkSignature(body, actualSignature)); - Assert.assertFalse(trigger.getWebHook().checkSignature(body, fakeSignature)); + Assert.assertTrue(trigger.matchSignature(body, actualSignature)); + Assert.assertFalse(trigger.matchSignature(body, fakeSignature)); } private String createSHA1Signature(String secret, String body) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException { diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java index 4bfa0296d..095f3a1a1 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java @@ -97,13 +97,15 @@ public void testUrlEncoded() throws Exception { // GIVEN FreeStyleProject project = jenkinsRule.createFreeStyleProject("testUrlEncoded"); GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); + doReturn(project).when(trigger).getActualProject(); + given(commitPointer.getSha()).willReturn("sha1"); GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); given(ghPullRequest.getId()).willReturn(prId); given(ghPullRequest.getNumber()).willReturn(prId); given(ghRepository.getPullRequest(prId)).willReturn(ghPullRequest); - Ghprb ghprb = spy(trigger.createGhprb(project)); + Ghprb ghprb = spy(new Ghprb(trigger)); doReturn(ghprbGitHub).when(ghprb).getGitHub(); trigger.start(project, true); trigger.setHelper(ghprb); @@ -139,13 +141,15 @@ public void disabledJobsDontBuild() throws Exception { // GIVEN FreeStyleProject project = jenkinsRule.createFreeStyleProject("disabledJobsDontBuild"); GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); + doReturn(project).when(trigger).getActualProject(); + given(commitPointer.getSha()).willReturn("sha1"); GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); given(ghPullRequest.getId()).willReturn(prId); given(ghPullRequest.getNumber()).willReturn(prId); given(ghRepository.getPullRequest(prId)).willReturn(ghPullRequest); - Ghprb ghprb = spy(trigger.createGhprb(project)); + Ghprb ghprb = spy(new Ghprb(trigger)); doReturn(ghprbGitHub).when(ghprb).getGitHub(); trigger.start(project, true); trigger.setHelper(ghprb); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/manager/impl/GhprbDefaultBuildManagerTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/manager/impl/GhprbDefaultBuildManagerTest.java index 3045eb833..ed12d6ffc 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/manager/impl/GhprbDefaultBuildManagerTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/manager/impl/GhprbDefaultBuildManagerTest.java @@ -2,20 +2,16 @@ import static org.fest.assertions.Assertions.assertThat; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.doReturn; import java.util.HashMap; import java.util.Map; -import com.coravy.hudson.plugins.github.GithubProjectProperty; import hudson.matrix.MatrixBuild; import hudson.matrix.MatrixProject; -import org.jenkinsci.plugins.ghprb.Ghprb; import org.jenkinsci.plugins.ghprb.GhprbITBaseTestCase; import org.jenkinsci.plugins.ghprb.GhprbTestUtil; -import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.jenkinsci.plugins.ghprb.manager.GhprbBuildManager; import org.jenkinsci.plugins.ghprb.manager.factory.GhprbBuildManagerFactoryUtil; import org.junit.Before; @@ -33,17 +29,25 @@ public class GhprbDefaultBuildManagerTest extends GhprbITBaseTestCase { @Rule public JenkinsRule jenkinsRule = new JenkinsRule(); + + private MatrixProject project; @Before public void setUp() throws Exception { // GhprbTestUtil.mockGithubUserPage(); - super.beforeTest(); + project = jenkinsRule.createMatrixProject("MTXPRJ"); + + Map config = new HashMap(1); + + config.put("publishedURL", "defaultPublishedURL"); + super.beforeTest(config, null, project); } @Test public void shouldCalculateUrlFromDefault() throws Exception { + // GIVEN - MatrixProject project = givenThatGhprbHasBeenTriggeredForAMatrixProject(); + givenThatGhprbHasBeenTriggeredForAMatrixProject(); // THEN assertThat(project.getBuilds().toArray().length).isEqualTo(1); @@ -57,44 +61,14 @@ public void shouldCalculateUrlFromDefault() throws Exception { assertThat(buildManager.calculateBuildUrl("defaultPublishedURL")).isEqualTo("defaultPublishedURL/" + matrixBuild.getUrl()); } - private MatrixProject givenThatGhprbHasBeenTriggeredForAMatrixProject() throws Exception { - MatrixProject project = jenkinsRule.createMatrixProject("MTXPRJ"); - - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); - + private void givenThatGhprbHasBeenTriggeredForAMatrixProject() throws Exception { given(commitPointer.getSha()).willReturn("sha"); - Map config = new HashMap(1); - config.put("publishedURL", "defaultPublishedURL"); - - GhprbTestUtil.setupGhprbTriggerDescriptor(config); - - - project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); - given(ghPullRequest.getNumber()).willReturn(1); - // Creating spy on ghprb, configuring repo - Ghprb ghprb = spyCreatingGhprb(trigger, project); - - doReturn(ghprbGitHub).when(ghprb).getGitHub(); - - setRepositoryHelper(ghprb); - given(ghRepository.getPullRequest(1)).willReturn(ghPullRequest); - // Configuring and adding Ghprb trigger - project.addTrigger(trigger); - - // Configuring Git SCM - project.setScm(GhprbTestUtil.provideGitSCM()); - - trigger.start(project, true); - - setTriggerHelper(trigger, ghprb); - GhprbTestUtil.triggerRunAndWait(10, trigger, project); - return project; } } \ No newline at end of file diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/manager/impl/downstreambuilds/BuildFlowBuildManagerTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/manager/impl/downstreambuilds/BuildFlowBuildManagerTest.java index 99810ca93..603e3e650 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/manager/impl/downstreambuilds/BuildFlowBuildManagerTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/manager/impl/downstreambuilds/BuildFlowBuildManagerTest.java @@ -3,19 +3,15 @@ import static org.fest.assertions.Assertions.assertThat; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.doReturn; import com.cloudbees.plugins.flow.BuildFlow; import com.cloudbees.plugins.flow.FlowRun; import com.cloudbees.plugins.flow.JobInvocation; -import com.coravy.hudson.plugins.github.GithubProjectProperty; import java.util.Iterator; -import org.jenkinsci.plugins.ghprb.Ghprb; import org.jenkinsci.plugins.ghprb.GhprbITBaseTestCase; import org.jenkinsci.plugins.ghprb.GhprbTestUtil; -import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.jenkinsci.plugins.ghprb.manager.GhprbBuildManager; import org.jenkinsci.plugins.ghprb.manager.factory.GhprbBuildManagerFactoryUtil; import org.jenkinsci.plugins.ghprb.rules.JenkinsRuleWithBuildFlow; @@ -35,16 +31,39 @@ public class BuildFlowBuildManagerTest extends GhprbITBaseTestCase { @Rule public JenkinsRuleWithBuildFlow jenkinsRule = new JenkinsRuleWithBuildFlow(); + + private BuildFlow buildFlowProject; @Before public void setUp() throws Exception { - super.beforeTest(); + + buildFlowProject = jenkinsRule.createBuildFlowProject(); + + jenkinsRule.createFreeStyleProject("downstreamProject1"); + jenkinsRule.createFreeStyleProject("downstreamProject2"); + jenkinsRule.createFreeStyleProject("downstreamProject3"); + + StringBuilder dsl = new StringBuilder(); + + dsl.append("parallel ("); + dsl.append(" { build(\"downstreamProject1\") },"); + dsl.append(" { build(\"downstreamProject2\") }"); + dsl.append(")"); + dsl.append("{ build(\"downstreamProject3\") }"); + + buildFlowProject.setDsl(dsl.toString()); + + given(ghPullRequest.getNumber()).willReturn(1); + given(ghRepository.getPullRequest(1)).willReturn(ghPullRequest); + + super.beforeTest(null, null, buildFlowProject); } @Test public void shouldCalculateUrlWithDownstreamBuilds() throws Exception { // GIVEN - BuildFlow buildFlowProject = givenThatGhprbHasBeenTriggeredForABuildFlowProject(); + + GhprbTestUtil.triggerRunAndWait(10, trigger, buildFlowProject); // THEN assertThat(buildFlowProject.getBuilds().toArray().length).isEqualTo(1); @@ -84,55 +103,4 @@ public void shouldCalculateUrlWithDownstreamBuilds() throws Exception { assertThat(buildManager.calculateBuildUrl(null)).isEqualTo(expectedUrl.toString()); } - private BuildFlow givenThatGhprbHasBeenTriggeredForABuildFlowProject() throws Exception { - - BuildFlow buildFlowProject = jenkinsRule.createBuildFlowProject(); - - jenkinsRule.createFreeStyleProject("downstreamProject1"); - jenkinsRule.createFreeStyleProject("downstreamProject2"); - jenkinsRule.createFreeStyleProject("downstreamProject3"); - - StringBuilder dsl = new StringBuilder(); - - dsl.append("parallel ("); - dsl.append(" { build(\"downstreamProject1\") },"); - dsl.append(" { build(\"downstreamProject2\") }"); - dsl.append(")"); - dsl.append("{ build(\"downstreamProject3\") }"); - - buildFlowProject.setDsl(dsl.toString()); - - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); - - given(commitPointer.getSha()).willReturn("sha"); - GhprbTestUtil.setupGhprbTriggerDescriptor(null); - - buildFlowProject.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); - - given(ghPullRequest.getNumber()).willReturn(1); - - // Creating spy on ghprb, configuring repo - Ghprb ghprb = spyCreatingGhprb(trigger, buildFlowProject); - - doReturn(ghprbGitHub).when(ghprb).getGitHub(); - - setRepositoryHelper(ghprb); - - given(ghRepository.getPullRequest(1)).willReturn(ghPullRequest); - - // Configuring and adding Ghprb trigger - buildFlowProject.addTrigger(trigger); - - // Configuring Git SCM - buildFlowProject.setScm(GhprbTestUtil.provideGitSCM()); - - trigger.start(buildFlowProject, true); - - setTriggerHelper(trigger, ghprb); - - GhprbTestUtil.triggerRunAndWait(10, trigger, buildFlowProject); - - return buildFlowProject; - } - } From bb69fb67739f2e6b613eb63a1cfa3c3c5c80792b Mon Sep 17 00:00:00 2001 From: Daniel Spilker Date: Thu, 7 Jan 2016 09:47:44 +0100 Subject: [PATCH 122/175] added Job DSL support for GhprbPullRequestMerge publisher --- .../jobdsl/GhprbContextExtensionPoint.java | 16 ++++ .../jobdsl/GhprbPullRequestMergeContext.java | 74 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbPullRequestMergeContext.java diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java index f0f4f0ae5..a246c3d84 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java @@ -3,10 +3,12 @@ import antlr.ANTLRException; import com.google.common.base.Joiner; import hudson.Extension; +import javaposse.jobdsl.dsl.helpers.publisher.PublisherContext; import javaposse.jobdsl.dsl.helpers.triggers.TriggerContext; import javaposse.jobdsl.plugin.ContextExtensionPoint; import javaposse.jobdsl.plugin.DslExtensionMethod; import org.jenkinsci.plugins.ghprb.GhprbBranch; +import org.jenkinsci.plugins.ghprb.GhprbPullRequestMerge; import org.jenkinsci.plugins.ghprb.GhprbTrigger; import java.util.ArrayList; @@ -39,4 +41,18 @@ public Object githubPullRequest(Runnable closure) throws ANTLRException { context.extensionContext.extensions ); } + + @DslExtensionMethod(context = PublisherContext.class) + public Object mergeGithubPullRequest(Runnable closure) { + GhprbPullRequestMergeContext context = new GhprbPullRequestMergeContext(); + executeInContext(closure, context); + + return new GhprbPullRequestMerge( + context.mergeComment, + context.onlyAdminsMerge, + context.disallowOwnCode, + context.failOnNonMerge, + context.deleteOnMerge + ); + } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbPullRequestMergeContext.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbPullRequestMergeContext.java new file mode 100644 index 000000000..eead87e0b --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbPullRequestMergeContext.java @@ -0,0 +1,74 @@ +package org.jenkinsci.plugins.ghprb.jobdsl; + +import javaposse.jobdsl.dsl.Context; + +public class GhprbPullRequestMergeContext implements Context { + String mergeComment; + boolean onlyAdminsMerge; + boolean disallowOwnCode; + boolean failOnNonMerge; + boolean deleteOnMerge; + + /** + * Sets a comment that should show up when the merge command is sent to GitHub. + */ + public void mergeComment(String mergeComment) { + this.mergeComment = mergeComment; + } + + /** + * Allows only admin users to trigger a pull request merge. Defaults to {@code false}. + */ + public void onlyAdminsMerge(boolean onlyAdminsMerge) { + this.onlyAdminsMerge = onlyAdminsMerge; + } + + /** + * Allows only admin users to trigger a pull request merge. Defaults to {@code false}. + */ + public void onlyAdminsMerge() { + onlyAdminsMerge(true); + } + + /** + * Disallows a user to merge their own code. Defaults to {@code false}. + */ + public void disallowOwnCode(boolean disallowOwnCode) { + this.disallowOwnCode = disallowOwnCode; + } + + /** + * Disallows a user to merge their own code. Defaults to {@code false}. + */ + public void disallowOwnCode() { + disallowOwnCode(true); + } + + /** + * Fails the build if the pull request can't be merged. Defaults to {@code false}. + */ + public void failOnNonMerge(boolean failOnNonMerge) { + this.failOnNonMerge = failOnNonMerge; + } + + /** + * Fails the build if the pull request can't be merged. Defaults to {@code false}. + */ + public void failOnNonMerge() { + failOnNonMerge(true); + } + + /** + * Deletes the branch after a successful merge. Defaults to {@code false}. + */ + public void deleteOnMerge(boolean deleteOnMerge) { + this.deleteOnMerge = deleteOnMerge; + } + + /** + * Deletes the branch after a successful merge. Defaults to {@code false}. + */ + public void deleteOnMerge() { + deleteOnMerge(true); + } +} From e75db2112b1fcc90c8fdcb49bf193eab2fb49975 Mon Sep 17 00:00:00 2001 From: Daniel Spilker Date: Thu, 7 Jan 2016 09:47:57 +0100 Subject: [PATCH 123/175] added documentation for Job DSL syntax --- README.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/README.md b/README.md index c3ae18c2e..84871d934 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,64 @@ Make sure you **DON'T** have ``Prune remote branches before build`` advanced opt #### Parameterized Builds If you want to manually build the job, in the job setting check ``This build is parameterized`` and add string parameter named ``sha1`` with a default value of ``master``. When starting build give the ``sha1`` parameter commit id you want to build or refname (eg: ``origin/pr/9/head``). +### Job DSL Support + +Since the plugin contains an extension for the Job DSL plugin to add DSL syntax for configuring the build trigger and +the pull request merger post-build action. + +Here is an example showing all DSL syntax elements: + +```groovy +job('example') { + scm { + git { + remote { + github('test-owner/test-project') + refspec('+refs/pull/*:refs/remotes/origin/pr/*') + } + branch('${sha1}') + } + } + triggers { + githubPullRequest { + admin('user_1') + admins(['user_2', 'user_3']) + userWhitelist('you@you.com') + userWhitelist(['me@me.com', 'they@they.com']) + orgWhitelist('my_github_org') + orgWhitelist(['your_github_org', 'another_org']) + cron('H/5 * * * *') + triggerPhrase('OK to test') + onlyTriggerPhrase() + useGitHubHooks() + permitAll() + autoCloseFailedPullRequests() + allowMembersOfWhitelistedOrgsAsAdmin() + extensions { + commitStatus { + context('deploy to staging site') + triggeredStatus('starting deployment to staging site...') + startedStatus('deploying to staging site...') + statusUrl('http://mystatussite.com/prs') + completedStatus('SUCCESS', 'All is well') + completedStatus('FAILURE', 'Something went wrong. Investigate!') + completedStatus('PENDING', 'still in progress...') + completedStatus('ERROR', 'Something went really wrong. Investigate!') + } + } + } + } + publishers { + mergeGithubPullRequest { + mergeComment('merged by Jenkins') + onlyAdminsMerge() + disallowOwnCode() + failOnNonMerge() + deleteOnMerge() + } + } +} +``` ### Updates From f9b00a4f89b268beeca2551eecfcf5bffcacd959 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 7 Jan 2016 19:24:11 -0700 Subject: [PATCH 124/175] Update readme before release --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 84871d934..9f21be9c8 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,9 @@ job('example') { ### Updates +#### -> 1.29.8 +* Merged #246 adding job dsl features and updating docs + #### -> 1.29.7 * Remove quoting of trigger phrase * Merged #242 replaces newline and quoted quotes From f051159dd5fbe09d11dc381351257c9260d296bb Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 7 Jan 2016 19:27:51 -0700 Subject: [PATCH 125/175] [maven-release-plugin] prepare release ghprb-1.29.8 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9d128cd63..f78d28640 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30-SNAPSHOT + 1.29.8 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.29.8 From e83c34537bd5ca97a475a57fc57f5a7b843f318a Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 7 Jan 2016 19:27:54 -0700 Subject: [PATCH 126/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f78d28640..9d128cd63 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.29.8 + 1.30-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.29.8 + HEAD From 41ebd057fffe2da63ad2df170d6b9bdaa0a37ee5 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 11 Jan 2016 21:34:00 -0700 Subject: [PATCH 127/175] Keep track of jobs that are using webhooks and refer to that instead of trying to find them in all of the jobs --- .../plugins/ghprb/GhprbRootAction.java | 31 +++------ .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 64 +++++++++++++++---- .../org/jenkinsci/plugins/ghprb/GhprbIT.java | 5 ++ .../plugins/ghprb/GhprbRootActionTest.java | 7 +- 4 files changed, 70 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 2d917a2d4..d33aa15c1 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -3,12 +3,8 @@ import hudson.Extension; import hudson.model.AbstractProject; import hudson.model.UnprotectedRootAction; -import hudson.security.ACL; import hudson.security.csrf.CrumbExclusion; -import jenkins.model.Jenkins; -import org.acegisecurity.Authentication; -import org.acegisecurity.context.SecurityContextHolder; import org.apache.commons.io.IOUtils; import org.kohsuke.github.GHEventPayload.IssueComment; import org.kohsuke.github.GHEventPayload.PullRequest; @@ -165,28 +161,19 @@ private String extractRequestBody(StaplerRequest req) { } private Set getTriggers(String repoName, String body, String signature) { - final Set triggers = new HashSet(5); - // We need this to get access to list of repositories - Authentication old = SecurityContextHolder.getContext().getAuthentication(); - SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); - - try { - for (AbstractProject job : Jenkins.getInstance().getAllItems(AbstractProject.class)) { - GhprbTrigger trigger = job.getTrigger(GhprbTrigger.class); - if (trigger == null || !(trigger.matchRepo(repoName) && trigger.matchSignature(body, signature))) { - continue; + Set triggers = new HashSet(); + + Set> projects = GhprbTrigger.getDscp().getRepoTriggers(repoName); + if (projects != null) { + for (AbstractProject project : projects) { + GhprbTrigger trigger = Ghprb.extractTrigger(project); + if (trigger.matchSignature(body, signature)) { + triggers.add(trigger); } - triggers.add(trigger); } - } finally { - SecurityContextHolder.getContext().setAuthentication(old); } - - if (triggers.isEmpty()) { - logger.log(Level.WARNING, "No projects found using GitHub pull request trigger"); - } - return triggers; + } @Extension diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 3b09eccf7..1f6bea2bf 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -47,9 +47,12 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; @@ -106,7 +109,6 @@ private void setExtensions(List extensions) { } @DataBoundConstructor - public GhprbTrigger(String adminlist, String whitelist, String orgslist, @@ -213,7 +215,10 @@ public void start(AbstractProject project, boolean newInstance) { logger.log(Level.INFO, "Starting the ghprb trigger for the {0} job; newInstance is {1}", new String[] { name, String.valueOf(newInstance) }); helper.init(); - + + if (getUseGitHubHooks()) { + DESCRIPTOR.addRepoTrigger(getRepository().getName(), super.job); + } } public ConcurrentMap getPulls() { @@ -225,6 +230,13 @@ public void stop() { String name = super.job != null ? super.job.getFullName(): "NOT STARTED"; logger.log(Level.INFO, "Stopping the ghprb trigger for project {0}", name); if (helper != null) { + GhprbRepository repository = getRepository(); + if (repository != null) { + String repo = repository.getName(); + if (!StringUtils.isEmpty(repo)) { + DESCRIPTOR.removeRepoTrigger(repo, super.job); + } + } helper.stop(); helper = null; } @@ -503,16 +515,7 @@ public String getProjectName() { return projectName; } - public boolean matchRepo(String hookRepoName) { - if (!isActive()) { - return false; - } - String repo = getRepository().getName(); - - logger.log(Level.FINE, "Comparing repository names: {0} to {1}, case is ignored", new Object[] { repo, hookRepoName }); - return repo.equalsIgnoreCase(hookRepoName); - } - + public boolean matchSignature(String body, String signature) { if (!isActive()) { return false; @@ -605,6 +608,12 @@ public List getDefaultAuth(List githubAuth) { // map of jobs (by their fullName) and their map of pull requests private Map> jobs; + /** + * map of jobs (by the repo name); No need to keep the projects from shutdown to startup. + * New triggers will register here, and ones that are stopping will remove themselves. + */ + private transient Map>> repoJobs; + public List getExtensionDescriptors() { return GhprbExtensionDescriptor.allProject(); } @@ -625,6 +634,9 @@ public DescribableList getExtensions() public DescriptorImpl() { load(); readBackFromLegacy(); + if (repoJobs == null) { + repoJobs = new ConcurrentHashMap>>(); + } if (jobs == null) { jobs = new HashMap>(); } @@ -785,6 +797,34 @@ public ConcurrentMap getPullRequests(String projectNa } return ret; } + + private void addRepoTrigger(String repo, AbstractProject project) { + if (project == null) { + return; + } + + Set> projects = repoJobs.get(repo); + if (projects == null) { + projects = Collections.newSetFromMap(new WeakHashMap, Boolean>()); + repoJobs.put(repo, projects); + } + + projects.add(project); + } + + private void removeRepoTrigger(String repo, AbstractProject project) { + Set> projects = repoJobs.get(repo); + if (project != null && projects != null) { + projects.remove(project); + } + } + + public Set> getRepoTriggers(String repo) { + if (repoJobs == null) { + repoJobs = new ConcurrentHashMap>>(5); + } + return repoJobs.get(repo); + } public List getWhiteListTargetBranches() { return whiteListTargetBranches; diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java index d1fcf7e3d..074a4f49e 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java @@ -102,5 +102,10 @@ public void shouldNotBuildDisabledBuild() throws Exception { Mockito.verify(ghRepository, Mockito.times(0)).createCommitStatus(any(String.class), any(GHCommitState.class), any(String.class), any(String.class)); } + + @Test + public void triggerIsRemovedFromListWhenProjectChanges() { + + } } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java index 095f3a1a1..a3084b23c 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java @@ -96,8 +96,9 @@ public void setup() throws Exception { public void testUrlEncoded() throws Exception { // GIVEN FreeStyleProject project = jenkinsRule.createFreeStyleProject("testUrlEncoded"); - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); + GhprbTrigger trigger = GhprbTestUtil.getTrigger(); doReturn(project).when(trigger).getActualProject(); + doReturn(true).when(trigger).getUseGitHubHooks(); given(commitPointer.getSha()).willReturn("sha1"); GhprbTestUtil.setupGhprbTriggerDescriptor(null); @@ -116,7 +117,7 @@ public void testUrlEncoded() throws Exception { GhprbTestUtil.triggerRunAndWait(10, trigger, project); - assertThat(project.getBuilds().toArray().length).isEqualTo(1); + assertThat(project.getBuilds().toArray().length).isEqualTo(0); doReturn(gitHub).when(trigger).getGitHub(); @@ -133,7 +134,7 @@ public void testUrlEncoded() throws Exception { ra.doIndex(req, null); GhprbTestUtil.waitForBuildsToFinish(project); - assertThat(project.getBuilds().toArray().length).isEqualTo(2); + assertThat(project.getBuilds().toArray().length).isEqualTo(1); } @Test From e0d44239a64d7d1ee24f1d863d69379dab137248 Mon Sep 17 00:00:00 2001 From: Eric Tam Date: Mon, 11 Jan 2016 23:51:30 -0800 Subject: [PATCH 128/175] Added Upstream commit statuses DSL for GHPRB --- .../jobdsl/GhprbContextExtensionPoint.java | 20 ++++++- .../ghprb/jobdsl/GhprbTriggerContext.java | 35 +++++++++++- .../jobdsl/GhprbUpstreamStatusContext.java | 55 +++++++++++++++++++ 3 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbUpstreamStatusContext.java diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java index a246c3d84..fd6bc2a40 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java @@ -5,11 +5,13 @@ import hudson.Extension; import javaposse.jobdsl.dsl.helpers.publisher.PublisherContext; import javaposse.jobdsl.dsl.helpers.triggers.TriggerContext; +import javaposse.jobdsl.dsl.helpers.wrapper.WrapperContext; import javaposse.jobdsl.plugin.ContextExtensionPoint; import javaposse.jobdsl.plugin.DslExtensionMethod; import org.jenkinsci.plugins.ghprb.GhprbBranch; import org.jenkinsci.plugins.ghprb.GhprbPullRequestMerge; import org.jenkinsci.plugins.ghprb.GhprbTrigger; +import org.jenkinsci.plugins.ghprb.upstream.GhprbUpstreamStatus; import java.util.ArrayList; @@ -29,9 +31,9 @@ public Object githubPullRequest(Runnable closure) throws ANTLRException { context.useGitHubHooks, context.permitAll, context.autoCloseFailedPullRequests, + context.displayBuildErrorsOnDownstreamBuilds, null, - null, - new ArrayList(), + context.whiteListTargetBranches, context.allowMembersOfWhitelistedOrgsAsAdmin, null, null, @@ -55,4 +57,18 @@ public Object mergeGithubPullRequest(Runnable closure) { context.deleteOnMerge ); } + + @DslExtensionMethod(context = WrapperContext.class) + public Object downstreamCommitStatus(Runnable closure) { + GhprbUpstreamStatusContext context = new GhprbUpstreamStatusContext(); + executeInContext(closure, context); + + return new GhprbUpstreamStatus( + context.context, + context.statusUrl, + context.triggeredStatus, + context.startedStatus, + context.completedStatus + ); + } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbTriggerContext.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbTriggerContext.java index d4fc4ccca..0e6638bdf 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbTriggerContext.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbTriggerContext.java @@ -1,8 +1,8 @@ package org.jenkinsci.plugins.ghprb.jobdsl; import javaposse.jobdsl.dsl.Context; -import javaposse.jobdsl.dsl.helpers.triggers.GitHubPullRequestBuilderExtensionContext; import javaposse.jobdsl.plugin.ContextExtensionPoint; +import org.jenkinsci.plugins.ghprb.GhprbBranch; import java.util.ArrayList; import java.util.List; @@ -11,6 +11,7 @@ class GhprbTriggerContext implements Context { List admins = new ArrayList(); List userWhitelist = new ArrayList(); List orgWhitelist = new ArrayList(); + List whiteListTargetBranches = new ArrayList(); String cron = "H/5 * * * *"; String triggerPhrase; boolean onlyTriggerPhrase; @@ -18,6 +19,7 @@ class GhprbTriggerContext implements Context { boolean permitAll; boolean autoCloseFailedPullRequests; boolean allowMembersOfWhitelistedOrgsAsAdmin; + boolean displayBuildErrorsOnDownstreamBuilds; GhprbExtensionContext extensionContext = new GhprbExtensionContext(); /** @@ -68,6 +70,23 @@ public void orgWhitelist(Iterable organizations) { } } + + /** + * Add branch names whose they are considered whitelisted for this specific job + */ + public void whiteListTargetBranch(String branch) { + whiteListTargetBranches.add(new GhprbBranch(branch)); + } + + /** + * Add branch names whose they are considered whitelisted for this specific job + */ + public void whiteListTargetBranches(Iterable branches) { + for (String branch : branches) { + whiteListTargetBranches.add(new GhprbBranch(branch)); + } + } + /** * This schedules polling to GitHub for new changes in pull requests. */ @@ -152,6 +171,20 @@ public void allowMembersOfWhitelistedOrgsAsAdmin() { allowMembersOfWhitelistedOrgsAsAdmin(true); } + /** + * Allow this upstream job to get commit statuses from downstream builds + */ + public void displayBuildErrorsOnDownstreamBuilds(boolean displayBuildErrorsOnDownstreamBuilds) { + this.displayBuildErrorsOnDownstreamBuilds = displayBuildErrorsOnDownstreamBuilds; + } + + /** + * Allow this upstream job to get commit statuses from downstream builds + */ + public void displayBuildErrorsOnDownstreamBuilds() { + displayBuildErrorsOnDownstreamBuilds(true); + } + /** * Adds additional trigger options. */ diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbUpstreamStatusContext.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbUpstreamStatusContext.java new file mode 100644 index 000000000..899ae2c85 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbUpstreamStatusContext.java @@ -0,0 +1,55 @@ +package org.jenkinsci.plugins.ghprb.jobdsl; + +import javaposse.jobdsl.dsl.Context; +import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; +import org.kohsuke.github.GHCommitState; + +import java.util.ArrayList; +import java.util.List; + +class GhprbUpstreamStatusContext implements Context { + String context; + String triggeredStatus; + String startedStatus; + String statusUrl; + List completedStatus = new ArrayList(); + + /** + * A string label to differentiate this status from the status of other systems. + */ + void context(String context) { + this.context = context; + } + + /** + * Use a custom status for when a build is triggered. + */ + void triggeredStatus(String triggeredStatus) { + this.triggeredStatus = triggeredStatus; + } + + /** + * Use a custom status for when a build is started. + */ + void startedStatus(String startedStatus) { + this.startedStatus = startedStatus; + } + + /** + * Use a custom URL instead of the job default. + */ + void statusUrl(String statusUrl) { + this.statusUrl = statusUrl; + } + + /** + * Use a custom status for when a build is completed. Can be called multiple times to set messages for different + * build results. Valid build results are {@code 'SUCCESS'}, {@code 'FAILURE'}, and {@code 'ERROR'}. + */ + void completedStatus(String buildResult, String message) { + completedStatus.add(new GhprbBuildResultMessage( + GHCommitState.valueOf(buildResult), + message + )); + } +} From f27dbc9344e749e93b002f7e3a557b5da23e4e1f Mon Sep 17 00:00:00 2001 From: Eric Tam Date: Tue, 12 Jan 2016 00:10:23 -0800 Subject: [PATCH 129/175] Updated README for downstream commit status for GHPRB --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f21be9c8..c5f0c17aa 100644 --- a/README.md +++ b/README.md @@ -110,10 +110,13 @@ If you want to manually build the job, in the job setting check ``This build is Since the plugin contains an extension for the Job DSL plugin to add DSL syntax for configuring the build trigger and the pull request merger post-build action. +It is also possible to set Downstream job commit statuses when `displayBuildErrorsOnDownstreamBuilds()` is set in the +upstream job's triggers and downstreamCommitStatus block is included in the downstream job's wrappers. + Here is an example showing all DSL syntax elements: ```groovy -job('example') { +job('upstreamJob') { scm { git { remote { @@ -123,6 +126,7 @@ job('example') { branch('${sha1}') } } + triggers { githubPullRequest { admin('user_1') @@ -137,6 +141,8 @@ job('example') { useGitHubHooks() permitAll() autoCloseFailedPullRequests() + displayBuildErrorsOnDownstreamBuilds() + whiteListTargetBranches(['master','test', 'test2']) allowMembersOfWhitelistedOrgsAsAdmin() extensions { commitStatus { @@ -162,6 +168,20 @@ job('example') { } } } + +job('downstreamJob') { + wrappers { + downstreamCommitStatus { + context('CONTEXT NAME') + triggeredStatus("The job has triggered") + startedStatus("The job has started") + statusUrl() + completedStatus('SUCCESS', "The job has passed") + completedStatus('FAILURE', "The job has failed") + completedStatus('ERROR', "The job has resulted in an error") + } + } +} ``` ### Updates From 48df0797f53b1542859455fdefa13d5ccf0e3bcb Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 15 Jan 2016 12:28:39 +0100 Subject: [PATCH 130/175] Fixed NPE when no build result is set --- .../jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java index 84c54be83..d462c6328 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/upstream/GhprbUpstreamStatus.java @@ -39,7 +39,7 @@ public void makeBuildVariables(@SuppressWarnings("rawtypes") AbstractBuild build Map statusMessages = new HashMap(5); - for (GhprbBuildResultMessage message : completedStatus) { + for (GhprbBuildResultMessage message : getCompletedStatus()) { GHCommitState state = message.getResult(); StringBuilder sb; if (!statusMessages.containsKey(state)) { From 5935ebff1fb458002018781b969b66c40e52cb35 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 22 Jan 2016 12:52:19 -0700 Subject: [PATCH 131/175] Work on cleaning out variables that aren't really needed. Remove init call for the PR when starting jenkins. Only get new PR data when needed, otherwise use what we have. Fix synchronization issue with adding multiple projects using the same repo --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 9 +- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 15 +- .../jenkinsci/plugins/ghprb/GhprbGitHub.java | 9 +- .../plugins/ghprb/GhprbGitHubAuth.java | 15 +- .../plugins/ghprb/GhprbPullRequest.java | 191 +++++++++++------- .../plugins/ghprb/GhprbRepository.java | 148 +++++++------- .../plugins/ghprb/GhprbRootAction.java | 12 +- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 38 +++- .../GhprbTriggerBackwardsCompatible.java | 4 + .../org/jenkinsci/plugins/ghprb/GhprbIT.java | 1 + .../plugins/ghprb/GhprbITBaseTestCase.java | 8 +- .../ghprb/GhprbPullRequestMergeTest.java | 2 +- .../plugins/ghprb/GhprbPullRequestTest.java | 5 +- .../plugins/ghprb/GhprbRepositoryTest.java | 52 +++-- .../plugins/ghprb/GhprbRootActionTest.java | 50 +++-- .../plugins/ghprb/GhprbTestUtil.java | 9 +- 16 files changed, 337 insertions(+), 231 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 427161005..650ecc213 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -57,6 +57,8 @@ public class Ghprb { private final GhprbTrigger trigger; private GhprbRepository repository; private GhprbBuilds builds; + + private transient GhprbGitHub github; public Ghprb(GhprbTrigger trigger) { @@ -74,7 +76,7 @@ public Ghprb(GhprbTrigger trigger) { this.trigger = trigger; - this.repository = new GhprbRepository(user, repo, this); + this.repository = new GhprbRepository(user, repo, trigger); this.builds = new GhprbBuilds(trigger, repository); } @@ -107,7 +109,10 @@ public GhprbRepository getRepository() { } public GhprbGitHub getGitHub() { - return new GhprbGitHub(trigger); + if (github == null) { + github = new GhprbGitHub(trigger); + } + return github; } void run() { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 426bef663..2507f795a 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.PrintStream; +import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; @@ -39,6 +40,16 @@ public GhprbBuilds(GhprbTrigger trigger, GhprbRepository repo) { } public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) { + + URL url = null; + GHUser prAuthor = null; + + try { + url = pr.getUrl(); + prAuthor = pr.getPullRequestAuthor(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to get PR author or PR URL", e); + } GhprbCause cause = new GhprbCause(pr.getHead(), pr.getId(), @@ -47,11 +58,11 @@ public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) pr.getSource(), pr.getAuthorEmail(), pr.getTitle(), - pr.getUrl(), + url, triggerSender, commentBody, pr.getCommitAuthor(), - pr.getPullRequestAuthor(), + prAuthor, pr.getDescription(), pr.getAuthorRepoGitUrl()); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHub.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHub.java index 625dcf4da..7b22bfd14 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHub.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHub.java @@ -6,7 +6,6 @@ import org.kohsuke.github.GHOrganization; import org.kohsuke.github.GHUser; -import org.kohsuke.github.GitHub; /** * @author janinko @@ -19,14 +18,10 @@ public GhprbGitHub(GhprbTrigger trigger) { this.trigger = trigger; } - public GitHub get() throws IOException { - return trigger.getGitHub(); - } - public boolean isUserMemberOfOrganization(String organisation, GHUser member) { boolean orgHasMember = false; try { - GHOrganization org = get().getOrganization(organisation); + GHOrganization org = trigger.getGitHub().getOrganization(organisation); orgHasMember = org.hasMember(member); logger.log(Level.FINE, "org.hasMember(member)? user:{0} org: {1} == {2}", new Object[] { member.getLogin(), organisation, orgHasMember ? "yes" : "no" }); @@ -40,7 +35,7 @@ public boolean isUserMemberOfOrganization(String organisation, GHUser member) { public String getBotUserLogin() { try { - return get().getMyself().getLogin(); + return trigger.getGitHub().getMyself().getLogin(); } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); return null; diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java index e72a50ff2..3a93e4938 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java @@ -62,6 +62,8 @@ public class GhprbGitHubAuth extends AbstractDescribableImpl { private final String id; private final String description; private final String secret; + + private transient GitHub gh; @DataBoundConstructor public GhprbGitHubAuth( @@ -181,19 +183,24 @@ private static GitHubBuilder getBuilder(Item context, String serverAPIUrl, Strin } return builder; } - - public GitHub getConnection(Item context) throws IOException { - GitHub gh = null; + + private void buildConnection(Item context) { GitHubBuilder builder = getBuilder(context, serverAPIUrl, credentialsId); if (builder == null) { logger.log(Level.SEVERE, "Unable to get builder using credentials: {0}", credentialsId); - return null; + return; } try { gh = builder.build(); } catch (IOException e) { logger.log(Level.SEVERE, "Unable to connect using credentials: " + credentialsId, e); } + } + + public GitHub getConnection(Item context) throws IOException { + if (gh == null) { + buildConnection(context); + } return gh; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 780b05928..76834642c 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -33,63 +33,63 @@ public class GhprbPullRequest { @Deprecated @SuppressWarnings("unused") private transient String authorEmail; @Deprecated @SuppressWarnings("unused") private transient URL url; @Deprecated @SuppressWarnings("unused") private transient String description; + @Deprecated @SuppressWarnings("unused") private transient String target; + @Deprecated @SuppressWarnings("unused") private transient String source; + @Deprecated @SuppressWarnings("unused") private transient String authorRepoGitUrl; - private final int id; - - private Date updated; // Needed to track when the PR was updated - private String target; - private String source; - private String head; - - private boolean accepted = false; // Needed to see if the PR has been added to the accepted list - - - private transient String authorRepoGitUrl; // Can be refreshed as needed. private transient Ghprb helper; // will be refreshed each time GhprbRepository.init() is called private transient GhprbRepository repo; // will be refreshed each time GhprbRepository.init() is called - private transient GHPullRequest pr; // will be refreshed each time GhprbRepository.init() is called + + private transient GHPullRequest pr; private transient GHUser triggerSender; // Only needed for a single build private transient GitUser commitAuthor; // Only needed for a single build + private transient String commentBody; private transient boolean shouldRun = false; // Declares if we should run the build this time. private transient boolean triggered = false; // Only lets us know if the trigger phrase was used for this run private transient boolean mergeable = false; // Only works as an easy way to pass the value around for the start of this build - private String commentBody; + + private final int id; + private Date updated; // Needed to track when the PR was updated + private String head; + private boolean accepted = false; // Needed to see if the PR has been added to the accepted list - public GhprbPullRequest(GHPullRequest pr, Ghprb helper, GhprbRepository repo) { + + public GhprbPullRequest(GHPullRequest pr, Ghprb ghprb, GhprbRepository repo) { id = pr.getNumber(); + this.pr = pr; + + this.helper = ghprb; + + this.repo = repo; + try { updated = pr.getUpdatedAt(); } catch (IOException e) { - e.printStackTrace(); + logger.log(Level.WARNING, "Unable to get date for new PR", e); updated = new Date(); } + GHCommitPointer prHead = pr.getHead(); head = prHead.getSha(); - source = prHead.getRef(); - target = pr.getBase().getRef(); - this.pr = pr; - - this.helper = helper; - this.repo = repo; GHUser author = pr.getUser(); String reponame = repo.getName(); - if (prHead != null && prHead.getRepository() != null) { - authorRepoGitUrl = prHead.getRepository().gitHttpTransportUrl(); - } - - if (helper.isWhitelisted(getPullRequestAuthor())) { - accepted = true; - shouldRun = true; - } else { - logger.log(Level.INFO, "Author of #{0} {1} on {2} not in whitelist!", new Object[] { id, author.getLogin(), reponame }); - repo.addComment(id, GhprbTrigger.getDscp().getRequestForTestingPhrase()); + try { + if (ghprb.isWhitelisted(getPullRequestAuthor())) { + accepted = true; + shouldRun = true; + } else { + logger.log(Level.INFO, "Author of #{0} {1} on {2} not in whitelist!", new Object[] { id, author.getLogin(), reponame }); + repo.addComment(id, GhprbTrigger.getDscp().getRequestForTestingPhrase()); + } + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to get pull request author", e); } logger.log(Level.INFO, "Created Pull Request #{0} on {1} by {2} ({3}) updated at: {4} SHA: {5}", @@ -97,33 +97,36 @@ public GhprbPullRequest(GHPullRequest pr, Ghprb helper, GhprbRepository repo) { ); } - public void init(Ghprb helper, GhprbRepository repo) throws IOException { + public void init(Ghprb helper, GhprbRepository repo) { this.helper = helper; this.repo = repo; - pr = repo.getPullRequest(id); - - GHCommitPointer prHead = pr.getHead(); - - if (prHead != null && prHead.getRepository() != null) { - authorRepoGitUrl = prHead.getRepository().gitHttpTransportUrl(); - } } /** * Checks this Pull Request representation against a GitHub version of the Pull Request, and triggers a build if necessary. * - * @param pr + * @param ghpr */ - public void check(GHPullRequest pr) { + public void check(GHPullRequest ghpr) { + if (ghpr != null) { + this.pr = ghpr; + } if (helper.isProjectDisabled()) { logger.log(Level.FINE, "Project is disabled, ignoring pull request"); return; } + + try { + getPullRequest(false); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to get the latest copy of the PR from github", e); + return; + } updatePR(pr, pr.getUser()); checkSkipBuild(pr); - tryBuild(pr); + tryBuild(); } private void checkSkipBuild(GHIssue issue) { @@ -139,29 +142,35 @@ public void check(GHIssueComment comment) { logger.log(Level.FINE, "Project is disabled, ignoring comment"); return; } + try { checkComment(comment); } catch (IOException ex) { logger.log(Level.SEVERE, "Couldn't check comment #" + comment.getId(), ex); return; } - - GHPullRequest pr = null; try { - pr = repo.getPullRequest(id); - updatePR(pr, comment.getUser()); - } catch (IOException e) { - logger.log(Level.SEVERE, "Couldn't get GHPullRequest for checking mergeable state"); + GHUser user = null; + try { + user = comment.getUser(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Couldn't get the user that made the comment", e); + } + updatePR(getPullRequest(true), user); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Unable to get a new copy of the pull request!"); } + checkSkipBuild(comment.getParent()); - tryBuild(pr); + tryBuild(); } private void updatePR(GHPullRequest pr, GHUser user) { + this.pr = pr; Date lastUpdateTime = updated; - if (pr != null && isUpdated(pr)) { + if (isUpdated(pr)) { logger.log(Level.INFO, "Pull request #{0} was updated on {1} at {2} by {3}", new Object[] { id, repo.getName(), updated, user }); // the author of the PR could have been whitelisted since its creation @@ -203,9 +212,6 @@ public boolean isWhiteListedTargetBranch() { } private boolean isUpdated(GHPullRequest pr) { - if (pr == null) { - return false; - } Date lastUpdated = new Date(); boolean ret = false; try { @@ -221,7 +227,7 @@ private boolean isUpdated(GHPullRequest pr) { return ret; } - private void tryBuild(GHPullRequest pr) { + private void tryBuild() { if (helper.isProjectDisabled()) { logger.log(Level.FINEST, "Project is disabled, not trying to build"); shouldRun = false; @@ -231,15 +237,19 @@ private void tryBuild(GHPullRequest pr) { logger.log(Level.FINEST, "Trigger only phrase but we are not triggered"); shouldRun = false; } + triggered = false; // Once we have decided that we are triggered then the flag should be set to false. + if (!isWhiteListedTargetBranch()) { + logger.log(Level.FINEST, "Branch is not whitelisted, skipping the build"); return; } if (shouldRun) { + shouldRun = false; // Change the shouldRun flag as soon as we decide to build. logger.log(Level.FINEST, "Running the build"); if (pr != null) { logger.log(Level.FINEST, "PR is not null, checking if mergable"); - checkMergeable(pr); + checkMergeable(); try { for (GHPullRequestCommitDetail commitDetails : pr.listCommits()) { if (commitDetails.getSha().equals(getHead())) { @@ -255,9 +265,6 @@ private void tryBuild(GHPullRequest pr) { logger.log(Level.FINEST, "Running build..."); build(); - - shouldRun = false; - triggered = false; } } @@ -281,7 +288,8 @@ private boolean checkCommit(GHCommitPointer sha) { private void checkComment(GHIssueComment comment) throws IOException { GHUser sender = comment.getUser(); String body = comment.getBody(); - GHUser author = pr.getUser(); + + logger.log(Level.FINEST, "[{0}] Added comment: {1}", new Object[]{sender.getName(), body}); // Disabled until more advanced configs get set up // ignore comments from bot user, this fixes an issue where the bot would auto-whitelist @@ -293,6 +301,8 @@ private void checkComment(GHIssueComment comment) throws IOException { // } if (helper.isWhitelistPhrase(body) && helper.isAdmin(sender)) { // add to whitelist + GHIssue parent = comment.getParent(); + GHUser author = parent.getUser(); if (!helper.isWhitelisted(author)) { logger.log(Level.FINEST, "Author {0} not whitelisted, adding to whitelist.", author); helper.addWhitelist(author.getLogin()); @@ -331,11 +341,14 @@ private void checkComment(GHIssueComment comment) throws IOException { } } - private int checkComments(GHPullRequest pr, Date lastUpdatedTime) { + private int checkComments(GHPullRequest ghpr, Date lastUpdatedTime) { int count = 0; + logger.log(Level.FINEST, "Checking for comments after: {0}", lastUpdatedTime); try { - for (GHIssueComment comment : pr.getComments()) { + for (GHIssueComment comment : ghpr.getComments()) { + logger.log(Level.FINEST, "Comment was made at: {0}", comment.getUpdatedAt()); if (lastUpdatedTime.compareTo(comment.getUpdatedAt()) < 0) { + logger.log(Level.FINEST, "Comment was made after last update time, {0}", comment.getBody()); count++; try { checkComment(comment); @@ -350,7 +363,13 @@ private int checkComments(GHPullRequest pr, Date lastUpdatedTime) { return count; } - public boolean checkMergeable(GHPullRequest pr) { + public boolean checkMergeable() { + try { + getPullRequest(false); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to get a copy of the PR from github", e); + return mergeable; + } try { int r = 5; Boolean isMergeable = pr.getMergeable(); @@ -361,7 +380,6 @@ public boolean checkMergeable(GHPullRequest pr) { break; } isMergeable = pr.getMergeable(); - pr = repo.getPullRequest(id); } mergeable = isMergeable != null && isMergeable; } catch (IOException e) { @@ -395,6 +413,12 @@ public String getHead() { } public String getAuthorRepoGitUrl() { + GHCommitPointer prHead = pr.getHead(); + String authorRepoGitUrl = ""; + + if (prHead != null && prHead.getRepository() != null) { + authorRepoGitUrl = prHead.getRepository().gitHttpTransportUrl(); + } return authorRepoGitUrl; } @@ -403,16 +427,24 @@ public boolean isMergeable() { } public String getTarget() { - return target; + try { + return getPullRequest(false).getBase().getRef(); + } catch (IOException e) { + return "UNKNOWN"; + } } public String getSource() { - return source; + try { + return getPullRequest(false).getHead().getRef(); + } catch (IOException e) { + return "UNKNOWN"; + } } public String getAuthorEmail() { try { - return pr.getUser().getEmail(); + return getPullRequest(false).getUser().getEmail(); } catch (IOException e) { logger.log(Level.SEVERE, "Unable to fetch author info for " + id); } @@ -420,31 +452,44 @@ public String getAuthorEmail() { } public String getTitle() { - return pr.getTitle(); + try { + return getPullRequest(false).getTitle(); + } catch (IOException e) { + return "UNKNOWN"; + } } /** * Returns the URL to the Github Pull Request. * * @return the Github Pull Request URL + * @throws IOException */ - public URL getUrl() { - return pr.getHtmlUrl(); + public URL getUrl() throws IOException { + return getPullRequest(false).getHtmlUrl(); } public GitUser getCommitAuthor() { return commitAuthor; } - public GHUser getPullRequestAuthor() { - return pr.getUser(); + public GHUser getPullRequestAuthor() throws IOException { + return getPullRequest(false).getUser(); } + - public GHPullRequest getPullRequest() { + public GHPullRequest getPullRequest(boolean force) throws IOException { + if (this.pr == null || force) { + this.pr = repo.getPullRequest(this.id); + } return pr; } public String getDescription() { - return pr.getBody(); + try { + return getPullRequest(false).getBody(); + } catch (IOException e) { + return "UNKNOWN"; + } } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index f8ba66267..4e9ef0371 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -1,7 +1,5 @@ package org.jenkinsci.plugins.ghprb; -import com.google.common.annotations.VisibleForTesting; - import hudson.model.AbstractBuild; import hudson.model.TaskListener; import jenkins.model.Jenkins; @@ -35,102 +33,98 @@ public class GhprbRepository { private final String reponame; private GHRepository ghRepository; - private Ghprb helper; + private GhprbTrigger trigger; - public GhprbRepository(String user, String repository, Ghprb helper) { + public GhprbRepository(String user, String repository, GhprbTrigger trigger) { this.reponame = user + "/" + repository; - this.helper = helper; + this.trigger = trigger; } public void init() { // make the initial check call to populate our data structures - if (!initGhRepository()) { - // We could have hit the rate limit while initializing. If we - // continue, then we will loop back around and attempt to re-init. - return; - } + initGhRepository(); - for (Entry next : helper.getTrigger().getPulls().entrySet()) { + for (Entry next : trigger.getPulls().entrySet()) { GhprbPullRequest pull = next.getValue(); - try { - pull.init(helper, this); - } catch (IOException e) { - logger.log(Level.SEVERE, "Unable to initialize pull request #{0} for repo {1}, job {2}", new Object[]{next.getKey(), reponame, helper.getTrigger().getActualProject().getFullName()}); - e.printStackTrace(); - } + pull.init(trigger.getHelper(), this); } } private boolean initGhRepository() { + if (ghRepository != null) { + return true; + } + GitHub gitHub = null; + + try { + gitHub = trigger.getGitHub(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Error while accessing rate limit API", ex); + return false; + } + + if (gitHub == null) { + logger.log(Level.SEVERE, "No connection returned to GitHub server!"); + return false; + } + try { - GhprbGitHub repo = helper.getGitHub(); - if (repo == null) { - return false; - } - gitHub = repo.get(); - if (gitHub == null) { - logger.log(Level.SEVERE, "No connection returned to GitHub server!"); - return false; - } if (gitHub.getRateLimit().remaining == 0) { + logger.log(Level.INFO, "Exceeded rate limit for repository"); return false; } } catch (FileNotFoundException ex) { logger.log(Level.INFO, "Rate limit API not found."); + return false; } catch (IOException ex) { logger.log(Level.SEVERE, "Error while accessing rate limit API", ex); return false; } + - if (ghRepository == null) { - try { - ghRepository = gitHub.getRepository(reponame); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Could not retrieve GitHub repository named " + reponame + " (Do you have properly set 'GitHub project' field in job configuration?)", ex); - return false; - } + try { + ghRepository = gitHub.getRepository(reponame); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Could not retrieve GitHub repository named " + reponame + " (Do you have properly set 'GitHub project' field in job configuration?)", ex); + return false; } return true; } public void check() { - if (!initGhRepository()) { + + if (!trigger.isActive()) { + logger.log(Level.FINE, "Project is not active, not checking github state"); return; } - - if (helper.isProjectDisabled()) { - logger.log(Level.FINE, "Project is disabled, not checking github state"); + + if (!initGhRepository()) { return; } List openPulls; try { - openPulls = ghRepository.getPullRequests(GHIssueState.OPEN); + openPulls = getGitHubRepo().getPullRequests(GHIssueState.OPEN); } catch (IOException ex) { logger.log(Level.SEVERE, "Could not retrieve open pull requests.", ex); return; } - ConcurrentMap pulls = helper.getTrigger().getPulls(); + ConcurrentMap pulls = trigger.getPulls(); Set closedPulls = new HashSet(pulls.keySet()); for (GHPullRequest pr : openPulls) { - if (pr.getHead() == null) { + if (pr.getHead() == null) { // Not sure if we need this, but leaving it for now. try { - pr = ghRepository.getPullRequest(pr.getNumber()); + pr = getGitHubRepo().getPullRequest(pr.getNumber()); } catch (IOException ex) { logger.log(Level.SEVERE, "Could not retrieve pr " + pr.getNumber(), ex); return; } } - try { - check(pr); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Could not retrieve pr " + pr.getNumber(), ex); - return; - } + check(pr); closedPulls.remove(pr.getNumber()); } @@ -141,15 +135,15 @@ public void check() { } } - private void check(GHPullRequest pr) throws IOException { - ConcurrentMap pulls = helper.getTrigger().getPulls(); + private void check(GHPullRequest pr) { + ConcurrentMap pulls = trigger.getPulls(); final Integer id = pr.getNumber(); GhprbPullRequest pull; if (pulls.containsKey(id)) { pull = pulls.get(id); } else { - pulls.putIfAbsent(id, new GhprbPullRequest(pr, helper, this)); + pulls.putIfAbsent(id, new GhprbPullRequest(pr, trigger.getHelper(), this)); pull = pulls.get(id); } pull.check(pr); @@ -275,11 +269,11 @@ public boolean createHook() { } private String getSecret() { - return helper.getTrigger().getGitHubApiAuth().getSecret(); + return trigger.getGitHubApiAuth().getSecret(); } private String getHookUrl() { - String baseUrl = helper.getTrigger().getGitHubApiAuth().getJenkinsUrl(); + String baseUrl = trigger.getGitHubApiAuth().getJenkinsUrl(); if (baseUrl == null) { baseUrl = Jenkins.getInstance().getRootUrl(); } @@ -291,7 +285,7 @@ public GHPullRequest getPullRequest(int id) throws IOException { } void onIssueCommentHook(IssueComment issueComment) throws IOException { - if (helper.isProjectDisabled()) { + if (!trigger.isActive()) { logger.log(Level.FINE, "Not checking comments since build is disabled"); return; } @@ -302,11 +296,13 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { return; } - ConcurrentMap pulls = helper.getTrigger().getPulls(); + ConcurrentMap pulls = trigger.getPulls(); GhprbPullRequest pull = pulls.get(id); if (pull == null) { - pull = new GhprbPullRequest(getGitHubRepo().getPullRequest(id), helper, this); + GHRepository repo = getGitHubRepo(); + GHPullRequest pr = repo.getPullRequest(id); + pull = new GhprbPullRequest(pr, trigger.getHelper(), this); pulls.put(id, pull); } pull.check(issueComment.getComment()); @@ -314,45 +310,43 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { } void onPullRequestHook(PullRequest pr) throws IOException { + GHPullRequest ghpr = pr.getPullRequest(); + int number = pr.getNumber(); + String action = pr.getAction(); - ConcurrentMap pulls = helper.getTrigger().getPulls(); + ConcurrentMap pulls = trigger.getPulls(); - if ("closed".equals(pr.getAction())) { - pulls.remove(pr.getNumber()); - } else if (helper.isProjectDisabled()) { + if ("closed".equals(action)) { + pulls.remove(number); + } else if (!trigger.isActive()) { logger.log(Level.FINE, "Not processing Pull request since the build is disabled"); - } else if ("opened".equals(pr.getAction()) || "reopened".equals(pr.getAction())) { - GhprbPullRequest pull = pulls.get(pr.getNumber()); + } else if ("opened".equals(action) || "reopened".equals(action)) { + GhprbPullRequest pull = pulls.get(number); if (pull == null) { - pulls.putIfAbsent(pr.getNumber(), new GhprbPullRequest(pr.getPullRequest(), helper, this)); - pull = pulls.get(pr.getNumber()); + pulls.putIfAbsent(number, new GhprbPullRequest(ghpr, trigger.getHelper(), this)); + pull = pulls.get(number); } - pull.check(pr.getPullRequest()); - } else if ("synchronize".equals(pr.getAction())) { - GhprbPullRequest pull = pulls.get(pr.getNumber()); + pull.check(ghpr); + } else if ("synchronize".equals(action)) { + GhprbPullRequest pull = pulls.get(number); if (pull == null) { - pulls.putIfAbsent(pr.getNumber(), new GhprbPullRequest(pr.getPullRequest(), helper, this)); - pull = pulls.get(pr.getNumber()); + pulls.putIfAbsent(number, new GhprbPullRequest(ghpr, trigger.getHelper(), this)); + pull = pulls.get(number); } if (pull == null) { - logger.log(Level.SEVERE, "Pull Request #{0} doesn''t exist", pr.getNumber()); + logger.log(Level.SEVERE, "Pull Request #{0} doesn''t exist", number); return; } - pull.check(pr.getPullRequest()); + pull.check(ghpr); } else { - logger.log(Level.WARNING, "Unknown Pull Request hook action: {0}", pr.getAction()); + logger.log(Level.WARNING, "Unknown Pull Request hook action: {0}", action); } GhprbTrigger.getDscp().save(); } - @VisibleForTesting - void setHelper(Ghprb helper) { - this.helper = helper; - } - public GHRepository getGitHubRepo() { if (ghRepository == null) { - init(); + initGhRepository(); } return ghRepository; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index d33aa15c1..cbcea86b7 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -3,8 +3,11 @@ import hudson.Extension; import hudson.model.AbstractProject; import hudson.model.UnprotectedRootAction; +import hudson.security.ACL; import hudson.security.csrf.CrumbExclusion; +import org.acegisecurity.Authentication; +import org.acegisecurity.context.SecurityContextHolder; import org.apache.commons.io.IOUtils; import org.kohsuke.github.GHEventPayload.IssueComment; import org.kohsuke.github.GHEventPayload.PullRequest; @@ -102,7 +105,7 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { String repoName = issueComment.getRepository().getFullName(); - logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", new Object[] { issueComment.getComment(), repoName }); + logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", new Object[] { issueComment.getComment().getBody(), repoName }); for (GhprbTrigger trigger : getTriggers(repoName, body, signature)) { try { @@ -162,6 +165,10 @@ private String extractRequestBody(StaplerRequest req) { private Set getTriggers(String repoName, String body, String signature) { Set triggers = new HashSet(); + + // We need this to get access to list of repositories + Authentication old = SecurityContextHolder.getContext().getAuthentication(); + SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); Set> projects = GhprbTrigger.getDscp().getRepoTriggers(repoName); if (projects != null) { @@ -172,6 +179,9 @@ private Set getTriggers(String repoName, String body, String signa } } } + + SecurityContextHolder.getContext().setAuthentication(old); + return triggers; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 1f6bea2bf..90c53c053 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -447,6 +447,10 @@ public Boolean getOnlyTriggerPhrase() { public Boolean getUseGitHubHooks() { return useGitHubHooks != null && useGitHubHooks; } + + public Ghprb getHelper() { + return helper; + } public Boolean getPermitAll() { return permitAll != null && permitAll; @@ -799,22 +803,29 @@ public ConcurrentMap getPullRequests(String projectNa } private void addRepoTrigger(String repo, AbstractProject project) { - if (project == null) { + if (project == null || StringUtils.isEmpty(repo)) { return; } + logger.log(Level.FINE, "Adding [{0}] to webhooks repo [{1}]", new Object[]{project.getFullName(), repo}); - Set> projects = repoJobs.get(repo); - if (projects == null) { - projects = Collections.newSetFromMap(new WeakHashMap, Boolean>()); - repoJobs.put(repo, projects); + synchronized (repoJobs) { + Set> projects = repoJobs.get(repo); + if (projects == null) { + logger.log(Level.FINE, "No other projects found, creating new repo set"); + projects = Collections.newSetFromMap(new WeakHashMap, Boolean>()); + repoJobs.put(repo, projects); + } else { + logger.log(Level.FINE, "Adding project to current repo set, length: {0}", new Object[]{projects.size()}); + } + + projects.add(project); } - - projects.add(project); } private void removeRepoTrigger(String repo, AbstractProject project) { Set> projects = repoJobs.get(repo); if (project != null && projects != null) { + logger.log(Level.FINE, "Removing [{0}] from webhooks repo [{1}]", new Object[]{repo, project.getFullName()}); projects.remove(project); } } @@ -823,7 +834,18 @@ private void removeRepoTrigger(String repo, AbstractProject project) { if (repoJobs == null) { repoJobs = new ConcurrentHashMap>>(5); } - return repoJobs.get(repo); + logger.log(Level.FINE, "Retrieving triggers for repo [{0}]", new Object[]{repo}); + + Set> projects = repoJobs.get(repo); + if (projects != null) { + for (AbstractProject project : projects) { + logger.log(Level.FINE, "Found project [{0}] for webhook repo [{0}]", new Object[]{project.getFullName(), repo}); + } + } else { + projects = Collections.newSetFromMap(new WeakHashMap, Boolean>(0)); + } + + return projects; } public List getWhiteListTargetBranches() { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java index 2c798071d..ec3c6d424 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java @@ -43,6 +43,10 @@ public GhprbTriggerBackwardsCompatible(String cron) throws ANTLRException { protected transient String commitStatusContext; @Deprecated protected transient GhprbGitHubAuth gitHubApiAuth; + @Deprecated + protected transient String project; + @Deprecated + protected transient AbstractProject _project; diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java index 074a4f49e..155437197 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java @@ -69,6 +69,7 @@ public void shouldBuildTriggersOnUpdatingNewCommitsPR() throws Exception { public void shouldBuildTriggersOnUpdatingRetestMessagePR() throws Exception { // GIVEN GhprbTestUtil.triggerRunAndWait(10, trigger, project); + assertThat(project.getBuilds().toArray().length).isEqualTo(1); given(comment.getBody()).willReturn("retest this please"); given(comment.getUpdatedAt()).willReturn(new DateTime().plusDays(1).toDate()); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java index ddba7ca5c..8c5709911 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java @@ -42,11 +42,8 @@ public abstract class GhprbITBaseTestCase { @Mock protected GHUser ghUser; @Mock - protected GitHub gitHub; - @Mock protected Ghprb helper; - protected GhprbBuilds builds; protected GhprbTrigger trigger; @@ -60,9 +57,8 @@ protected void beforeTest(Map globalConfig, Map trigger = GhprbTestUtil.getTrigger(triggerConfig); - given(ghprbGitHub.get()).willReturn(gitHub); + GitHub gitHub = trigger.getGitHub(); - given(gitHub.getRateLimit()).willReturn(ghRateLimit); given(gitHub.getRepository(anyString())).willReturn(ghRepository); given(ghPullRequest.getHead()).willReturn(commitPointer); @@ -86,7 +82,7 @@ protected void beforeTest(Map globalConfig, Map GhprbTestUtil.mockCommitList(ghPullRequest); - GhprbRepository repo = Mockito.spy(new GhprbRepository("user", "dropwizard", helper)); + GhprbRepository repo = Mockito.spy(new GhprbRepository("user", "dropwizard", trigger)); Mockito.doReturn(ghRepository).when(repo).getGitHubRepo(); Mockito.doNothing().when(repo).addComment(Mockito.anyInt(), Mockito.anyString(), any(AbstractBuild.class), any(TaskListener.class)); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 942be3a71..210dcb5f9 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -140,7 +140,7 @@ public void beforeTest() throws Exception { given(build.getResult()).willReturn(Result.SUCCESS); given(build.getParent()).willCallRealMethod(); - given(pullRequest.getPullRequest()).willReturn(pr); + given(pullRequest.getPullRequest(Mockito.anyBoolean())).willReturn(pr); given(cause.getPullID()).willReturn(pullId); given(cause.isMerged()).willReturn(true); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java index b8812b472..72f21e6db 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java @@ -116,8 +116,7 @@ public void testInitRepoNameNull() throws IOException { ghprbPullRequest.init(helper, ghprbRepository); // THEN - verify(ghprbRepository, times(1)).getPullRequest(10); - verify(pr, times(2)).getHead(); + verify(pr, times(1)).getHead(); } @@ -188,7 +187,7 @@ public void authorRepoGitUrlShouldBeNullWhenNoRepository() throws Exception { ghprbPullRequest.init(helper, ghprbRepository); // THEN - assertThat(ghprbPullRequest.getAuthorRepoGitUrl()).isNull(); + assertThat(ghprbPullRequest.getAuthorRepoGitUrl()).isEqualTo(""); } @Test diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 637ee6de5..0ced66d93 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -69,7 +69,6 @@ public class GhprbRepositoryTest { private static final Date UPDATE_DATE = new Date(); private static final String msg = "Build triggered. sha1 is merged."; - @Mock private GitHub gt; @Mock private GHRepository ghRepository; @@ -98,17 +97,19 @@ public class GhprbRepositoryTest { public JenkinsRule jenkinsRule = new JenkinsRule(); @Before - @SuppressWarnings("unused") public void setUp() throws Exception { AbstractProject project = jenkinsRule.createFreeStyleProject("GhprbRepoTest"); trigger = GhprbTestUtil.getTrigger(null); + trigger.start(project, true); + trigger.setHelper(helper); + gt = trigger.getGitHub(); + doReturn(mock(QueueTaskFuture.class)).when(trigger).startJob(any(GhprbCause.class), any(GhprbRepository.class)); initGHPRWithTestData(); // Mock github API given(helper.getGitHub()).willReturn(gitHub); given(helper.getTrigger()).willReturn(trigger); - given(gitHub.get()).willReturn(gt); given(gt.getRepository(anyString())).willReturn(ghRepository); // Mock rate limit @@ -150,7 +151,7 @@ public void testCheckMethodWhenUsingGitHubEnterprise() throws IOException { ghprbRepository.check(); // THEN - verifyGetGithub(1); + verifyGetGithub(2, 0); } @Test @@ -174,7 +175,7 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { ghprbRepository.check(); // THEN - verifyGetGithub(1); + verifyGetGithub(2, 1); /** GH Repo verifications */ verify(ghRepository, only()).getPullRequests(OPEN); // Call to Github API @@ -192,7 +193,6 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { verify(helper).getWhiteListTargetBranches(); verify(helper, times(3)).isProjectDisabled(); verify(helper).checkSkipBuild(eq(ghPullRequest)); - verify(helper, times(2)).getTrigger(); verifyNoMoreInteractions(helper); verifyNoMoreInteractions(gt); @@ -232,7 +232,7 @@ public void testCheckMethodWithNewPR() throws IOException { ghprbRepository.check(); // THEN - verifyGetGithub(1); + verifyGetGithub(2, 1); verifyNoMoreInteractions(gt); /** GH PR verifications */ @@ -244,7 +244,7 @@ public void testCheckMethodWithNewPR() throws IOException { verify(ghPullRequest, times(1)).getTitle(); verify(ghPullRequest, times(7)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(5)).getHead(); + verify(ghPullRequest, times(7)).getHead(); verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(3)).getUpdatedAt(); @@ -260,7 +260,6 @@ public void testCheckMethodWithNewPR() throws IOException { verify(helper, times(2)).getWhiteListTargetBranches(); verify(helper, times(5)).isProjectDisabled(); verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); - verify(helper, times(3)).getTrigger(); verifyNoMoreInteractions(helper); verify(ghUser, times(2)).getEmail(); // Call to Github API @@ -314,7 +313,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException ghprbRepository.check(); // PR was updated // THEN - verifyGetGithub(2); + verifyGetGithub(2, 1); verifyNoMoreInteractions(gt); /** GH PR verifications */ @@ -324,9 +323,9 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(1)).getTitle(); - verify(ghPullRequest, times(8)).getUser(); + verify(ghPullRequest, times(7)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(6)).getHead(); + verify(ghPullRequest, times(8)).getHead(); verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(1)).getHtmlUrl(); @@ -342,7 +341,6 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(helper, times(2)).ifOnlyTriggerPhrase(); verify(helper, times(1)).getBuilds(); verify(helper, times(2)).getWhiteListTargetBranches(); - verify(helper, times(4)).getTrigger(); // verify(helper).isBotUser(eq(ghUser)); verify(helper).isWhitelistPhrase(eq("comment body")); @@ -355,6 +353,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(ghUser, times(2)).getEmail(); // Call to Github API verify(ghUser, times(1)).getLogin(); + verify(ghUser, times(1)).getName(); verifyNoMoreInteractions(ghUser); } @@ -402,7 +401,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException ghprbRepository.check(); // PR was updated // THEN - verifyGetGithub(2); + verifyGetGithub(2, 1); verifyNoMoreInteractions(gt); /** GH PR verifications */ @@ -414,10 +413,10 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(2)).getTitle(); - verify(ghPullRequest, times(10)).getUser(); + verify(ghPullRequest, times(9)).getUser(); verify(ghPullRequest, times(2)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(6)).getHead(); - verify(ghPullRequest, times(1)).getBase(); + verify(ghPullRequest, times(10)).getHead(); + verify(ghPullRequest, times(2)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(3)).getUpdatedAt(); verify(ghPullRequest, times(2)).getHtmlUrl(); @@ -440,11 +439,11 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(helper).isAdmin(eq(ghUser)); verify(helper, times(6)).isProjectDisabled(); verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); - verify(helper, times(4)).getTrigger(); verifyNoMoreInteractions(helper); verify(ghUser, times(3)).getEmail(); // Call to Github API verify(ghUser, times(1)).getLogin(); + verify(ghUser, times(1)).getName(); verifyNoMoreInteractions(ghUser); verify(builds, times(2)).build(any(GhprbPullRequest.class), any(GHUser.class), any(String.class)); @@ -490,11 +489,10 @@ public void testCheckMethodWithNoPR() throws IOException { verify(helper).isProjectDisabled(); // THEN - verifyGetGithub(1); + verifyGetGithub(2, 1); verifyNoMoreInteractions(gt); verify(ghRepository, times(1)).getPullRequests(OPEN); // Call to Github API - verify(helper, times(1)).getTrigger(); verifyNoMoreInteractions(helper, ghRepository); } @@ -507,8 +505,7 @@ public void testExceedRateLimit() throws IOException { ghprbRepository.check(); // THEN - verify(helper, only()).getGitHub(); - verify(gitHub, only()).get(); + verify(trigger, times(2)).getGitHub(); verify(gt, only()).getRateLimit(); verifyZeroInteractions(ghRepository); verifyZeroInteractions(gitHub); @@ -560,7 +557,7 @@ private void initGHPRWithTestData() throws IOException { given(head.getSha()).willReturn("head sha"); pulls = new ConcurrentHashMap(); - ghprbRepository = new GhprbRepository(TEST_USER_NAME, TEST_REPO_NAME, helper); + ghprbRepository = new GhprbRepository(TEST_USER_NAME, TEST_REPO_NAME, trigger); ghprbPullRequest = new GhprbPullRequest(ghPullRequest, helper, ghprbRepository); given(trigger.getPulls()).willReturn(pulls); @@ -574,10 +571,9 @@ private void increaseRateLimitToDefaults() { } // Verifications - private void verifyGetGithub(int callsCount) throws IOException { - verify(helper, times(callsCount)).getGitHub(); - verify(gitHub, times(callsCount)).get(); // Call to Github API (once, than cached) - verify(gt, times(1)).getRepository(anyString()); // Call to Github API - verify(gt, times(callsCount)).getRateLimit(); + private void verifyGetGithub(int callsCount, int repoTimes) throws IOException { + verify(trigger, times(callsCount)).getGitHub(); + verify(gt, times(1)).getRateLimit(); + verify(gt, times(repoTimes)).getRepository(anyString()); } } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java index a3084b23c..afcb41968 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java @@ -7,6 +7,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.Reader; import java.io.StringReader; import java.net.URLEncoder; @@ -17,13 +18,15 @@ import org.junit.runner.RunWith; import org.jvnet.hudson.test.JenkinsRule; import org.kohsuke.github.GHCommitPointer; +import org.kohsuke.github.GHEventPayload.IssueComment; +import org.kohsuke.github.GHIssueComment; import org.kohsuke.github.GHPullRequest; -import org.kohsuke.github.GHRateLimit; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHUser; import org.kohsuke.github.GitHub; import org.kohsuke.stapler.StaplerRequest; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import com.coravy.hudson.plugins.github.GithubProjectProperty; @@ -54,10 +57,6 @@ public class GhprbRootActionTest { @Mock protected GHUser ghUser; - protected GitHub gitHub; - // Stubs - protected GHRateLimit ghRateLimit = new GHRateLimit(); - @Rule public JenkinsRule jenkinsRule = new JenkinsRule(); @@ -67,15 +66,17 @@ public class GhprbRootActionTest { private BufferedReader br; + private GhprbTrigger trigger; + private final int prId = 1; @Before public void setup() throws Exception { - gitHub = spy(GitHub.connectAnonymously()); - given(ghprbGitHub.get()).willReturn(gitHub); - given(gitHub.getRateLimit()).willReturn(ghRateLimit); - doReturn(ghRepository).when(gitHub).getRepository(anyString()); + trigger = GhprbTestUtil.getTrigger(); + GitHub gitHub = trigger.getGitHub(); + + given(gitHub.getRepository(anyString())).willReturn(ghRepository); given(commitPointer.getRef()).willReturn("ref"); given(ghRepository.getName()).willReturn("dropwizard"); @@ -86,8 +87,8 @@ public void setup() throws Exception { given(ghPullRequest.getUser()).willReturn(ghUser); given(ghUser.getEmail()).willReturn("email@email.com"); given(ghUser.getLogin()).willReturn("user"); + given(ghUser.getName()).willReturn("User"); - ghRateLimit.remaining = GhprbTestUtil.INITIAL_RATE_LIMIT; GhprbTestUtil.mockCommitList(ghPullRequest); } @@ -96,7 +97,7 @@ public void setup() throws Exception { public void testUrlEncoded() throws Exception { // GIVEN FreeStyleProject project = jenkinsRule.createFreeStyleProject("testUrlEncoded"); - GhprbTrigger trigger = GhprbTestUtil.getTrigger(); + doReturn(project).when(trigger).getActualProject(); doReturn(true).when(trigger).getUseGitHubHooks(); @@ -108,9 +109,11 @@ public void testUrlEncoded() throws Exception { given(ghRepository.getPullRequest(prId)).willReturn(ghPullRequest); Ghprb ghprb = spy(new Ghprb(trigger)); doReturn(ghprbGitHub).when(ghprb).getGitHub(); + doReturn(true).when(ghprb).isAdmin(Mockito.any(GHUser.class)); + trigger.start(project, true); trigger.setHelper(ghprb); - ghprb.getRepository().setHelper(ghprb); + project.addTrigger(trigger); GitSCM scm = GhprbTestUtil.provideGitSCM(); project.setScm(scm); @@ -119,10 +122,10 @@ public void testUrlEncoded() throws Exception { assertThat(project.getBuilds().toArray().length).isEqualTo(0); - doReturn(gitHub).when(trigger).getGitHub(); - BufferedReader br = new BufferedReader(new StringReader( "payload=" + URLEncoder.encode(GhprbTestUtil.PAYLOAD, "UTF-8"))); + + given(req.getContentType()).willReturn("application/x-www-form-urlencoded"); given(req.getParameter("payload")).willReturn(GhprbTestUtil.PAYLOAD); @@ -130,6 +133,20 @@ public void testUrlEncoded() throws Exception { given(req.getReader()).willReturn(br); given(req.getCharacterEncoding()).willReturn("UTF-8"); + + StringReader brTest = new StringReader(GhprbTestUtil.PAYLOAD); + + IssueComment issueComment = spy(GitHub.connectAnonymously().parseEventPayload(brTest, IssueComment.class)); + brTest.close(); + + GHIssueComment ghIssueComment = spy(issueComment.getComment()); + + Mockito.when(issueComment.getComment()).thenReturn(ghIssueComment); + Mockito.when(ghIssueComment.getUser()).thenReturn(ghUser); + + + given(trigger.getGitHub().parseEventPayload(Mockito.any(Reader.class), Mockito.eq(IssueComment.class))).willReturn(issueComment); + GhprbRootAction ra = new GhprbRootAction(); ra.doIndex(req, null); GhprbTestUtil.waitForBuildsToFinish(project); @@ -141,7 +158,6 @@ public void testUrlEncoded() throws Exception { public void disabledJobsDontBuild() throws Exception { // GIVEN FreeStyleProject project = jenkinsRule.createFreeStyleProject("disabledJobsDontBuild"); - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); doReturn(project).when(trigger).getActualProject(); given(commitPointer.getSha()).willReturn("sha1"); @@ -154,7 +170,7 @@ public void disabledJobsDontBuild() throws Exception { doReturn(ghprbGitHub).when(ghprb).getGitHub(); trigger.start(project, true); trigger.setHelper(ghprb); - ghprb.getRepository().setHelper(ghprb); + project.addTrigger(trigger); GitSCM scm = GhprbTestUtil.provideGitSCM(); project.setScm(scm); @@ -165,8 +181,6 @@ public void disabledJobsDontBuild() throws Exception { project.disable(); - doReturn(gitHub).when(trigger).getGitHub(); - BufferedReader br = new BufferedReader(new StringReader( "payload=" + URLEncoder.encode(GhprbTestUtil.PAYLOAD, "UTF-8"))); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java index 0e541af32..1e41ff803 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java @@ -27,6 +27,8 @@ import org.joda.time.DateTime; import org.kohsuke.github.GHCommitPointer; import org.kohsuke.github.GHPullRequest; +import org.kohsuke.github.GHRateLimit; +import org.kohsuke.github.GitHub; import org.kohsuke.github.PagedIterable; import org.kohsuke.github.PagedIterator; import org.kohsuke.stapler.BindInterceptor; @@ -40,7 +42,6 @@ import net.sf.json.JSONObject; import static org.mockito.Matchers.any; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; public class GhprbTestUtil { @@ -380,9 +381,15 @@ public static GhprbTrigger getTrigger(Map values) throws Excepti GhprbTrigger trigger = spy(req.bindJSON(GhprbTrigger.class, defaults)); + GHRateLimit limit = new GHRateLimit(); + limit.remaining = INITIAL_RATE_LIMIT; + + GitHub github = Mockito.mock(GitHub.class); + given(github.getRateLimit()).willReturn(limit); ConcurrentMap pulls = new ConcurrentHashMap(1); Mockito.doReturn(pulls).when(trigger).getPulls(); + Mockito.doReturn(github).when(trigger).getGitHub(); return trigger; } From 08a2612c1ff3dbf5297faf5611680f6b59e9ae6c Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 22 Jan 2016 20:08:07 -0700 Subject: [PATCH 132/175] Add comments, and some caching of values we don't get for free --- .../plugins/ghprb/GhprbPullRequest.java | 71 ++++++++++++++----- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 76834642c..1570226d0 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -30,13 +30,14 @@ public class GhprbPullRequest { @Deprecated @SuppressWarnings("unused") private transient GHUser author; @Deprecated @SuppressWarnings("unused") private transient String title; @Deprecated @SuppressWarnings("unused") private transient String reponame; - @Deprecated @SuppressWarnings("unused") private transient String authorEmail; @Deprecated @SuppressWarnings("unused") private transient URL url; @Deprecated @SuppressWarnings("unused") private transient String description; @Deprecated @SuppressWarnings("unused") private transient String target; @Deprecated @SuppressWarnings("unused") private transient String source; @Deprecated @SuppressWarnings("unused") private transient String authorRepoGitUrl; + + private transient String authorEmail; private transient Ghprb helper; // will be refreshed each time GhprbRepository.init() is called private transient GhprbRepository repo; // will be refreshed each time GhprbRepository.init() is called @@ -426,6 +427,10 @@ public boolean isMergeable() { return mergeable; } + /** + * Base and Ref are part of the PullRequest object + * @return + */ public String getTarget() { try { return getPullRequest(false).getBase().getRef(); @@ -434,6 +439,10 @@ public String getTarget() { } } + /** + * Head and Ref are part of the PullRequest object + * @return + */ public String getSource() { try { return getPullRequest(false).getHead().getRef(); @@ -442,15 +451,11 @@ public String getSource() { } } - public String getAuthorEmail() { - try { - return getPullRequest(false).getUser().getEmail(); - } catch (IOException e) { - logger.log(Level.SEVERE, "Unable to fetch author info for " + id); - } - return ""; - } + /** + * Title is part of the PullRequest object + * @return + */ public String getTitle() { try { return getPullRequest(false).getTitle(); @@ -461,23 +466,46 @@ public String getTitle() { /** * Returns the URL to the Github Pull Request. + * This URL is part of the pull request object * * @return the Github Pull Request URL - * @throws IOException */ public URL getUrl() throws IOException { return getPullRequest(false).getHtmlUrl(); } + + + /** + * The description body is part of the PullRequest object + * @return + */ + public String getDescription() { + try { + return getPullRequest(false).getBody(); + } catch (IOException e) { + return "UNKNOWN"; + } + } public GitUser getCommitAuthor() { return commitAuthor; } + /** + * Author is part of the PullRequest Object + * @return + * @throws IOException + */ public GHUser getPullRequestAuthor() throws IOException { return getPullRequest(false).getUser(); } - + /** + * Get the PullRequest object for this PR + * @param force - forces the code to go get the PullRequest from GitHub now + * @return + * @throws IOException + */ public GHPullRequest getPullRequest(boolean force) throws IOException { if (this.pr == null || force) { this.pr = repo.getPullRequest(this.id); @@ -485,11 +513,22 @@ public GHPullRequest getPullRequest(boolean force) throws IOException { return pr; } - public String getDescription() { - try { - return getPullRequest(false).getBody(); - } catch (IOException e) { - return "UNKNOWN"; + + /** + * Email address is collected from GitHub as extra information, so lets cache it. + * @return + */ + public String getAuthorEmail() { + if (StringUtils.isEmpty(authorEmail)) { + try { + GHUser user = getPullRequestAuthor(); + authorEmail = user.getEmail(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to fetch author info for " + id); + } } + authorEmail = StringUtils.isEmpty(authorEmail) ? "" : authorEmail; + return authorEmail; } + } From cb901831ab96be8f249591e01dcad3bd65b21438 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 22 Jan 2016 22:31:28 -0700 Subject: [PATCH 133/175] Move PR lists down to the job configuration --- .../plugins/ghprb/GhprbRepository.java | 36 ++++----- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 75 ++++++++++--------- .../jobdsl/GhprbContextExtensionPoint.java | 3 +- .../ghprb/GhprbPullRequestMergeTest.java | 4 +- .../plugins/ghprb/GhprbRepositoryTest.java | 2 +- .../plugins/ghprb/GhprbTestUtil.java | 2 +- 6 files changed, 60 insertions(+), 62 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 4e9ef0371..c4b658204 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -44,7 +44,7 @@ public void init() { // make the initial check call to populate our data structures initGhRepository(); - for (Entry next : trigger.getPulls().entrySet()) { + for (Entry next : trigger.getPullRequests().entrySet()) { GhprbPullRequest pull = next.getValue(); pull.init(trigger.getHelper(), this); } @@ -111,7 +111,7 @@ public void check() { return; } - ConcurrentMap pulls = trigger.getPulls(); + Map pulls = trigger.getPullRequests(); Set closedPulls = new HashSet(pulls.keySet()); @@ -133,20 +133,22 @@ public void check() { for (Integer id : closedPulls) { pulls.remove(id); } + trigger.save(); } private void check(GHPullRequest pr) { - ConcurrentMap pulls = trigger.getPulls(); + Map pulls = trigger.getPullRequests(); final Integer id = pr.getNumber(); GhprbPullRequest pull; if (pulls.containsKey(id)) { pull = pulls.get(id); } else { - pulls.putIfAbsent(id, new GhprbPullRequest(pr, trigger.getHelper(), this)); + pulls.put(id, new GhprbPullRequest(pr, trigger.getHelper(), this)); pull = pulls.get(id); } pull.check(pr); + trigger.save(); } public void commentOnFailure(AbstractBuild build, TaskListener listener, GhprbCommitStatusException ex) { @@ -296,7 +298,7 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { return; } - ConcurrentMap pulls = trigger.getPulls(); + Map pulls = trigger.getPullRequests(); GhprbPullRequest pull = pulls.get(id); if (pull == null) { @@ -306,7 +308,7 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { pulls.put(id, pull); } pull.check(issueComment.getComment()); - GhprbTrigger.getDscp().save(); + trigger.save(); } void onPullRequestHook(PullRequest pr) throws IOException { @@ -314,36 +316,24 @@ void onPullRequestHook(PullRequest pr) throws IOException { int number = pr.getNumber(); String action = pr.getAction(); - ConcurrentMap pulls = trigger.getPulls(); + Map pulls = trigger.getPullRequests(); if ("closed".equals(action)) { pulls.remove(number); } else if (!trigger.isActive()) { logger.log(Level.FINE, "Not processing Pull request since the build is disabled"); - } else if ("opened".equals(action) || "reopened".equals(action)) { + } else if ("opened".equals(action) || "reopened".equals(action) || "synchronize".equals(action)) { GhprbPullRequest pull = pulls.get(number); if (pull == null) { - pulls.putIfAbsent(number, new GhprbPullRequest(ghpr, trigger.getHelper(), this)); - pull = pulls.get(number); - } - pull.check(ghpr); - } else if ("synchronize".equals(action)) { - GhprbPullRequest pull = pulls.get(number); - if (pull == null) { - pulls.putIfAbsent(number, new GhprbPullRequest(ghpr, trigger.getHelper(), this)); - pull = pulls.get(number); - } - if (pull == null) { - logger.log(Level.SEVERE, "Pull Request #{0} doesn''t exist", number); - return; + pull = new GhprbPullRequest(ghpr, trigger.getHelper(), this); + pulls.put(number, pull); } pull.check(ghpr); } else { logger.log(Level.WARNING, "Unknown Pull Request hook action: {0}", action); } - GhprbTrigger.getDscp().save(); } - + public GHRepository getGitHubRepo() { if (ghRepository == null) { initGhRepository(); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 90c53c053..dc40871ac 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -127,7 +127,8 @@ public GhprbTrigger(String adminlist, String commitStatusContext, String gitHubAuthId, String buildDescTemplate, - List extensions + List extensions, + Map pullRequests ) throws ANTLRException { super(cron); this.adminlist = adminlist; @@ -146,6 +147,7 @@ public GhprbTrigger(String adminlist, this.buildDescTemplate = buildDescTemplate; setExtensions(extensions); configVersion = latestVersion; + this.pullRequests = pullRequests; } @Override @@ -154,6 +156,7 @@ public Object readResolve() { checkGitHubApiAuth(); return this; } + @SuppressWarnings("deprecation") private void checkGitHubApiAuth() { @@ -171,20 +174,13 @@ public static DescriptorImpl getDscp() { * Save any updates that may have been made inside the plugin that would affect the config.xml */ public void save() { - if (super.job != null) { - String xmlConfig = ""; - try { - xmlConfig = super.job.getConfigFile().asString(); - } catch (IOException e) { - logger.log(Level.SEVERE, "Unable to save load config file", e); - } - if (!xmlConfig.contains("" + configVersion)) { - try { - super.job.save(); - } catch (IOException e) { - logger.log(Level.SEVERE, "Unable to save config updates", e); - } - } + if (super.job == null) { + return; + } + try { + super.job.save(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to save config updates", e); } } @@ -193,6 +189,20 @@ public void start(AbstractProject project, boolean newInstance) { // We should always start the trigger, and handle cases where we don't run in the run function. super.start(project, newInstance); + try { + Map prs = getDescriptor().getPullRequests(project.getFullName()); + if (prs != null) { + prs = new HashMap(prs); + if (pullRequests == null) { + pullRequests = prs; + } else { + pullRequests.putAll(prs); + } + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to transfer map of pull requests", e); + } + save(); String name = project.getFullName(); @@ -220,9 +230,14 @@ public void start(AbstractProject project, boolean newInstance) { DESCRIPTOR.addRepoTrigger(getRepository().getName(), super.job); } } + + private Map pullRequests; - public ConcurrentMap getPulls() { - return getDescriptor().getPullRequests(super.job.getFullName()); + public Map getPullRequests() { + if (pullRequests == null) { + pullRequests = new HashMap(); + } + return pullRequests; } @Override @@ -255,11 +270,10 @@ public void run() { return; } - logger.log(Level.FINE, "Running trigger for {0}", super.job.getFullName()); helper.run(); - getDescriptor().save(); + save(); } public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { @@ -610,7 +624,7 @@ public List getDefaultAuth(List githubAuth) { private String requestForTestingPhrase; // map of jobs (by their fullName) and their map of pull requests - private Map> jobs; + private transient Map> jobs; /** * map of jobs (by the repo name); No need to keep the projects from shutdown to startup. @@ -641,9 +655,9 @@ public DescriptorImpl() { if (repoJobs == null) { repoJobs = new ConcurrentHashMap>>(); } - if (jobs == null) { - jobs = new HashMap>(); - } +// if (jobs == null) { +// jobs = new HashMap>(); +// } // save(); } @@ -786,18 +800,11 @@ public ListBoxModel doFillGitHubAuthIdItems(@QueryParameter("gitHubAuthId") Stri } - public ConcurrentMap getPullRequests(String projectName) { - ConcurrentMap ret; + public Map getPullRequests(String projectName) { + Map ret = null; if (jobs.containsKey(projectName)) { - Map map = jobs.get(projectName); - if (!(map instanceof ConcurrentMap)) { - map = new ConcurrentHashMap(map); - } - jobs.put(projectName, (ConcurrentMap) map); - ret = (ConcurrentMap) map; - } else { - ret = new ConcurrentHashMap(); - jobs.put(projectName, ret); + ret = jobs.get(projectName); + jobs.remove(projectName); } return ret; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java index a246c3d84..08608c24e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java @@ -38,7 +38,8 @@ public Object githubPullRequest(Runnable closure) throws ANTLRException { null, null, null, - context.extensionContext.extensions + context.extensionContext.extensions, + null ); } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 210dcb5f9..c2c787580 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -118,7 +118,7 @@ public void beforeTest() throws Exception { jobs.put("project", pulls); Mockito.doReturn(project).when(trigger).getActualProject(); - Mockito.doReturn(pulls).when(trigger).getPulls(); + Mockito.doReturn(pulls).when(trigger).getPullRequests(); Mockito.doReturn(repo).when(trigger).getRepository(); Mockito.doReturn(pr).when(repo).getPullRequest(pullId); @@ -161,7 +161,7 @@ public void beforeTest() throws Exception { jobsField.set(descriptor, jobs); helper = spy(new Ghprb(trigger)); - given(trigger.getPulls()).willReturn(pulls); + given(trigger.getPullRequests()).willReturn(pulls); trigger.setHelper(helper); given(helper.getRepository()).willReturn(repo); given(helper.isBotUser(any(GHUser.class))).willReturn(false); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 0ced66d93..b9d12336d 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -560,7 +560,7 @@ private void initGHPRWithTestData() throws IOException { ghprbRepository = new GhprbRepository(TEST_USER_NAME, TEST_REPO_NAME, trigger); ghprbPullRequest = new GhprbPullRequest(ghPullRequest, helper, ghprbRepository); - given(trigger.getPulls()).willReturn(pulls); + given(trigger.getPullRequests()).willReturn(pulls); // Reset mocks not to mix init data invocations with tests reset(ghPullRequest, ghUser, helper, head, base); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java index 1e41ff803..d44f2cd3c 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java @@ -388,7 +388,7 @@ public static GhprbTrigger getTrigger(Map values) throws Excepti given(github.getRateLimit()).willReturn(limit); ConcurrentMap pulls = new ConcurrentHashMap(1); - Mockito.doReturn(pulls).when(trigger).getPulls(); + Mockito.doReturn(pulls).when(trigger).getPullRequests(); Mockito.doReturn(github).when(trigger).getGitHub(); return trigger; From c337729286b48d8362abcc908f4cf0589e05c1ed Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 23 Jan 2016 12:51:12 -0700 Subject: [PATCH 134/175] Update tests to reflect cached email --- .../jenkinsci/plugins/ghprb/GhprbRepositoryTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index b9d12336d..0aad464e4 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -242,7 +242,7 @@ public void testCheckMethodWithNewPR() throws IOException { verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(1)).getTitle(); - verify(ghPullRequest, times(7)).getUser(); + verify(ghPullRequest, times(6)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API verify(ghPullRequest, times(7)).getHead(); verify(ghPullRequest, times(1)).getBase(); @@ -262,7 +262,7 @@ public void testCheckMethodWithNewPR() throws IOException { verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); - verify(ghUser, times(2)).getEmail(); // Call to Github API + verify(ghUser, times(1)).getEmail(); // Call to Github API verify(ghUser, times(1)).getLogin(); verifyNoMoreInteractions(ghUser); } @@ -323,7 +323,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(1)).getTitle(); - verify(ghPullRequest, times(7)).getUser(); + verify(ghPullRequest, times(6)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API verify(ghPullRequest, times(8)).getHead(); verify(ghPullRequest, times(1)).getBase(); @@ -351,7 +351,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); - verify(ghUser, times(2)).getEmail(); // Call to Github API + verify(ghUser, times(1)).getEmail(); // Call to Github API verify(ghUser, times(1)).getLogin(); verify(ghUser, times(1)).getName(); verifyNoMoreInteractions(ghUser); @@ -413,7 +413,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(2)).getTitle(); - verify(ghPullRequest, times(9)).getUser(); + verify(ghPullRequest, times(7)).getUser(); verify(ghPullRequest, times(2)).getMergeable(); // Call to Github API verify(ghPullRequest, times(10)).getHead(); verify(ghPullRequest, times(2)).getBase(); @@ -441,7 +441,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); - verify(ghUser, times(3)).getEmail(); // Call to Github API + verify(ghUser, times(1)).getEmail(); // Call to Github API verify(ghUser, times(1)).getLogin(); verify(ghUser, times(1)).getName(); verifyNoMoreInteractions(ghUser); From bc3f35eaa32cd5dab48979bb214cee2a47007628 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 23 Jan 2016 14:24:37 -0700 Subject: [PATCH 135/175] Add more tests and fix some bugs --- .../plugins/ghprb/GhprbPullRequest.java | 57 ++++-- .../plugins/ghprb/GhprbRepository.java | 13 +- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 11 +- .../plugins/ghprb/GhprbPullRequestTest.java | 174 +++++++----------- .../plugins/ghprb/GhprbRepositoryTest.java | 28 +-- 5 files changed, 139 insertions(+), 144 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 1570226d0..41731cc31 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -56,9 +56,26 @@ public class GhprbPullRequest { private Date updated; // Needed to track when the PR was updated private String head; private boolean accepted = false; // Needed to see if the PR has been added to the accepted list + private Boolean changed = true; // Keep track for when the job config needs to be saved again. + + private void setUpdated(Date lastUpdateTime) { + updated = lastUpdateTime; + changed = true; + } + + private void setHead(String newHead) { + this.head = StringUtils.isEmpty(newHead) ? head : newHead; + changed = true; + } - public GhprbPullRequest(GHPullRequest pr, Ghprb ghprb, GhprbRepository repo) { + private void setAccepted(boolean shouldRun) { + accepted = true; + this.shouldRun = shouldRun; + changed = true; + } + + public GhprbPullRequest(GHPullRequest pr, Ghprb ghprb, GhprbRepository repo, boolean isNew) { id = pr.getNumber(); this.pr = pr; @@ -67,14 +84,18 @@ public GhprbPullRequest(GHPullRequest pr, Ghprb ghprb, GhprbRepository repo) { this.repo = repo; try { - updated = pr.getUpdatedAt(); + if (isNew) { + setUpdated(pr.getCreatedAt()); + } else { + setUpdated(pr.getUpdatedAt()); + } } catch (IOException e) { logger.log(Level.WARNING, "Unable to get date for new PR", e); - updated = new Date(); + setUpdated(new Date()); } GHCommitPointer prHead = pr.getHead(); - head = prHead.getSha(); + setHead(prHead.getSha()); GHUser author = pr.getUser(); @@ -83,8 +104,7 @@ public GhprbPullRequest(GHPullRequest pr, Ghprb ghprb, GhprbRepository repo) { try { if (ghprb.isWhitelisted(getPullRequestAuthor())) { - accepted = true; - shouldRun = true; + setAccepted(true); } else { logger.log(Level.INFO, "Author of #{0} {1} on {2} not in whitelist!", new Object[] { id, author.getLogin(), reponame }); repo.addComment(id, GhprbTrigger.getDscp().getRequestForTestingPhrase()); @@ -167,6 +187,7 @@ public void check(GHIssueComment comment) { tryBuild(); } + private void updatePR(GHPullRequest pr, GHUser user) { this.pr = pr; @@ -177,7 +198,7 @@ private void updatePR(GHPullRequest pr, GHUser user) { // the author of the PR could have been whitelisted since its creation if (!accepted && helper.isWhitelisted(pr.getUser())) { logger.log(Level.INFO, "Pull request #{0}'s author has been whitelisted", new Object[]{id}); - accepted = true; + setAccepted(false); } int commentsChecked = checkComments(pr, lastUpdateTime); @@ -218,13 +239,13 @@ private boolean isUpdated(GHPullRequest pr) { try { lastUpdated = pr.getUpdatedAt(); ret = updated.compareTo(lastUpdated) < 0; - updated = lastUpdated; + setUpdated(lastUpdated); } catch (Exception e) { logger.log(Level.WARNING, "Unable to update last updated date", e); } GHCommitPointer pointer = pr.getHead(); String pointerSha = pointer.getSha(); - ret = ret || !pointerSha.equals(head); + ret |= !pointerSha.equals(head); return ret; } @@ -270,7 +291,8 @@ private void tryBuild() { } private void build() { - helper.getBuilds().build(this, triggerSender, commentBody); + GhprbBuilds builder = helper.getBuilds(); + builder.build(this, triggerSender, commentBody); } // returns false if no new commit @@ -279,7 +301,7 @@ private boolean checkCommit(GHCommitPointer sha) { return false; } logger.log(Level.FINE, "New commit. Sha: {0} => {1}", new Object[] { head, sha.getSha() }); - head = sha.getSha(); + setHead(sha.getSha()); if (accepted) { shouldRun = true; } @@ -308,12 +330,10 @@ private void checkComment(GHIssueComment comment) throws IOException { logger.log(Level.FINEST, "Author {0} not whitelisted, adding to whitelist.", author); helper.addWhitelist(author.getLogin()); } - accepted = true; - shouldRun = true; + setAccepted(true); } else if (helper.isOktotestPhrase(body) && helper.isAdmin(sender)) { // ok to test logger.log(Level.FINEST, "Admin {0} gave OK to test", sender); - accepted = true; - shouldRun = true; + setAccepted(true); } else if (helper.isRetestPhrase(body)) { // test this please logger.log(Level.FINEST, "Retest phrase"); if (helper.isAdmin(sender)) { @@ -530,5 +550,12 @@ public String getAuthorEmail() { authorEmail = StringUtils.isEmpty(authorEmail) ? "" : authorEmail; return authorEmail; } + + public boolean isChanged() { + return changed == null ? false : changed; + } + public void save() { + changed = false; + } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index c4b658204..948af7fc7 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -18,7 +18,6 @@ import java.net.URL; import java.util.*; import java.util.Map.Entry; -import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -124,7 +123,7 @@ public void check() { return; } } - check(pr); + check(pr, true); closedPulls.remove(pr.getNumber()); } @@ -136,7 +135,7 @@ public void check() { trigger.save(); } - private void check(GHPullRequest pr) { + private void check(GHPullRequest pr, boolean isNew) { Map pulls = trigger.getPullRequests(); final Integer id = pr.getNumber(); @@ -144,8 +143,8 @@ private void check(GHPullRequest pr) { if (pulls.containsKey(id)) { pull = pulls.get(id); } else { - pulls.put(id, new GhprbPullRequest(pr, trigger.getHelper(), this)); - pull = pulls.get(id); + pull = new GhprbPullRequest(pr, trigger.getHelper(), this, isNew); + pulls.put(id, pull); } pull.check(pr); trigger.save(); @@ -304,7 +303,7 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { if (pull == null) { GHRepository repo = getGitHubRepo(); GHPullRequest pr = repo.getPullRequest(id); - pull = new GhprbPullRequest(pr, trigger.getHelper(), this); + pull = new GhprbPullRequest(pr, trigger.getHelper(), this, false); pulls.put(id, pull); } pull.check(issueComment.getComment()); @@ -325,7 +324,7 @@ void onPullRequestHook(PullRequest pr) throws IOException { } else if ("opened".equals(action) || "reopened".equals(action) || "synchronize".equals(action)) { GhprbPullRequest pull = pulls.get(number); if (pull == null) { - pull = new GhprbPullRequest(ghpr, trigger.getHelper(), this); + pull = new GhprbPullRequest(ghpr, trigger.getHelper(), this, "opened".equals(action)); pulls.put(number, pull); } pull.check(ghpr); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index dc40871ac..68881bc66 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -174,7 +174,16 @@ public static DescriptorImpl getDscp() { * Save any updates that may have been made inside the plugin that would affect the config.xml */ public void save() { - if (super.job == null) { + if (super.job == null || pullRequests == null) { + return; + } + boolean save = false; + for (GhprbPullRequest pr : pullRequests.values()) { + if (save || pr.isChanged()) { + pr.save(); + } + } + if (!save) { return; } try { diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java index 72f21e6db..31127bb19 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java @@ -1,5 +1,6 @@ package org.jenkinsci.plugins.ghprb; +import org.joda.time.DateTime; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -17,6 +18,7 @@ import static org.fest.assertions.Assertions.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; @@ -37,43 +39,53 @@ public class GhprbPullRequestTest { @Mock private GhprbRepository repo; @Mock - private GHCommitPointer head; + private GHCommitPointer head, base; @Mock private GhprbRepository ghprbRepository; + @Mock + private GHUser ghUser; + @Mock + private GhprbBuilds builds; @Before public void setup() throws IOException { - given(ghprbRepository.getPullRequest(10)).willReturn(pr); - given(pr.getHead()).willReturn(head); - } - - @Test - public void testConstructorWhenAuthorIsWhitelisted() throws IOException { - // GIVEN - GHUser ghUser = mock(GHUser.class); - GHCommitPointer head = mock(GHCommitPointer.class); - GHCommitPointer base = mock(GHCommitPointer.class); - given(head.getSha()).willReturn("some sha"); given(base.getRef()).willReturn("some ref"); // Mocks for GHPullRequest given(pr.getNumber()).willReturn(10); + given(pr.getCreatedAt()).willReturn(new Date()); given(pr.getUpdatedAt()).willReturn(new Date()); given(pr.getTitle()).willReturn("title"); given(pr.getHead()).willReturn(head); given(pr.getBase()).willReturn(base); - given(pr.getUser()).willReturn(ghUser); + given(ghUser.getEmail()).willReturn("email"); - + + given(ghprbRepository.getPullRequest(10)).willReturn(pr); + given(ghprbRepository.getName()).willReturn("name"); + + given(pr.getHead()).willReturn(head); + given(pr.getUser()).willReturn(ghUser); + + // Mocks for Ghprb + given(helper.isWhitelisted(ghUser)).willReturn(true); + given(helper.getBuilds()).willReturn(builds); + + doNothing().when(builds).build(any(GhprbPullRequest.class), any(GHUser.class), anyString()); + // Mocks for GhprbRepository given(repo.getName()).willReturn("repoName"); - // Mocks for Ghprb - given(helper.isWhitelisted(ghUser)).willReturn(true); + // Mocks for GhprbRepository + doNothing().when(repo).addComment(Mockito.anyInt(), anyString()); + } + + @Test + public void testConstructorWhenAuthorIsWhitelisted() throws IOException { // WHEN - GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); + GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo, false); // THEN assertThat(ghprbPullRequest.getId()).isEqualTo(10); @@ -86,102 +98,45 @@ public void testConstructorWhenAuthorIsWhitelisted() throws IOException { @Test public void testInitRepoNameNull() throws IOException { - // GIVEN - GHUser ghUser = mock(GHUser.class); - GHCommitPointer head = mock(GHCommitPointer.class); - GHCommitPointer base = mock(GHCommitPointer.class); - // Mocks for GHPullRequest - given(pr.getNumber()).willReturn(10); - given(pr.getUpdatedAt()).willReturn(new Date()); - given(pr.getTitle()).willReturn("title"); - given(pr.getHead()).willReturn(head); - given(pr.getBase()).willReturn(base); - given(head.getSha()).willReturn("some sha"); - given(base.getRef()).willReturn("some ref"); - given(pr.getUser()).willReturn(ghUser); - given(ghUser.getEmail()).willReturn("email"); - - // Mocks for GhprbRepository given(repo.getName()).willReturn(null); - doNothing().when(repo).addComment(eq(10), anyString()); - // Mocks for Ghprb - given(helper.isWhitelisted(ghUser)).willReturn(true); - - GhprbPullRequest ghprbPullRequest = Mockito.spy(new GhprbPullRequest(pr, helper, repo)); - given(ghprbRepository.getName()).willReturn("name"); + GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo, false); // WHEN ghprbPullRequest.init(helper, ghprbRepository); // THEN verify(pr, times(1)).getHead(); + verify(pr, times(1)).getNumber(); + verify(pr, times(1)).getUpdatedAt(); + verify(pr, times(3)).getUser(); + Mockito.verifyNoMoreInteractions(pr); } @Test public void testInitRepoNameNotNull() throws IOException { - // GIVEN - GHUser ghUser = mock(GHUser.class); - GHCommitPointer head = mock(GHCommitPointer.class); - GHCommitPointer base = mock(GHCommitPointer.class); - - // Mocks for GHPullRequest - given(pr.getNumber()).willReturn(10); - given(pr.getUpdatedAt()).willReturn(new Date()); - given(pr.getTitle()).willReturn("title"); - given(pr.getHead()).willReturn(head); - given(pr.getBase()).willReturn(base); - given(head.getSha()).willReturn("some sha"); - given(base.getRef()).willReturn("some ref"); - given(pr.getUser()).willReturn(ghUser); - given(ghUser.getEmail()).willReturn("email"); // Mocks for GhprbRepository given(repo.getName()).willReturn("name"); doNothing().when(repo).addComment(eq(10), anyString()); - // Mocks for Ghprb - given(helper.isWhitelisted(ghUser)).willReturn(true); - - GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); - given(ghprbRepository.getName()).willReturn("name"); + GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo, false); // WHEN ghprbPullRequest.init(helper, ghprbRepository); // THEN verify(ghprbRepository, never()).getName(); + Mockito.verifyNoMoreInteractions(ghprbRepository); } @Test public void authorRepoGitUrlShouldBeNullWhenNoRepository() throws Exception { // GIVEN - GHUser ghUser = mock(GHUser.class); - GHCommitPointer head = mock(GHCommitPointer.class); - GHCommitPointer base = mock(GHCommitPointer.class); - - // Mocks for GHPullRequest - given(pr.getNumber()).willReturn(10); - given(pr.getUpdatedAt()).willReturn(new Date()); - given(pr.getTitle()).willReturn("title"); - given(pr.getHead()).willReturn(head); - given(pr.getBase()).willReturn(base); - given(head.getSha()).willReturn("some sha"); - given(base.getRef()).willReturn("some ref"); - given(pr.getUser()).willReturn(ghUser); - given(ghUser.getEmail()).willReturn("email"); - - // Mocks for GhprbRepository - given(repo.getName()).willReturn("name"); - doNothing().when(repo).addComment(eq(10), anyString()); - // Mocks for Ghprb - given(helper.isWhitelisted(ghUser)).willReturn(true); - - GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); - given(ghprbRepository.getName()).willReturn("name"); + GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo, false); // WHEN ghprbPullRequest.init(helper, ghprbRepository); @@ -193,39 +148,40 @@ public void authorRepoGitUrlShouldBeNullWhenNoRepository() throws Exception { @Test public void authorRepoGitUrlShouldBeSetWhenRepository() throws Exception { // GIVEN - GHUser ghUser = mock(GHUser.class); - GHCommitPointer head = mock(GHCommitPointer.class); - GHCommitPointer base = mock(GHCommitPointer.class); - GHRepository repository = mock(GHRepository.class); - - // Mocks for GHPullRequest - given(pr.getNumber()).willReturn(10); - given(pr.getUpdatedAt()).willReturn(new Date()); - given(pr.getTitle()).willReturn("title"); - given(pr.getHead()).willReturn(head); - given(pr.getBase()).willReturn(base); - given(head.getSha()).willReturn("some sha"); - given(base.getRef()).willReturn("some ref"); - given(pr.getUser()).willReturn(ghUser); - given(ghUser.getEmail()).willReturn("email"); - given(head.getRepository()).willReturn(repository); String expectedAuthorRepoGitUrl = "https://github.com/jenkinsci/ghprb-plugin"; + GHRepository repository = mock(GHRepository.class); given(repository.gitHttpTransportUrl()).willReturn(expectedAuthorRepoGitUrl); - // Mocks for GhprbRepository - given(repo.getName()).willReturn("name"); - doNothing().when(repo).addComment(eq(10), anyString()); - - // Mocks for Ghprb - given(helper.isWhitelisted(ghUser)).willReturn(true); - - GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo); - given(ghprbRepository.getName()).willReturn("name"); + given(head.getRepository()).willReturn(repository); - // WHEN - ghprbPullRequest.init(helper, ghprbRepository); + GhprbPullRequest ghprbPullRequest = new GhprbPullRequest(pr, helper, repo, false); // THEN assertThat(ghprbPullRequest.getAuthorRepoGitUrl()).isEqualTo(expectedAuthorRepoGitUrl); } + + @Test + public void pullRequestIsMarkedAsChanged() throws Exception { + GhprbPullRequest pull = new GhprbPullRequest(pr, helper, repo, true); + pull.save(); + assertThat(pull.isChanged() == false); + + given(pr.getUpdatedAt()).willReturn(new DateTime().plusHours(2).toDate()); + pull.check(pr); + assertThat(pull.isChanged() == true); + + } + + @Test + public void pullRequestIsNotMarkedAsChanged() throws Exception { + GhprbPullRequest pull = new GhprbPullRequest(pr, helper, repo, true); + pull.save(); + assertThat(pull.isChanged() == false); + + pull.check(pr); + pull.check(pr); + pull.check(pr); + assertThat(pull.isChanged() == false); + + } } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 0aad464e4..173a05827 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -247,7 +247,8 @@ public void testCheckMethodWithNewPR() throws IOException { verify(ghPullRequest, times(7)).getHead(); verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(5)).getNumber(); - verify(ghPullRequest, times(3)).getUpdatedAt(); + verify(ghPullRequest, times(2)).getUpdatedAt(); + verify(ghPullRequest, times(1)).getCreatedAt(); verify(ghPullRequest, times(1)).getHtmlUrl(); verify(ghPullRequest, times(1)).listCommits(); verify(ghPullRequest, times(1)).getBody(); @@ -283,13 +284,13 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException mockCommitList(); GhprbBuilds builds = mockBuilds(); - Date now = new Date(); + Date later = new DateTime().plusHours(3).toDate(); Date tomorrow = new DateTime().plusDays(1).toDate(); given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(ghPullRequests); - given(ghPullRequest.getUpdatedAt()).willReturn(now).willReturn(now).willReturn(tomorrow); + given(ghPullRequest.getUpdatedAt()).willReturn(later).willReturn(tomorrow); given(ghPullRequest.getNumber()).willReturn(100); given(ghPullRequest.getMergeable()).willReturn(true); given(ghPullRequest.getTitle()).willReturn("title"); @@ -325,13 +326,14 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(ghPullRequest, times(1)).getTitle(); verify(ghPullRequest, times(6)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API - verify(ghPullRequest, times(8)).getHead(); + verify(ghPullRequest, times(9)).getHead(); verify(ghPullRequest, times(1)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(1)).getHtmlUrl(); - verify(ghPullRequest, times(3)).getUpdatedAt(); + verify(ghPullRequest, times(2)).getUpdatedAt(); + verify(ghPullRequest, times(1)).getCreatedAt(); - verify(ghPullRequest, times(1)).getComments(); + verify(ghPullRequest, times(2)).getComments(); verify(ghPullRequest, times(1)).listCommits(); verify(ghPullRequest, times(1)).getBody(); verify(ghPullRequest, times(1)).getId(); @@ -357,7 +359,9 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verifyNoMoreInteractions(ghUser); } - private List createListWithMockPR() { + private List createListWithMockPR() throws IOException { + + given(ghPullRequest.getCreatedAt()).willReturn(new Date()); List ghPullRequests = new ArrayList(); ghPullRequests.add(ghPullRequest); return ghPullRequests; @@ -374,9 +378,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException mockCommitList(); GhprbBuilds builds = mockBuilds(); - given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(ghPullRequests); - - given(ghPullRequest.getUpdatedAt()).willReturn(now).willReturn(now).willReturn(tomorrow); + given(ghPullRequest.getUpdatedAt()).willReturn(now).willReturn(tomorrow); given(ghPullRequest.getNumber()).willReturn(100); given(ghPullRequest.getMergeable()).willReturn(true); given(ghPullRequest.getTitle()).willReturn("title"); @@ -385,6 +387,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException given(ghPullRequest.getApiURL()).willReturn(new URL("https://github.com/org/repo/pull/100")); given(ghPullRequest.getId()).willReturn(100); given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); + given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(ghPullRequests); given(ghUser.getEmail()).willReturn("email"); given(ghUser.getLogin()).willReturn("login"); @@ -418,7 +421,8 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(ghPullRequest, times(10)).getHead(); verify(ghPullRequest, times(2)).getBase(); verify(ghPullRequest, times(5)).getNumber(); - verify(ghPullRequest, times(3)).getUpdatedAt(); + verify(ghPullRequest, times(2)).getUpdatedAt(); + verify(ghPullRequest, times(1)).getCreatedAt(); verify(ghPullRequest, times(2)).getHtmlUrl(); verify(ghPullRequest, times(1)).getId(); @@ -558,7 +562,7 @@ private void initGHPRWithTestData() throws IOException { pulls = new ConcurrentHashMap(); ghprbRepository = new GhprbRepository(TEST_USER_NAME, TEST_REPO_NAME, trigger); - ghprbPullRequest = new GhprbPullRequest(ghPullRequest, helper, ghprbRepository); + ghprbPullRequest = new GhprbPullRequest(ghPullRequest, helper, ghprbRepository, false); given(trigger.getPullRequests()).willReturn(pulls); From 679a4fe95e01ede85467bf5e8f61ad62973d890a Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 25 Jan 2016 20:25:53 -0700 Subject: [PATCH 136/175] Add some synchronization where needed and fix tests. --- .../plugins/ghprb/GhprbGitHubAuth.java | 10 ++-- .../plugins/ghprb/GhprbRepository.java | 57 ++++++++++--------- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 15 ++--- .../plugins/ghprb/GhprbITBaseTestCase.java | 1 + .../plugins/ghprb/GhprbRepositoryTest.java | 3 + 5 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java index 3a93e4938..b588503a8 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java @@ -198,11 +198,13 @@ private void buildConnection(Item context) { } public GitHub getConnection(Item context) throws IOException { - if (gh == null) { - buildConnection(context); + synchronized (credentialsId) { + if (gh == null) { + buildConnection(context); + } + + return gh; } - - return gh; } @Override diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 948af7fc7..e16f25c2c 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -136,17 +136,13 @@ public void check() { } private void check(GHPullRequest pr, boolean isNew) { - Map pulls = trigger.getPullRequests(); - - final Integer id = pr.getNumber(); - GhprbPullRequest pull; - if (pulls.containsKey(id)) { - pull = pulls.get(id); - } else { - pull = new GhprbPullRequest(pr, trigger.getHelper(), this, isNew); - pulls.put(id, pull); + int number = pr.getNumber(); + try { + GhprbPullRequest pull = getPullRequest(null, isNew, number); + pull.check(pr); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to check pr: " + number, e); } - pull.check(pr); trigger.save(); } @@ -290,25 +286,38 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { logger.log(Level.FINE, "Not checking comments since build is disabled"); return; } - int id = issueComment.getIssue().getNumber(); + int number = issueComment.getIssue().getNumber(); logger.log(Level.FINER, "Comment on issue #{0} from {1}: {2}", - new Object[] { id, issueComment.getComment().getUser(), issueComment.getComment().getBody() }); + new Object[] { number, issueComment.getComment().getUser(), issueComment.getComment().getBody() }); + if (!"created".equals(issueComment.getAction())) { return; } - Map pulls = trigger.getPullRequests(); - - GhprbPullRequest pull = pulls.get(id); - if (pull == null) { - GHRepository repo = getGitHubRepo(); - GHPullRequest pr = repo.getPullRequest(id); - pull = new GhprbPullRequest(pr, trigger.getHelper(), this, false); - pulls.put(id, pull); - } + GhprbPullRequest pull = getPullRequest(null, false, number); pull.check(issueComment.getComment()); trigger.save(); } + + private GhprbPullRequest getPullRequest(GHPullRequest ghpr, Boolean isNew, Integer number) throws IOException { + Map prs = trigger.getPullRequests(); + if (number == null) { + number = ghpr.getNumber(); + } + synchronized (prs) { + GhprbPullRequest pr = prs.get(number); + if (pr == null) { + if (ghpr == null) { + GHRepository repo = getGitHubRepo(); + ghpr = repo.getPullRequest(number); + } + pr = new GhprbPullRequest(ghpr, trigger.getHelper(), this, isNew); + prs.put(number, pr); + } + + return pr; + } + } void onPullRequestHook(PullRequest pr) throws IOException { GHPullRequest ghpr = pr.getPullRequest(); @@ -322,11 +331,7 @@ void onPullRequestHook(PullRequest pr) throws IOException { } else if (!trigger.isActive()) { logger.log(Level.FINE, "Not processing Pull request since the build is disabled"); } else if ("opened".equals(action) || "reopened".equals(action) || "synchronize".equals(action)) { - GhprbPullRequest pull = pulls.get(number); - if (pull == null) { - pull = new GhprbPullRequest(ghpr, trigger.getHelper(), this, "opened".equals(action)); - pulls.put(number, pull); - } + GhprbPullRequest pull = getPullRequest(ghpr, false, number); pull.check(ghpr); } else { logger.log(Level.WARNING, "Unknown Pull Request hook action: {0}", action); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 68881bc66..3a1f0b20c 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -48,13 +48,11 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; @@ -201,7 +199,7 @@ public void start(AbstractProject project, boolean newInstance) { try { Map prs = getDescriptor().getPullRequests(project.getFullName()); if (prs != null) { - prs = new HashMap(prs); + prs = new ConcurrentHashMap(prs); if (pullRequests == null) { pullRequests = prs; } else { @@ -244,7 +242,7 @@ public void start(AbstractProject project, boolean newInstance) { public Map getPullRequests() { if (pullRequests == null) { - pullRequests = new HashMap(); + pullRequests = new ConcurrentHashMap(); } return pullRequests; } @@ -633,7 +631,7 @@ public List getDefaultAuth(List githubAuth) { private String requestForTestingPhrase; // map of jobs (by their fullName) and their map of pull requests - private transient Map> jobs; + private transient Map> jobs; /** * map of jobs (by the repo name); No need to keep the projects from shutdown to startup. @@ -664,10 +662,7 @@ public DescriptorImpl() { if (repoJobs == null) { repoJobs = new ConcurrentHashMap>>(); } -// if (jobs == null) { -// jobs = new HashMap>(); -// } -// save(); + save(); } @Override @@ -811,7 +806,7 @@ public ListBoxModel doFillGitHubAuthIdItems(@QueryParameter("gitHubAuthId") Stri public Map getPullRequests(String projectName) { Map ret = null; - if (jobs.containsKey(projectName)) { + if (jobs != null && jobs.containsKey(projectName)) { ret = jobs.get(projectName); jobs.remove(projectName); } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java index 8c5709911..ad4d5c5b6 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java @@ -73,6 +73,7 @@ protected void beforeTest(Map globalConfig, Map given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(newArrayList(ghPullRequest)).willReturn(newArrayList(ghPullRequest)); + given(ghRepository.getPullRequest(Mockito.anyInt())).willReturn(ghPullRequest); given(ghUser.getEmail()).willReturn("email@email.com"); given(ghUser.getLogin()).willReturn("user"); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 173a05827..e6fa42a8a 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -239,6 +239,7 @@ public void testCheckMethodWithNewPR() throws IOException { verify(builds, times(1)).build(any(GhprbPullRequest.class), any(GHUser.class), any(String.class)); verify(ghRepository, times(1)).getPullRequests(OPEN); // Call to Github API verify(ghRepository, times(1)).createCommitStatus(eq("head sha"), eq(PENDING), eq(""), eq(msg), eq("default")); // Call to Github API + verify(ghRepository, times(1)).getPullRequest(Mockito.anyInt()); verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(1)).getTitle(); @@ -321,6 +322,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(builds, times(1)).build(any(GhprbPullRequest.class), any(GHUser.class), any(String.class)); verify(ghRepository, times(2)).getPullRequests(eq(OPEN)); // Call to Github API verify(ghRepository, times(1)).createCommitStatus(eq("head sha"), eq(PENDING), eq(""), eq(msg), eq("default")); // Call to Github API + verify(ghRepository, times(1)).getPullRequest(Mockito.anyInt()); verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(1)).getTitle(); @@ -413,6 +415,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(ghRepository, times(2)).getPullRequests(eq(OPEN)); // Call to Github API verify(ghRepository, times(2)).createCommitStatus(eq("head sha"), eq(PENDING), eq(""), eq(msg), eq("default")); // Call to Github API + verify(ghRepository, times(1)).getPullRequest(Mockito.anyInt()); verifyNoMoreInteractions(ghRepository); verify(ghPullRequest, times(2)).getTitle(); From 5fa2f76cf9505f5c9862ecd624ef9c617a322155 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 25 Jan 2016 20:50:17 -0700 Subject: [PATCH 137/175] finish save logic in trigger --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 3a1f0b20c..68ef401aa 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -178,6 +178,7 @@ public void save() { boolean save = false; for (GhprbPullRequest pr : pullRequests.values()) { if (save || pr.isChanged()) { + save = true; pr.save(); } } @@ -185,6 +186,7 @@ public void save() { return; } try { + logger.log(Level.FINEST, "Saving config update for job"); super.job.save(); } catch (IOException e) { logger.log(Level.SEVERE, "Unable to save config updates", e); From 13bc7fd2fc66a3269cb14f17465d175aaf8b595a Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 26 Jan 2016 10:10:38 -0700 Subject: [PATCH 138/175] Update readme for next release --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index c5f0c17aa..ae9c20dd5 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,15 @@ job('downstreamJob') { ### Updates +#### -> 1.30 +* Merged #253, cleaning up code. +* WebHooks are refactored to be closer to the variables it depends on +* PR data is now local per job instead of global +* The config.xml is only saved when there is a change to a PR the job is watching +* GitHub connections are now shared. +* Shouldn't run into rate limits on startup +* Pull Requests are only updated when the trigger runs, instead of on startup. + #### -> 1.29.8 * Merged #246 adding job dsl features and updating docs From a4a5955cf1f8355e2068264a8f5f29143a8e71ba Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 26 Jan 2016 10:14:06 -0700 Subject: [PATCH 139/175] [maven-release-plugin] prepare release ghprb-1.30 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9d128cd63..e347b3012 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30-SNAPSHOT + 1.30 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.30 From dce405d77d4d29878a693c00cf82cf550d6df995 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 26 Jan 2016 10:14:09 -0700 Subject: [PATCH 140/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e347b3012..182f59564 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30 + 1.31-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.30 + HEAD From 7e782648ef7a99362ed946fcb51b6b12636dbadc Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Fri, 29 Jan 2016 15:02:20 -0800 Subject: [PATCH 141/175] Use message metadata to determine whether issue_comment is pull request Avoids a lot of unneeded API calls that will return 404 --- .../java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index cbcea86b7..f313df21b 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -102,6 +102,11 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { logger.log(Level.INFO, "Skip comment on closed PR"); return; } + + if (!issueComment.getIssue().isPullRequest()) { + logger.log(Level.INFO, "Skip comment on Issue"); + return; + } String repoName = issueComment.getRepository().getFullName(); From 6d3f775e2092aef0ac9d9fb368b2bf4e7c12c7fb Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 1 Feb 2016 07:48:53 -0700 Subject: [PATCH 142/175] Move pull request state into the builds directory Now when a PR updates it will be saved automatically, and not in any of the Ghprb config files --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 50 +------- .../plugins/ghprb/GhprbPullRequestMerge.java | 3 +- .../plugins/ghprb/GhprbRepository.java | 116 +++++++++++++---- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 121 ++++++++++-------- .../jobdsl/GhprbContextExtensionPoint.java | 5 +- .../plugins/ghprb/GhprbITBaseTestCase.java | 6 +- .../ghprb/GhprbPullRequestMergeTest.java | 2 +- .../plugins/ghprb/GhprbRepositoryTest.java | 24 ++-- 8 files changed, 185 insertions(+), 142 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 650ecc213..3d5eba940 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -14,7 +14,6 @@ import com.cloudbees.plugins.credentials.domains.SchemeSpecification; import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder; import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl; -import com.coravy.hudson.plugins.github.GithubProjectProperty; import hudson.Util; import hudson.model.AbstractBuild; @@ -44,7 +43,6 @@ import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -52,39 +50,12 @@ */ public class Ghprb { private static final Logger logger = Logger.getLogger(Ghprb.class.getName()); - private static final Pattern githubUserRepoPattern = Pattern.compile("^(http[s]?://[^/]*)/([^/]*)/([^/]*).*"); + public static final Pattern githubUserRepoPattern = Pattern.compile("^(http[s]?://[^/]*)/([^/]*/[^/]*).*"); private final GhprbTrigger trigger; - private GhprbRepository repository; - private GhprbBuilds builds; - - private transient GhprbGitHub github; public Ghprb(GhprbTrigger trigger) { - - final GithubProjectProperty ghpp = trigger.getActualProject().getProperty(GithubProjectProperty.class); - if (ghpp == null || ghpp.getProjectUrl() == null) { - throw new IllegalStateException("A GitHub project url is required."); - } - String baseUrl = ghpp.getProjectUrl().baseUrl(); - Matcher m = githubUserRepoPattern.matcher(baseUrl); - if (!m.matches()) { - throw new IllegalStateException(String.format("Invalid GitHub project url: %s", baseUrl)); - } - final String user = m.group(2); - final String repo = m.group(3); - this.trigger = trigger; - - this.repository = new GhprbRepository(user, repo, trigger); - this.builds = new GhprbBuilds(trigger, repository); - } - - public void init() { - this.repository.init(); - if (trigger.getUseGitHubHooks()) { - this.repository.createHook(); - } } public void addWhitelist(String author) { @@ -97,33 +68,18 @@ public boolean isProjectDisabled() { } public GhprbBuilds getBuilds() { - return builds; + return trigger.getBuilds(); } public GhprbTrigger getTrigger() { return trigger; } - public GhprbRepository getRepository() { - return repository; - } public GhprbGitHub getGitHub() { - if (github == null) { - github = new GhprbGitHub(trigger); - } - return github; + return trigger.getGhprbGitHub(); } - void run() { - getRepository().check(); - } - - void stop() { - repository = null; - builds = null; - } - public static Pattern compilePattern(String regex) { return Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL); } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index b07777b9a..55e031150 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -109,7 +109,6 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build if (helper == null) { helper = new Ghprb(trigger); - helper.init(); } GHUser triggerSender = cause.getTriggerSender(); @@ -209,7 +208,7 @@ private void deleteBranch(AbstractBuild build, Launcher launcher, final Bu private void commentOnRequest(String comment) { try { - helper.getRepository().addComment(pr.getNumber(), comment); + trigger.getRepository().addComment(pr.getNumber(), comment); } catch (Exception e) { logger.println("Failed to add comment"); e.printStackTrace(logger); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index e16f25c2c..32eef27e7 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -1,49 +1,76 @@ package org.jenkinsci.plugins.ghprb; +import hudson.BulkChange; +import hudson.XmlFile; import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import hudson.model.Items; +import hudson.model.Saveable; import hudson.model.TaskListener; +import hudson.model.listeners.SaveableListener; import jenkins.model.Jenkins; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommentAppender; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildStatus; -import org.kohsuke.github.*; +import org.kohsuke.github.GHCommitState; +import org.kohsuke.github.GHEvent; import org.kohsuke.github.GHEventPayload.IssueComment; import org.kohsuke.github.GHEventPayload.PullRequest; +import org.kohsuke.github.GHHook; +import org.kohsuke.github.GHIssueState; +import org.kohsuke.github.GHPullRequest; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GitHub; +import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; +import java.io.UnsupportedEncodingException; import java.net.URL; -import java.util.*; +import java.net.URLEncoder; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; /** * @author Honza Brázdil */ -public class GhprbRepository { +public class GhprbRepository implements Saveable{ - private static final Logger logger = Logger.getLogger(GhprbRepository.class.getName()); - private static final EnumSet HOOK_EVENTS = EnumSet.of(GHEvent.ISSUE_COMMENT, GHEvent.PULL_REQUEST); + private static final transient Logger logger = Logger.getLogger(GhprbRepository.class.getName()); + private static final transient EnumSet HOOK_EVENTS = EnumSet.of(GHEvent.ISSUE_COMMENT, GHEvent.PULL_REQUEST); private final String reponame; - private GHRepository ghRepository; - private GhprbTrigger trigger; + private transient GHRepository ghRepository; + private transient GhprbTrigger trigger; + private final Map pullRequests; - public GhprbRepository(String user, String repository, GhprbTrigger trigger) { - this.reponame = user + "/" + repository; + public GhprbRepository(String reponame, GhprbTrigger trigger) { + this.pullRequests = new ConcurrentHashMap(); + this.reponame = reponame; this.trigger = trigger; } - + + public void addPullRequests(Map prs) { + pullRequests.putAll(prs); + } + public void init() { // make the initial check call to populate our data structures initGhRepository(); - for (Entry next : trigger.getPullRequests().entrySet()) { + for (Entry next : pullRequests.entrySet()) { GhprbPullRequest pull = next.getValue(); pull.init(trigger.getHelper(), this); } @@ -101,23 +128,24 @@ public void check() { if (!initGhRepository()) { return; } + + GHRepository repo = getGitHubRepo(); List openPulls; try { - openPulls = getGitHubRepo().getPullRequests(GHIssueState.OPEN); + openPulls = repo.getPullRequests(GHIssueState.OPEN); } catch (IOException ex) { logger.log(Level.SEVERE, "Could not retrieve open pull requests.", ex); return; } - Map pulls = trigger.getPullRequests(); - Set closedPulls = new HashSet(pulls.keySet()); + Set closedPulls = new HashSet(pullRequests.keySet()); for (GHPullRequest pr : openPulls) { if (pr.getHead() == null) { // Not sure if we need this, but leaving it for now. try { - pr = getGitHubRepo().getPullRequest(pr.getNumber()); + pr = getPullRequest(pr.getNumber()); } catch (IOException ex) { logger.log(Level.SEVERE, "Could not retrieve pr " + pr.getNumber(), ex); return; @@ -130,9 +158,13 @@ public void check() { // remove closed pulls so we don't check them again for (Integer id : closedPulls) { - pulls.remove(id); + pullRequests.remove(id); + } + try { + this.save(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to save repository!", e); } - trigger.save(); } private void check(GHPullRequest pr, boolean isNew) { @@ -143,7 +175,11 @@ private void check(GHPullRequest pr, boolean isNew) { } catch (IOException e) { logger.log(Level.SEVERE, "Unable to check pr: " + number, e); } - trigger.save(); + try { + this.save(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to save repository!", e); + } } public void commentOnFailure(AbstractBuild build, TaskListener listener, GhprbCommitStatusException ex) { @@ -296,23 +332,26 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { GhprbPullRequest pull = getPullRequest(null, false, number); pull.check(issueComment.getComment()); - trigger.save(); + try { + this.save(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to save repository!", e); + } } private GhprbPullRequest getPullRequest(GHPullRequest ghpr, Boolean isNew, Integer number) throws IOException { - Map prs = trigger.getPullRequests(); if (number == null) { number = ghpr.getNumber(); } - synchronized (prs) { - GhprbPullRequest pr = prs.get(number); + synchronized (pullRequests) { + GhprbPullRequest pr = pullRequests.get(number); if (pr == null) { if (ghpr == null) { GHRepository repo = getGitHubRepo(); ghpr = repo.getPullRequest(number); } pr = new GhprbPullRequest(ghpr, trigger.getHelper(), this, isNew); - prs.put(number, pr); + pullRequests.put(number, pr); } return pr; @@ -324,10 +363,9 @@ void onPullRequestHook(PullRequest pr) throws IOException { int number = pr.getNumber(); String action = pr.getAction(); - Map pulls = trigger.getPullRequests(); if ("closed".equals(action)) { - pulls.remove(number); + pullRequests.remove(number); } else if (!trigger.isActive()) { logger.log(Level.FINE, "Not processing Pull request since the build is disabled"); } else if ("opened".equals(action) || "reopened".equals(action) || "synchronize".equals(action)) { @@ -344,4 +382,32 @@ public GHRepository getGitHubRepo() { } return ghRepository; } + + public void load() throws IOException { + XmlFile xml = getConfigXml(trigger.getActualProject()); + if(xml.exists()){ + xml.unmarshal(this); + } else { + save(); + } + } + + public void save() throws IOException { + if(BulkChange.contains(this)) { + return; + } + XmlFile config = getConfigXml(trigger.getActualProject()); + config.write(this); + SaveableListener.fireOnChange(this, config); + } + + protected XmlFile getConfigXml(AbstractProject project) throws IOException { + try { + String escapedRepoName = URLEncoder.encode(reponame, "UTF8"); + File file = new File(project.getBuildDir() + "/pullrequests", escapedRepoName); + return Items.getConfigFile(file); + } catch (UnsupportedEncodingException e) { + throw new IOException(e); + } + } } \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 68ef401aa..f1aae41fe 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -55,6 +55,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -81,7 +82,9 @@ public class GhprbTrigger extends GhprbTriggerBackwardsCompatible { private transient Ghprb helper; - + private transient GhprbRepository repository; + private transient GhprbBuilds builds; + private transient GhprbGitHub ghprbGitHub; private DescribableList extensions = new DescribableList(Saveable.NOOP); @@ -125,8 +128,7 @@ public GhprbTrigger(String adminlist, String commitStatusContext, String gitHubAuthId, String buildDescTemplate, - List extensions, - Map pullRequests + List extensions ) throws ANTLRException { super(cron); this.adminlist = adminlist; @@ -145,7 +147,6 @@ public GhprbTrigger(String adminlist, this.buildDescTemplate = buildDescTemplate; setExtensions(extensions); configVersion = latestVersion; - this.pullRequests = pullRequests; } @Override @@ -168,51 +169,54 @@ public static DescriptorImpl getDscp() { return DESCRIPTOR; } - /** - * Save any updates that may have been made inside the plugin that would affect the config.xml - */ - public void save() { - if (super.job == null || pullRequests == null) { - return; - } - boolean save = false; - for (GhprbPullRequest pr : pullRequests.values()) { - if (save || pr.isChanged()) { - save = true; - pr.save(); - } - } - if (!save) { - return; + private void initState() throws IOException { + + final GithubProjectProperty ghpp = super.job.getProperty(GithubProjectProperty.class); + if (ghpp == null || ghpp.getProjectUrl() == null) { + throw new IllegalStateException("A GitHub project url is required."); } - try { - logger.log(Level.FINEST, "Saving config update for job"); - super.job.save(); - } catch (IOException e) { - logger.log(Level.SEVERE, "Unable to save config updates", e); + String baseUrl = ghpp.getProjectUrl().baseUrl(); + Matcher m = Ghprb.githubUserRepoPattern.matcher(baseUrl); + if (!m.matches()) { + throw new IllegalStateException(String.format("Invalid GitHub project url: %s", baseUrl)); } - } + final String reponame = m.group(2); - @Override - public void start(AbstractProject project, boolean newInstance) { - // We should always start the trigger, and handle cases where we don't run in the run function. - super.start(project, newInstance); + this.repository = new GhprbRepository(reponame, this); + Map pulls = this.pullRequests; + this.pullRequests = null; + try { - Map prs = getDescriptor().getPullRequests(project.getFullName()); + Map prs = getDescriptor().getPullRequests(super.job.getFullName()); if (prs != null) { prs = new ConcurrentHashMap(prs); - if (pullRequests == null) { - pullRequests = prs; + if (pulls == null) { + pulls = prs; } else { - pullRequests.putAll(prs); + pulls.putAll(prs); } } } catch (Exception e) { logger.log(Level.SEVERE, "Unable to transfer map of pull requests", e); } - save(); + if (pulls != null) { + this.repository.addPullRequests(pulls); + } else { + this.repository.load(); + } + this.builds = new GhprbBuilds(this, repository); + + this.repository.init(); + this.ghprbGitHub = new GhprbGitHub(this); + } + + + @Override + public void start(AbstractProject project, boolean newInstance) { + // We should always start the trigger, and handle cases where we don't run in the run function. + super.start(project, newInstance); String name = project.getFullName(); @@ -225,17 +229,19 @@ public void start(AbstractProject project, boolean newInstance) { return; } try { - helper = new Ghprb(this); - } catch (IllegalStateException ex) { + initState(); + } catch (Exception ex) { logger.log(Level.SEVERE, "Can't start ghprb trigger", ex); return; } logger.log(Level.INFO, "Starting the ghprb trigger for the {0} job; newInstance is {1}", new String[] { name, String.valueOf(newInstance) }); - helper.init(); + + helper = new Ghprb(this); if (getUseGitHubHooks()) { + this.repository.createHook(); DESCRIPTOR.addRepoTrigger(getRepository().getName(), super.job); } } @@ -253,16 +259,11 @@ public Map getPullRequests() { public void stop() { String name = super.job != null ? super.job.getFullName(): "NOT STARTED"; logger.log(Level.INFO, "Stopping the ghprb trigger for project {0}", name); - if (helper != null) { - GhprbRepository repository = getRepository(); - if (repository != null) { - String repo = repository.getName(); - if (!StringUtils.isEmpty(repo)) { - DESCRIPTOR.removeRepoTrigger(repo, super.job); - } + if (this.repository != null) { + String repo = this.repository.getName(); + if (!StringUtils.isEmpty(repo)) { + DESCRIPTOR.removeRepoTrigger(repo, super.job); } - helper.stop(); - helper = null; } super.stop(); } @@ -281,8 +282,7 @@ public void run() { logger.log(Level.FINE, "Running trigger for {0}", super.job.getFullName()); - helper.run(); - save(); + this.repository.check(); } public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { @@ -400,7 +400,7 @@ private BuildData findPreviousBuildForPullId(StringParameterValue pullIdPv) { } return null; } - + private ArrayList getDefaultParameters() { ArrayList values = new ArrayList(); ParametersDefinitionProperty pdp = this.job.getProperty(ParametersDefinitionProperty.class); @@ -513,7 +513,17 @@ void setHelper(Ghprb helper) { } public GhprbBuilds getBuilds() { - return isActive() ? helper.getBuilds() : null; + if (this.builds == null && this.isActive()) { + this.builds = new GhprbBuilds(this, getRepository()); + } + return this.builds; + } + + public GhprbGitHub getGhprbGitHub() { + if (this.ghprbGitHub == null && this.isActive()) { + this.ghprbGitHub = new GhprbGitHub(this); + } + return this.ghprbGitHub; } public boolean isActive() { @@ -534,7 +544,14 @@ public boolean isActive() { } public GhprbRepository getRepository() { - return isActive() ? helper.getRepository() : null; + if (this.repository == null && this.isActive()) { + try { + this.initState(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to init trigger state!", e); + } + } + return this.repository; } public String getProjectName() { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java index 671f1c3bd..ae4c5593b 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/jobdsl/GhprbContextExtensionPoint.java @@ -8,12 +8,10 @@ import javaposse.jobdsl.dsl.helpers.wrapper.WrapperContext; import javaposse.jobdsl.plugin.ContextExtensionPoint; import javaposse.jobdsl.plugin.DslExtensionMethod; -import org.jenkinsci.plugins.ghprb.GhprbBranch; import org.jenkinsci.plugins.ghprb.GhprbPullRequestMerge; import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.jenkinsci.plugins.ghprb.upstream.GhprbUpstreamStatus; -import java.util.ArrayList; @Extension(optional = true) public class GhprbContextExtensionPoint extends ContextExtensionPoint { @@ -40,8 +38,7 @@ public Object githubPullRequest(Runnable closure) throws ANTLRException { null, null, null, - context.extensionContext.extensions, - null + context.extensionContext.extensions ); } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java index ad4d5c5b6..4f6eb1317 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java @@ -83,22 +83,22 @@ protected void beforeTest(Map globalConfig, Map GhprbTestUtil.mockCommitList(ghPullRequest); - GhprbRepository repo = Mockito.spy(new GhprbRepository("user", "dropwizard", trigger)); + GhprbRepository repo = Mockito.spy(new GhprbRepository("user/dropwizard", trigger)); Mockito.doReturn(ghRepository).when(repo).getGitHubRepo(); Mockito.doNothing().when(repo).addComment(Mockito.anyInt(), Mockito.anyString(), any(AbstractBuild.class), any(TaskListener.class)); + Mockito.doReturn(repo).when(trigger).getRepository(); builds = new GhprbBuilds(trigger, repo); // Creating spy on ghprb, configuring repo given(helper.getGitHub()).willReturn(ghprbGitHub); - given(helper.getRepository()).willReturn(repo); given(helper.getTrigger()).willReturn(trigger); given(helper.isWhitelisted(ghUser)).willReturn(true); given(helper.getBuilds()).willReturn(builds); - Mockito.doCallRealMethod().when(helper).run(); + Mockito.doCallRealMethod().when(trigger).run(); // Configuring and adding Ghprb trigger diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index c2c787580..78d0c7363 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -110,6 +110,7 @@ public void beforeTest() throws Exception { triggerValues.put("triggerPhrase", triggerPhrase); GhprbTrigger trigger = GhprbTestUtil.getTrigger(triggerValues); + Mockito.doReturn(repo).when(trigger).getRepository(); ConcurrentMap pulls = new ConcurrentHashMap(1); @@ -163,7 +164,6 @@ public void beforeTest() throws Exception { helper = spy(new Ghprb(trigger)); given(trigger.getPullRequests()).willReturn(pulls); trigger.setHelper(helper); - given(helper.getRepository()).willReturn(repo); given(helper.isBotUser(any(GHUser.class))).willReturn(false); } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index e6fa42a8a..38e451596 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -26,7 +26,10 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; + +import hudson.model.AbstractBuild; import hudson.model.AbstractProject; +import hudson.model.TaskListener; import hudson.model.queue.QueueTaskFuture; import java.io.FileNotFoundException; @@ -64,8 +67,7 @@ @RunWith(MockitoJUnitRunner.class) public class GhprbRepositoryTest { - private static final String TEST_USER_NAME = "test-user"; - private static final String TEST_REPO_NAME = "test-repo"; + private static final String TEST_REPO_NAME = "test-user/test-repo"; private static final Date UPDATE_DATE = new Date(); private static final String msg = "Build triggered. sha1 is merged."; @@ -104,8 +106,13 @@ public void setUp() throws Exception { trigger.setHelper(helper); gt = trigger.getGitHub(); + pulls = new ConcurrentHashMap(); + doReturn(mock(QueueTaskFuture.class)).when(trigger).startJob(any(GhprbCause.class), any(GhprbRepository.class)); + doReturn(ghprbRepository).when(trigger).getRepository(); initGHPRWithTestData(); + + given(ghPullRequest.getUser()).willReturn(ghUser); // Mock github API given(helper.getGitHub()).willReturn(gitHub); @@ -159,14 +166,16 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { // GIVEN List ghPullRequests = createListWithMockPR(); given(ghRepository.getPullRequests(eq(GHIssueState.OPEN))).willReturn(ghPullRequests); - given(ghRepository.getPullRequest(ghPullRequest.getId())).willReturn(ghPullRequest); + given(ghRepository.getPullRequest(Mockito.anyInt())).willReturn(ghPullRequest); + doReturn(ghRepository).when(ghprbRepository).getGitHubRepo(); mockHeadAndBase(); mockCommitList(); given(helper.ifOnlyTriggerPhrase()).willReturn(true); pulls.put(1, ghprbPullRequest); + ghprbRepository.addPullRequests(pulls); given(ghPullRequest.getUpdatedAt()).willReturn(UPDATE_DATE); given(ghPullRequest.getNumber()).willReturn(1); @@ -186,7 +195,6 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { verify(ghPullRequest, times(2)).getNumber(); verify(ghPullRequest, times(1)).getUpdatedAt(); verify(ghPullRequest, times(1)).getUser(); - verify(ghPullRequest, times(1)).getId(); verifyNoMoreInteractions(ghPullRequest); verify(helper).ifOnlyTriggerPhrase(); @@ -563,12 +571,12 @@ private void initGHPRWithTestData() throws IOException { given(ghPullRequest.getHead()).willReturn(head); given(head.getSha()).willReturn("head sha"); - pulls = new ConcurrentHashMap(); - ghprbRepository = new GhprbRepository(TEST_USER_NAME, TEST_REPO_NAME, trigger); + ghprbRepository = spy(new GhprbRepository(TEST_REPO_NAME, trigger)); + Mockito.doNothing().when(ghprbRepository).addComment(Mockito.anyInt(), anyString()); + Mockito.doNothing().when(ghprbRepository).addComment(Mockito.anyInt(), anyString(), any(AbstractBuild.class), any(TaskListener.class)); + ghprbPullRequest = new GhprbPullRequest(ghPullRequest, helper, ghprbRepository, false); - given(trigger.getPullRequests()).willReturn(pulls); - // Reset mocks not to mix init data invocations with tests reset(ghPullRequest, ghUser, helper, head, base); } From 661ec34aee804b069e49c932885faa30a4bae3a5 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 1 Feb 2016 14:56:16 -0700 Subject: [PATCH 143/175] Fix issues where current PR status wasn't kept --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 2 +- .../plugins/ghprb/GhprbRepository.java | 3 +-- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 26 ++++++++----------- .../GhprbTriggerBackwardsCompatible.java | 3 +++ .../ghprb/GhprbPullRequestMergeTest.java | 3 +-- .../plugins/ghprb/GhprbRepositoryTest.java | 8 ++++-- .../plugins/ghprb/GhprbTestUtil.java | 2 -- 7 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 3d5eba940..062f9dc1b 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -64,7 +64,7 @@ public void addWhitelist(String author) { } public boolean isProjectDisabled() { - return trigger.getActualProject().isDisabled(); + return !trigger.isActive(); } public GhprbBuilds getBuilds() { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 32eef27e7..df711915e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -387,9 +387,8 @@ public void load() throws IOException { XmlFile xml = getConfigXml(trigger.getActualProject()); if(xml.exists()){ xml.unmarshal(this); - } else { - save(); } + save(); } public void save() throws IOException { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index f1aae41fe..1cdd3eb98 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -168,7 +168,8 @@ private void checkGitHubApiAuth() { public static DescriptorImpl getDscp() { return DESCRIPTOR; } - + + @SuppressWarnings("deprecation") private void initState() throws IOException { final GithubProjectProperty ghpp = super.job.getProperty(GithubProjectProperty.class); @@ -183,6 +184,7 @@ private void initState() throws IOException { final String reponame = m.group(2); this.repository = new GhprbRepository(reponame, this); + this.repository.load(); Map pulls = this.pullRequests; this.pullRequests = null; @@ -203,8 +205,7 @@ private void initState() throws IOException { if (pulls != null) { this.repository.addPullRequests(pulls); - } else { - this.repository.load(); + this.repository.save(); } this.builds = new GhprbBuilds(this, repository); @@ -246,14 +247,6 @@ public void start(AbstractProject project, boolean newInstance) { } } - private Map pullRequests; - - public Map getPullRequests() { - if (pullRequests == null) { - pullRequests = new ConcurrentHashMap(); - } - return pullRequests; - } @Override public void stop() { @@ -472,6 +465,9 @@ public Boolean getUseGitHubHooks() { } public Ghprb getHelper() { + if (helper == null) { + helper = new Ghprb(this); + } return helper; } @@ -532,11 +528,11 @@ public boolean isActive() { if (super.job == null) { logger.log(Level.FINE, "Project was never set, start was never run"); isActive = false; - } else if ((helper != null && helper.isProjectDisabled()) || (super.job != null && super.job.isDisabled())) { + } else if (super.job.isDisabled()) { logger.log(Level.FINE, "Project is disabled, ignoring trigger run call for job {0}", name); isActive = false; - } else if (helper == null) { - logger.log(Level.SEVERE, "The ghprb trigger for {0} wasn''t properly started - helper is null", name); + } else if (getRepository() == null) { + logger.log(Level.SEVERE, "The ghprb trigger for {0} wasn''t properly started - repository is null", name); isActive = false; } @@ -544,7 +540,7 @@ public boolean isActive() { } public GhprbRepository getRepository() { - if (this.repository == null && this.isActive()) { + if (this.repository == null && super.job != null && !super.job.isDisabled()) { try { this.initState(); } catch (IOException e) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java index ec3c6d424..a67506220 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.apache.commons.lang.StringUtils; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; @@ -47,6 +48,8 @@ public GhprbTriggerBackwardsCompatible(String cron) throws ANTLRException { protected transient String project; @Deprecated protected transient AbstractProject _project; + @Deprecated + protected transient Map pullRequests; diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 78d0c7363..2684d1065 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -119,8 +119,8 @@ public void beforeTest() throws Exception { jobs.put("project", pulls); Mockito.doReturn(project).when(trigger).getActualProject(); - Mockito.doReturn(pulls).when(trigger).getPullRequests(); Mockito.doReturn(repo).when(trigger).getRepository(); + repo.addPullRequests(pulls); Mockito.doReturn(pr).when(repo).getPullRequest(pullId); @@ -162,7 +162,6 @@ public void beforeTest() throws Exception { jobsField.set(descriptor, jobs); helper = spy(new Ghprb(trigger)); - given(trigger.getPullRequests()).willReturn(pulls); trigger.setHelper(helper); given(helper.isBotUser(any(GHUser.class))).willReturn(false); } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 38e451596..05106144a 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -24,6 +24,8 @@ import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; +import com.coravy.hudson.plugins.github.GithubProjectProperty; + import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -101,9 +103,11 @@ public class GhprbRepositoryTest { @Before public void setUp() throws Exception { AbstractProject project = jenkinsRule.createFreeStyleProject("GhprbRepoTest"); + project.addProperty(new GithubProjectProperty("https://github.com/" + TEST_REPO_NAME)); trigger = GhprbTestUtil.getTrigger(null); trigger.start(project, true); trigger.setHelper(helper); + gt = trigger.getGitHub(); pulls = new ConcurrentHashMap(); @@ -501,7 +505,7 @@ public void testCheckMethodWithNoPR() throws IOException { // WHEN ghprbRepository.check(); - verify(helper).isProjectDisabled(); + verify(trigger).isActive(); // THEN verifyGetGithub(2, 1); @@ -520,7 +524,7 @@ public void testExceedRateLimit() throws IOException { ghprbRepository.check(); // THEN - verify(trigger, times(2)).getGitHub(); + verify(trigger, times(1)).getGitHub(); verify(gt, only()).getRateLimit(); verifyZeroInteractions(ghRepository); verifyZeroInteractions(gitHub); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java index d44f2cd3c..caafef707 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java @@ -387,8 +387,6 @@ public static GhprbTrigger getTrigger(Map values) throws Excepti GitHub github = Mockito.mock(GitHub.class); given(github.getRateLimit()).willReturn(limit); - ConcurrentMap pulls = new ConcurrentHashMap(1); - Mockito.doReturn(pulls).when(trigger).getPullRequests(); Mockito.doReturn(github).when(trigger).getGitHub(); return trigger; From da913959db9c7a03b6429caa84038e48bcf0646e Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 1 Feb 2016 19:09:58 -0700 Subject: [PATCH 144/175] Fix test for new architecture --- .../plugins/ghprb/GhprbRepositoryTest.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 05106144a..a62ad2e4f 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -73,6 +73,7 @@ public class GhprbRepositoryTest { private static final Date UPDATE_DATE = new Date(); private static final String msg = "Build triggered. sha1 is merged."; + @Mock private GitHub gt; @Mock private GHRepository ghRepository; @@ -105,15 +106,18 @@ public void setUp() throws Exception { AbstractProject project = jenkinsRule.createFreeStyleProject("GhprbRepoTest"); project.addProperty(new GithubProjectProperty("https://github.com/" + TEST_REPO_NAME)); trigger = GhprbTestUtil.getTrigger(null); + doReturn(gt).when(trigger).getGitHub(); + + given(gt.getRepository(anyString())).willReturn(ghRepository); + trigger.start(project, true); trigger.setHelper(helper); - gt = trigger.getGitHub(); pulls = new ConcurrentHashMap(); + doReturn(mock(QueueTaskFuture.class)).when(trigger).startJob(any(GhprbCause.class), any(GhprbRepository.class)); - doReturn(ghprbRepository).when(trigger).getRepository(); initGHPRWithTestData(); given(ghPullRequest.getUser()).willReturn(ghUser); @@ -203,7 +207,7 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { verify(helper).ifOnlyTriggerPhrase(); verify(helper).getWhiteListTargetBranches(); - verify(helper, times(3)).isProjectDisabled(); + verify(helper, times(2)).isProjectDisabled(); verify(helper).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); verifyNoMoreInteractions(gt); @@ -272,7 +276,7 @@ public void testCheckMethodWithNewPR() throws IOException { verify(helper, times(2)).ifOnlyTriggerPhrase(); verify(helper, times(1)).getBuilds(); verify(helper, times(2)).getWhiteListTargetBranches(); - verify(helper, times(5)).isProjectDisabled(); + verify(helper, times(4)).isProjectDisabled(); verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); @@ -363,7 +367,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(helper).isOktotestPhrase(eq("comment body")); verify(helper).isRetestPhrase(eq("comment body")); verify(helper).isTriggerPhrase(eq("comment body")); - verify(helper, times(6)).isProjectDisabled(); + verify(helper, times(4)).isProjectDisabled(); verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); @@ -456,7 +460,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(helper).isOktotestPhrase(eq("test this please")); verify(helper).isRetestPhrase(eq("test this please")); verify(helper).isAdmin(eq(ghUser)); - verify(helper, times(6)).isProjectDisabled(); + verify(helper, times(4)).isProjectDisabled(); verify(helper, times(2)).checkSkipBuild(eq(ghPullRequest)); verifyNoMoreInteractions(helper); @@ -524,8 +528,8 @@ public void testExceedRateLimit() throws IOException { ghprbRepository.check(); // THEN - verify(trigger, times(1)).getGitHub(); - verify(gt, only()).getRateLimit(); + verify(trigger, times(2)).getGitHub(); + verifyGetGithub(2, 0); verifyZeroInteractions(ghRepository); verifyZeroInteractions(gitHub); verifyZeroInteractions(gt); @@ -576,9 +580,12 @@ private void initGHPRWithTestData() throws IOException { given(head.getSha()).willReturn("head sha"); ghprbRepository = spy(new GhprbRepository(TEST_REPO_NAME, trigger)); + Mockito.doNothing().when(ghprbRepository).addComment(Mockito.anyInt(), anyString()); Mockito.doNothing().when(ghprbRepository).addComment(Mockito.anyInt(), anyString(), any(AbstractBuild.class), any(TaskListener.class)); + doReturn(ghprbRepository).when(trigger).getRepository(); + ghprbPullRequest = new GhprbPullRequest(ghPullRequest, helper, ghprbRepository, false); // Reset mocks not to mix init data invocations with tests @@ -592,7 +599,7 @@ private void increaseRateLimitToDefaults() { // Verifications private void verifyGetGithub(int callsCount, int repoTimes) throws IOException { verify(trigger, times(callsCount)).getGitHub(); - verify(gt, times(1)).getRateLimit(); + verify(gt, times(callsCount)).getRateLimit(); verify(gt, times(repoTimes)).getRepository(anyString()); } } From 65cadd8bd7d3a63094d10f085463942de3363296 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 2 Feb 2016 09:33:04 -0700 Subject: [PATCH 145/175] Update readme for next release --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index ae9c20dd5..521a271fd 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,11 @@ job('downstreamJob') { ### Updates +#### -> 1.31 +* Moved pull request state into build/pullrequests directory. +* Dynamic state is no longer kept as part of the trigger +* Merged #258 ignore comments on issues that aren't pull requests + #### -> 1.30 * Merged #253, cleaning up code. * WebHooks are refactored to be closer to the variables it depends on From e89a328711930673a4977ca89236418d0f5ed7a3 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 2 Feb 2016 09:34:02 -0700 Subject: [PATCH 146/175] Fix version for patch bump --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 521a271fd..54f6c604b 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ job('downstreamJob') { ### Updates -#### -> 1.31 +#### -> 1.30.1 * Moved pull request state into build/pullrequests directory. * Dynamic state is no longer kept as part of the trigger * Merged #258 ignore comments on issues that aren't pull requests From 56296b365b5c3ae3993c69a0401eb3313661c937 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 2 Feb 2016 09:38:22 -0700 Subject: [PATCH 147/175] [maven-release-plugin] prepare release ghprb-1.30.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 182f59564..23356f09a 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.31-SNAPSHOT + 1.30.1 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.30.1 From 57ec5d1cf18ab3bdc4fd3576b7e20d752d00b6e7 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 2 Feb 2016 09:38:25 -0700 Subject: [PATCH 148/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 23356f09a..182f59564 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30.1 + 1.31-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.30.1 + HEAD From 466f769f2c8851d2b8da19f98901e4c407eb79fc Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 5 Feb 2016 06:50:55 -0700 Subject: [PATCH 149/175] Add a check to see if the base of a PR has changed --- .../plugins/ghprb/GhprbPullRequest.java | 44 ++++++++++++------- .../plugins/ghprb/GhprbPullRequestTest.java | 26 ----------- .../plugins/ghprb/GhprbRepositoryTest.java | 7 +-- 3 files changed, 31 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 41731cc31..83dec91aa 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -55,24 +55,25 @@ public class GhprbPullRequest { private final int id; private Date updated; // Needed to track when the PR was updated private String head; + private String base; private boolean accepted = false; // Needed to see if the PR has been added to the accepted list - private Boolean changed = true; // Keep track for when the job config needs to be saved again. private void setUpdated(Date lastUpdateTime) { updated = lastUpdateTime; - changed = true; } private void setHead(String newHead) { this.head = StringUtils.isEmpty(newHead) ? head : newHead; - changed = true; + } + + private void setBase(String newBase) { + this.base = StringUtils.isEmpty(newBase) ? base : newBase; } private void setAccepted(boolean shouldRun) { accepted = true; this.shouldRun = shouldRun; - changed = true; } public GhprbPullRequest(GHPullRequest pr, Ghprb ghprb, GhprbRepository repo, boolean isNew) { @@ -97,6 +98,8 @@ public GhprbPullRequest(GHPullRequest pr, Ghprb ghprb, GhprbRepository repo, boo GHCommitPointer prHead = pr.getHead(); setHead(prHead.getSha()); + GHCommitPointer prBase = pr.getBase(); + setBase(prBase.getSha()); GHUser author = pr.getUser(); String reponame = repo.getName(); @@ -202,7 +205,7 @@ private void updatePR(GHPullRequest pr, GHUser user) { } int commentsChecked = checkComments(pr, lastUpdateTime); - boolean newCommit = checkCommit(pr.getHead()); + boolean newCommit = checkCommit(pr); if (!newCommit && commentsChecked == 0) { logger.log(Level.INFO, "Pull request #{0} was updated on repo {1} but there aren''t any new comments nor commits; " @@ -246,6 +249,11 @@ private boolean isUpdated(GHPullRequest pr) { GHCommitPointer pointer = pr.getHead(); String pointerSha = pointer.getSha(); ret |= !pointerSha.equals(head); + + pointer = pr.getBase(); + pointerSha = pointer.getSha(); + ret |= !pointerSha.equals(base); + return ret; } @@ -296,12 +304,22 @@ private void build() { } // returns false if no new commit - private boolean checkCommit(GHCommitPointer sha) { - if (head.equals(sha.getSha())) { + private boolean checkCommit(GHPullRequest pr) { + GHCommitPointer head = pr.getHead(); + GHCommitPointer base = pr.getBase(); + + String headSha = head.getSha(); + String baseSha = base.getSha(); + + if (StringUtils.equals(headSha, this.head) && StringUtils.equals(baseSha, this.base)) { return false; } - logger.log(Level.FINE, "New commit. Sha: {0} => {1}", new Object[] { head, sha.getSha() }); - setHead(sha.getSha()); + + logger.log(Level.FINE, "New commit. Sha: Head[{0} => {1}] Base[{2} => {3}]", new Object[] { this.head, headSha, this.base, baseSha }); + + setHead(headSha); + setBase(baseSha); + if (accepted) { shouldRun = true; } @@ -550,12 +568,4 @@ public String getAuthorEmail() { authorEmail = StringUtils.isEmpty(authorEmail) ? "" : authorEmail; return authorEmail; } - - public boolean isChanged() { - return changed == null ? false : changed; - } - - public void save() { - changed = false; - } } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java index 31127bb19..0872401fe 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java @@ -1,6 +1,5 @@ package org.jenkinsci.plugins.ghprb; -import org.joda.time.DateTime; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -159,29 +158,4 @@ public void authorRepoGitUrlShouldBeSetWhenRepository() throws Exception { // THEN assertThat(ghprbPullRequest.getAuthorRepoGitUrl()).isEqualTo(expectedAuthorRepoGitUrl); } - - @Test - public void pullRequestIsMarkedAsChanged() throws Exception { - GhprbPullRequest pull = new GhprbPullRequest(pr, helper, repo, true); - pull.save(); - assertThat(pull.isChanged() == false); - - given(pr.getUpdatedAt()).willReturn(new DateTime().plusHours(2).toDate()); - pull.check(pr); - assertThat(pull.isChanged() == true); - - } - - @Test - public void pullRequestIsNotMarkedAsChanged() throws Exception { - GhprbPullRequest pull = new GhprbPullRequest(pr, helper, repo, true); - pull.save(); - assertThat(pull.isChanged() == false); - - pull.check(pr); - pull.check(pr); - pull.check(pr); - assertThat(pull.isChanged() == false); - - } } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index a62ad2e4f..70b43a67d 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -203,6 +203,7 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { verify(ghPullRequest, times(2)).getNumber(); verify(ghPullRequest, times(1)).getUpdatedAt(); verify(ghPullRequest, times(1)).getUser(); + verify(ghPullRequest, times(1)).getBase(); verifyNoMoreInteractions(ghPullRequest); verify(helper).ifOnlyTriggerPhrase(); @@ -262,7 +263,7 @@ public void testCheckMethodWithNewPR() throws IOException { verify(ghPullRequest, times(6)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API verify(ghPullRequest, times(7)).getHead(); - verify(ghPullRequest, times(1)).getBase(); + verify(ghPullRequest, times(4)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(2)).getUpdatedAt(); verify(ghPullRequest, times(1)).getCreatedAt(); @@ -345,7 +346,7 @@ public void testCheckMethodWhenPrWasUpdatedWithNonKeyPhrase() throws IOException verify(ghPullRequest, times(6)).getUser(); verify(ghPullRequest, times(1)).getMergeable(); // Call to Github API verify(ghPullRequest, times(9)).getHead(); - verify(ghPullRequest, times(1)).getBase(); + verify(ghPullRequest, times(6)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(1)).getHtmlUrl(); verify(ghPullRequest, times(2)).getUpdatedAt(); @@ -438,7 +439,7 @@ public void testCheckMethodWhenPrWasUpdatedWithRetestPhrase() throws IOException verify(ghPullRequest, times(7)).getUser(); verify(ghPullRequest, times(2)).getMergeable(); // Call to Github API verify(ghPullRequest, times(10)).getHead(); - verify(ghPullRequest, times(2)).getBase(); + verify(ghPullRequest, times(6)).getBase(); verify(ghPullRequest, times(5)).getNumber(); verify(ghPullRequest, times(2)).getUpdatedAt(); verify(ghPullRequest, times(1)).getCreatedAt(); From 41d3a9d6793644e8311114c9f2f9d8a38473c2ad Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 8 Feb 2016 16:53:38 -0700 Subject: [PATCH 150/175] Move security around calls to triggers --- .../jenkinsci/plugins/ghprb/GhprbRootAction.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index f313df21b..0a9c46e4e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -91,6 +91,10 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { } logger.log(Level.FINE, "Got payload event: {0}", event); + + // Not sure if this is needed, but it may be to get info about old builds. + Authentication old = SecurityContextHolder.getContext().getAuthentication(); + SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); try { GitHub gh = GitHub.connectAnonymously(); @@ -141,7 +145,10 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { } catch (IOException e) { logger.log(Level.SEVERE, "Unable to connect to GitHub anonymously", e); + } finally { + SecurityContextHolder.getContext().setAuthentication(old); } + } private PullRequest getPullRequest(String payload, GitHub gh) throws IOException { @@ -171,10 +178,6 @@ private String extractRequestBody(StaplerRequest req) { private Set getTriggers(String repoName, String body, String signature) { Set triggers = new HashSet(); - // We need this to get access to list of repositories - Authentication old = SecurityContextHolder.getContext().getAuthentication(); - SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); - Set> projects = GhprbTrigger.getDscp().getRepoTriggers(repoName); if (projects != null) { for (AbstractProject project : projects) { @@ -184,9 +187,6 @@ private Set getTriggers(String repoName, String body, String signa } } } - - SecurityContextHolder.getContext().setAuthentication(old); - return triggers; } From dc6fa507385b22120ef5222fc2c11fbe5cebbcf5 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 8 Feb 2016 21:30:36 -0700 Subject: [PATCH 151/175] Fix test to account for new call to getBase --- .../java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java index 0872401fe..ed52f8acf 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java @@ -107,6 +107,7 @@ public void testInitRepoNameNull() throws IOException { // THEN verify(pr, times(1)).getHead(); + verify(pr, times(1)).getBase(); verify(pr, times(1)).getNumber(); verify(pr, times(1)).getUpdatedAt(); verify(pr, times(3)).getUser(); From 836e5529191f7a3a6776eb2bfa80b2fc62a7afbe Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 8 Feb 2016 21:51:55 -0700 Subject: [PATCH 152/175] Remove lookup for previous build --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 1cdd3eb98..ee9113768 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -329,7 +329,7 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { // add the previous pr BuildData as an action so that the correct change log is generated by the GitSCM plugin // note that this will be removed from the Actions list after the job is completed so that the old (and incorrect) // one isn't there - return this.job.scheduleBuild2(job.getQuietPeriod(), cause, new ParametersAction(values), findPreviousBuildForPullId(pullIdPv)); + return this.job.scheduleBuild2(job.getQuietPeriod(), cause, new ParametersAction(values)); } private String escapeText(String text) { @@ -375,6 +375,7 @@ private String getString(String actual, String d) { /** * Find the previous BuildData for the given pull request number; this may return null + * Currently this doesn't appear to be working, and needs to be revised so it is faster */ private BuildData findPreviousBuildForPullId(StringParameterValue pullIdPv) { // Don't add the Action if it's a matrix job. From 1d6bbfa2a2e9b927d6581b408e398799c0dd778b Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 9 Feb 2016 14:09:22 -0700 Subject: [PATCH 153/175] Add build to the PR --- .../org/jenkinsci/plugins/ghprb/GhprbBuilds.java | 6 ++++-- .../jenkinsci/plugins/ghprb/GhprbPullRequest.java | 15 +++++++++------ .../plugins/ghprb/GhprbPullRequestMerge.java | 2 +- .../jenkinsci/plugins/ghprb/GhprbRepository.java | 8 ++++++-- .../org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 13 ++++++++++++- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index 2507f795a..d31817325 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -89,9 +89,11 @@ public void onStarted(AbstractBuild build, TaskListener listener) { } GhprbTrigger trigger = Ghprb.extractTrigger(build); + GhprbPullRequest pullRequest = trigger.getRepository().getPullRequest(c.getPullID()); + pullRequest.setBuild(build); try { - GHPullRequest pr = trigger.getRepository().getPullRequest(c.getPullID()); + GHPullRequest pr = pullRequest.getPullRequest(true); int counter = 0; // If the PR is being resolved by GitHub then getMergeable will return null Boolean isMergeable = pr.getMergeable(); @@ -200,7 +202,7 @@ public void onCompleted(AbstractBuild build, TaskListener listener) { private void closeFailedRequest(TaskListener listener, GhprbCause c) { try { - GHPullRequest pr = repo.getPullRequest(c.getPullID()); + GHPullRequest pr = repo.getActualPullRequest(c.getPullID()); if (pr.getState().equals(GHIssueState.OPEN)) { repo.closePullRequest(c.getPullID()); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 41731cc31..b940795df 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -2,6 +2,8 @@ import com.google.common.base.Joiner; +import hudson.model.AbstractBuild; + import org.apache.commons.lang.StringUtils; import org.kohsuke.github.GHCommitPointer; import org.kohsuke.github.GHIssue; @@ -35,6 +37,7 @@ public class GhprbPullRequest { @Deprecated @SuppressWarnings("unused") private transient String target; @Deprecated @SuppressWarnings("unused") private transient String source; @Deprecated @SuppressWarnings("unused") private transient String authorRepoGitUrl; + @Deprecated @SuppressWarnings("unused") private transient Boolean changed = true; private transient String authorEmail; @@ -56,7 +59,7 @@ public class GhprbPullRequest { private Date updated; // Needed to track when the PR was updated private String head; private boolean accepted = false; // Needed to see if the PR has been added to the accepted list - private Boolean changed = true; // Keep track for when the job config needs to be saved again. + private String lastBuildId; private void setUpdated(Date lastUpdateTime) { @@ -528,7 +531,7 @@ public GHUser getPullRequestAuthor() throws IOException { */ public GHPullRequest getPullRequest(boolean force) throws IOException { if (this.pr == null || force) { - this.pr = repo.getPullRequest(this.id); + this.pr = repo.getActualPullRequest(this.id); } return pr; } @@ -551,11 +554,11 @@ public String getAuthorEmail() { return authorEmail; } - public boolean isChanged() { - return changed == null ? false : changed; + public void setBuild(AbstractBuild build) { + lastBuildId = build.getId(); } - public void save() { - changed = false; + public String getLastBuildId() { + return lastBuildId; } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 55e031150..16f45cb0e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -105,7 +105,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build return true; } - pr = trigger.getRepository().getPullRequest(cause.getPullID()); + pr = trigger.getRepository().getActualPullRequest(cause.getPullID()); if (helper == null) { helper = new Ghprb(trigger); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index df711915e..120ff709e 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -145,7 +145,7 @@ public void check() { for (GHPullRequest pr : openPulls) { if (pr.getHead() == null) { // Not sure if we need this, but leaving it for now. try { - pr = getPullRequest(pr.getNumber()); + pr = getActualPullRequest(pr.getNumber()); } catch (IOException ex) { logger.log(Level.SEVERE, "Could not retrieve pr " + pr.getNumber(), ex); return; @@ -313,7 +313,11 @@ private String getHookUrl() { return baseUrl + GhprbRootAction.URL + "/"; } - public GHPullRequest getPullRequest(int id) throws IOException { + public GhprbPullRequest getPullRequest(int id) { + return pullRequests.get(id); + } + + public GHPullRequest getActualPullRequest(int id) throws IOException { return getGitHubRepo().getPullRequest(id); } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index ee9113768..9d21eb547 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -8,6 +8,7 @@ import hudson.Extension; import hudson.Util; import hudson.matrix.MatrixProject; +import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Item; import hudson.model.ParameterDefinition; @@ -286,6 +287,14 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { String triggerAuthor = ""; String triggerAuthorEmail = ""; String triggerAuthorLogin = ""; + + GhprbPullRequest pr = getRepository().getPullRequest(cause.getPullID()); + String lastBuildId = pr.getLastBuildId(); + BuildData buildData = null; + if (!(job instanceof MatrixProject) && !StringUtils.isEmpty(lastBuildId)) { + AbstractBuild lastBuild = job.getBuild(lastBuildId); + buildData = lastBuild.getAction(BuildData.class); + } try { triggerAuthor = getString(cause.getTriggerSender().getName(), ""); @@ -325,11 +334,13 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { values.add(new StringParameterValue("ghprbGhRepository", repo.getName())); values.add(new StringParameterValue("ghprbCredentialsId", getString(getGitHubApiAuth().getCredentialsId(), ""))); + + // add the previous pr BuildData as an action so that the correct change log is generated by the GitSCM plugin // note that this will be removed from the Actions list after the job is completed so that the old (and incorrect) // one isn't there - return this.job.scheduleBuild2(job.getQuietPeriod(), cause, new ParametersAction(values)); + return this.job.scheduleBuild2(job.getQuietPeriod(), cause, new ParametersAction(values), buildData); } private String escapeText(String text) { From e8ce66686af61f2972e4a73907d2fadbbe570e55 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 9 Feb 2016 14:59:25 -0700 Subject: [PATCH 154/175] Fix tests --- .../plugins/ghprb/GhprbITBaseTestCase.java | 3 +++ .../ghprb/GhprbPullRequestMergeTest.java | 3 ++- .../plugins/ghprb/GhprbPullRequestTest.java | 27 +------------------ 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java index 4f6eb1317..30c85304a 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbITBaseTestCase.java @@ -43,6 +43,8 @@ public abstract class GhprbITBaseTestCase { protected GHUser ghUser; @Mock protected Ghprb helper; + @Mock + protected GhprbPullRequest ghprbPullRequest; protected GhprbBuilds builds; @@ -86,6 +88,7 @@ protected void beforeTest(Map globalConfig, Map GhprbRepository repo = Mockito.spy(new GhprbRepository("user/dropwizard", trigger)); Mockito.doReturn(ghRepository).when(repo).getGitHubRepo(); Mockito.doNothing().when(repo).addComment(Mockito.anyInt(), Mockito.anyString(), any(AbstractBuild.class), any(TaskListener.class)); + Mockito.doReturn(ghprbPullRequest).when(repo).getPullRequest(Mockito.anyInt()); Mockito.doReturn(repo).when(trigger).getRepository(); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 2684d1065..c9d17ac3f 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -121,7 +121,8 @@ public void beforeTest() throws Exception { Mockito.doReturn(project).when(trigger).getActualProject(); Mockito.doReturn(repo).when(trigger).getRepository(); repo.addPullRequests(pulls); - Mockito.doReturn(pr).when(repo).getPullRequest(pullId); + Mockito.doReturn(pullRequest).when(repo).getPullRequest(pullId); + Mockito.doReturn(pr).when(repo).getActualPullRequest(pullId); GithubProjectProperty projectProperty = new GithubProjectProperty("https://github.com/jenkinsci/ghprb-plugin"); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java index 31127bb19..783e03bfe 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java @@ -62,7 +62,7 @@ public void setup() throws IOException { given(ghUser.getEmail()).willReturn("email"); - given(ghprbRepository.getPullRequest(10)).willReturn(pr); + given(ghprbRepository.getActualPullRequest(10)).willReturn(pr); given(ghprbRepository.getName()).willReturn("name"); given(pr.getHead()).willReturn(head); @@ -159,29 +159,4 @@ public void authorRepoGitUrlShouldBeSetWhenRepository() throws Exception { // THEN assertThat(ghprbPullRequest.getAuthorRepoGitUrl()).isEqualTo(expectedAuthorRepoGitUrl); } - - @Test - public void pullRequestIsMarkedAsChanged() throws Exception { - GhprbPullRequest pull = new GhprbPullRequest(pr, helper, repo, true); - pull.save(); - assertThat(pull.isChanged() == false); - - given(pr.getUpdatedAt()).willReturn(new DateTime().plusHours(2).toDate()); - pull.check(pr); - assertThat(pull.isChanged() == true); - - } - - @Test - public void pullRequestIsNotMarkedAsChanged() throws Exception { - GhprbPullRequest pull = new GhprbPullRequest(pr, helper, repo, true); - pull.save(); - assertThat(pull.isChanged() == false); - - pull.check(pr); - pull.check(pr); - pull.check(pr); - assertThat(pull.isChanged() == false); - - } } From 8d49751b0a0c6841f7bcdba321c03021be2ba3ff Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 10 Feb 2016 09:23:17 -0700 Subject: [PATCH 155/175] Update readme for next release --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 54f6c604b..718d8beb0 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,10 @@ job('downstreamJob') { ### Updates +#### -> 1.30.2 +* Don't run through all the builds for changelog, track it in the PR object instead +* Synchronization around the PR object fields + #### -> 1.30.1 * Moved pull request state into build/pullrequests directory. * Dynamic state is no longer kept as part of the trigger From ec1790edf4056b5c8875e00ed46022b71eff8c16 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 11 Feb 2016 09:45:05 -0700 Subject: [PATCH 156/175] Add synchronization --- .../plugins/ghprb/GhprbPullRequest.java | 316 ++++++++++-------- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 2 +- .../plugins/ghprb/GhprbPullRequestTest.java | 2 +- .../plugins/ghprb/GhprbRepositoryTest.java | 1 + 4 files changed, 186 insertions(+), 135 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index b6efa74de..ea0613c01 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -21,40 +21,58 @@ import java.util.logging.Logger; /** - * Maintains state about a Pull Request for a particular Jenkins job. This is what understands the current state of a PR for a particular job. + * Maintains state about a Pull Request for a particular Jenkins job. This is what understands the current state of a PR + * for a particular job. * * @author Honza Brázdil */ public class GhprbPullRequest { private static final Logger logger = Logger.getLogger(GhprbPullRequest.class.getName()); - - @Deprecated @SuppressWarnings("unused") private transient GHUser author; - @Deprecated @SuppressWarnings("unused") private transient String title; - @Deprecated @SuppressWarnings("unused") private transient String reponame; - @Deprecated @SuppressWarnings("unused") private transient URL url; - @Deprecated @SuppressWarnings("unused") private transient String description; - @Deprecated @SuppressWarnings("unused") private transient String target; - @Deprecated @SuppressWarnings("unused") private transient String source; - @Deprecated @SuppressWarnings("unused") private transient String authorRepoGitUrl; - @Deprecated @SuppressWarnings("unused") private transient Boolean changed = true; + @Deprecated + @SuppressWarnings("unused") + private transient GHUser author; + @Deprecated + @SuppressWarnings("unused") + private transient String title; + @Deprecated + @SuppressWarnings("unused") + private transient String reponame; + @Deprecated + @SuppressWarnings("unused") + private transient URL url; + @Deprecated + @SuppressWarnings("unused") + private transient String description; + @Deprecated + @SuppressWarnings("unused") + private transient String target; + @Deprecated + @SuppressWarnings("unused") + private transient String source; + @Deprecated + @SuppressWarnings("unused") + private transient String authorRepoGitUrl; + @Deprecated + @SuppressWarnings("unused") + private transient Boolean changed = true; private transient String authorEmail; private transient Ghprb helper; // will be refreshed each time GhprbRepository.init() is called private transient GhprbRepository repo; // will be refreshed each time GhprbRepository.init() is called - + private transient GHPullRequest pr; private transient GHUser triggerSender; // Only needed for a single build private transient GitUser commitAuthor; // Only needed for a single build private transient String commentBody; - + private transient boolean shouldRun = false; // Declares if we should run the build this time. private transient boolean triggered = false; // Only lets us know if the trigger phrase was used for this run - private transient boolean mergeable = false; // Only works as an easy way to pass the value around for the start of this build + private transient boolean mergeable = false; // Only works as an easy way to pass the value around for the start of + // this build - private final int id; private Date updated; // Needed to track when the PR was updated private String head; @@ -62,88 +80,75 @@ public class GhprbPullRequest { private boolean accepted = false; // Needed to see if the PR has been added to the accepted list private String lastBuildId; - private void setUpdated(Date lastUpdateTime) { updated = lastUpdateTime; } - + private void setHead(String newHead) { this.head = StringUtils.isEmpty(newHead) ? head : newHead; } - + private void setBase(String newBase) { this.base = StringUtils.isEmpty(newBase) ? base : newBase; } - + private void setAccepted(boolean shouldRun) { accepted = true; this.shouldRun = shouldRun; } - - public GhprbPullRequest(GHPullRequest pr, Ghprb ghprb, GhprbRepository repo, boolean isNew) { + + public GhprbPullRequest(GHPullRequest pr, + Ghprb ghprb, + GhprbRepository repo, + boolean isNew) { + id = pr.getNumber(); - this.pr = pr; - + setPullRequest(pr); + this.helper = ghprb; - + this.repo = repo; - - try { - if (isNew) { - setUpdated(pr.getCreatedAt()); - } else { - setUpdated(pr.getUpdatedAt()); - } - } catch (IOException e) { - logger.log(Level.WARNING, "Unable to get date for new PR", e); - setUpdated(new Date()); - } - - GHCommitPointer prHead = pr.getHead(); - setHead(prHead.getSha()); - - GHCommitPointer prBase = pr.getBase(); - setBase(prBase.getSha()); - + GHUser author = pr.getUser(); String reponame = repo.getName(); - try { if (ghprb.isWhitelisted(getPullRequestAuthor())) { setAccepted(true); } else { - logger.log(Level.INFO, "Author of #{0} {1} on {2} not in whitelist!", new Object[] { id, author.getLogin(), reponame }); + logger.log(Level.INFO, + "Author of #{0} {1} on {2} not in whitelist!", + new Object[] { id, author.getLogin(), reponame }); repo.addComment(id, GhprbTrigger.getDscp().getRequestForTestingPhrase()); } } catch (IOException e) { logger.log(Level.SEVERE, "Unable to get pull request author", e); } - logger.log(Level.INFO, "Created Pull Request #{0} on {1} by {2} ({3}) updated at: {4} SHA: {5}", - new Object[] { id, reponame, author.getLogin(), getAuthorEmail(), updated, prHead.getRef() } - ); + logger.log(Level.INFO, + "Created Pull Request #{0} on {1} by {2} ({3}) updated at: {4} SHA: {5}", + new Object[] { id, reponame, author.getLogin(), getAuthorEmail(), updated, this.head }); } - public void init(Ghprb helper, GhprbRepository repo) { + public void init(Ghprb helper, + GhprbRepository repo) { this.helper = helper; this.repo = repo; } /** - * Checks this Pull Request representation against a GitHub version of the Pull Request, and triggers a build if necessary. + * Checks this Pull Request representation against a GitHub version of the Pull Request, and triggers a build if + * necessary. * * @param ghpr */ public void check(GHPullRequest ghpr) { - if (ghpr != null) { - this.pr = ghpr; - } + setPullRequest(ghpr); if (helper.isProjectDisabled()) { logger.log(Level.FINE, "Project is disabled, ignoring pull request"); return; } - + try { getPullRequest(false); } catch (IOException e) { @@ -156,11 +161,13 @@ public void check(GHPullRequest ghpr) { checkSkipBuild(pr); tryBuild(); } - + private void checkSkipBuild(GHIssue issue) { String skipBuildPhrase = helper.checkSkipBuild(issue); if (!StringUtils.isEmpty(skipBuildPhrase)) { - logger.log(Level.INFO, "Pull request commented with {0} skipBuildPhrase. Hence skipping the build.", skipBuildPhrase); + logger.log(Level.INFO, + "Pull request commented with {0} skipBuildPhrase. Hence skipping the build.", + skipBuildPhrase); shouldRun = false; } } @@ -170,52 +177,58 @@ public void check(GHIssueComment comment) { logger.log(Level.FINE, "Project is disabled, ignoring comment"); return; } - - try { - checkComment(comment); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Couldn't check comment #" + comment.getId(), ex); - return; - } - try { - GHUser user = null; + synchronized (this) { try { - user = comment.getUser(); - } catch (IOException e) { - logger.log(Level.SEVERE, "Couldn't get the user that made the comment", e); + checkComment(comment); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Couldn't check comment #" + comment.getId(), ex); + return; } - updatePR(getPullRequest(true), user); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Unable to get a new copy of the pull request!"); + + try { + GHUser user = null; + try { + user = comment.getUser(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Couldn't get the user that made the comment", e); + } + updatePR(getPullRequest(true), user); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Unable to get a new copy of the pull request!"); + } + + checkSkipBuild(comment.getParent()); + tryBuild(); } - - checkSkipBuild(comment.getParent()); - tryBuild(); } - - - private void updatePR(GHPullRequest pr, GHUser user) { - this.pr = pr; - - Date lastUpdateTime = updated; - if (isUpdated(pr)) { - logger.log(Level.INFO, "Pull request #{0} was updated on {1} at {2} by {3}", new Object[] { id, repo.getName(), updated, user }); - - // the author of the PR could have been whitelisted since its creation - if (!accepted && helper.isWhitelisted(pr.getUser())) { - logger.log(Level.INFO, "Pull request #{0}'s author has been whitelisted", new Object[]{id}); - setAccepted(false); - } - - int commentsChecked = checkComments(pr, lastUpdateTime); - boolean newCommit = checkCommit(pr); - - if (!newCommit && commentsChecked == 0) { - logger.log(Level.INFO, "Pull request #{0} was updated on repo {1} but there aren''t any new comments nor commits; " - + "that may mean that commit status was updated.", - new Object[] { id, repo.getName() } - ); + + private void updatePR(GHPullRequest pr, + GHUser user) { + setPullRequest(pr); + + synchronized (this) { + Date lastUpdateTime = updated; + if (isUpdated(pr)) { + logger.log(Level.INFO, + "Pull request #{0} was updated on {1} at {2} by {3}", + new Object[] { id, repo.getName(), updated, user }); + + // the author of the PR could have been whitelisted since its creation + if (!accepted && helper.isWhitelisted(pr.getUser())) { + logger.log(Level.INFO, "Pull request #{0}'s author has been whitelisted", new Object[] { id }); + setAccepted(false); + } + + int commentsChecked = checkComments(pr, lastUpdateTime); + boolean newCommit = checkCommit(pr); + + if (!newCommit && commentsChecked == 0) { + logger.log(Level.INFO, + "Pull request #{0} was updated on repo {1} but there aren''t any new comments nor commits; " + + "that may mean that commit status was updated.", + new Object[] { id, repo.getName() }); + } } } } @@ -226,7 +239,7 @@ public boolean isWhiteListedTargetBranch() { // no branches in white list means we should test all return true; } - + String target = getTarget(); for (GhprbBranch b : branches) { if (b.matches(target)) { @@ -234,31 +247,33 @@ public boolean isWhiteListedTargetBranch() { return true; } } - logger.log(Level.FINEST, "PR #{0} target branch: {1} isn''t in our whitelist of target branches: {2}", - new Object[] { id, target, Joiner.on(',').skipNulls().join(branches) } - ); + logger.log(Level.FINEST, + "PR #{0} target branch: {1} isn''t in our whitelist of target branches: {2}", + new Object[] { id, target, Joiner.on(',').skipNulls().join(branches) }); return false; } private boolean isUpdated(GHPullRequest pr) { - Date lastUpdated = new Date(); - boolean ret = false; - try { - lastUpdated = pr.getUpdatedAt(); - ret = updated.compareTo(lastUpdated) < 0; - setUpdated(lastUpdated); - } catch (Exception e) { - logger.log(Level.WARNING, "Unable to update last updated date", e); + synchronized (this) { + Date lastUpdated = new Date(); + boolean ret = false; + try { + lastUpdated = pr.getUpdatedAt(); + ret = updated.compareTo(lastUpdated) < 0; + setUpdated(lastUpdated); + } catch (Exception e) { + logger.log(Level.WARNING, "Unable to update last updated date", e); + } + GHCommitPointer pointer = pr.getHead(); + String pointerSha = pointer.getSha(); + ret |= !pointerSha.equals(head); + + pointer = pr.getBase(); + pointerSha = pointer.getSha(); + ret |= !pointerSha.equals(base); + + return ret; } - GHCommitPointer pointer = pr.getHead(); - String pointerSha = pointer.getSha(); - ret |= !pointerSha.equals(head); - - pointer = pr.getBase(); - pointerSha = pointer.getSha(); - ret |= !pointerSha.equals(base); - - return ret; } private void tryBuild() { @@ -272,7 +287,7 @@ private void tryBuild() { shouldRun = false; } triggered = false; // Once we have decided that we are triggered then the flag should be set to false. - + if (!isWhiteListedTargetBranch()) { logger.log(Level.FINEST, "Branch is not whitelisted, skipping the build"); return; @@ -311,19 +326,21 @@ private void build() { private boolean checkCommit(GHPullRequest pr) { GHCommitPointer head = pr.getHead(); GHCommitPointer base = pr.getBase(); - + String headSha = head.getSha(); String baseSha = base.getSha(); - + if (StringUtils.equals(headSha, this.head) && StringUtils.equals(baseSha, this.base)) { return false; } - - logger.log(Level.FINE, "New commit. Sha: Head[{0} => {1}] Base[{2} => {3}]", new Object[] { this.head, headSha, this.base, baseSha }); - + + logger.log(Level.FINE, + "New commit. Sha: Head[{0} => {1}] Base[{2} => {3}]", + new Object[] { this.head, headSha, this.base, baseSha }); + setHead(headSha); setBase(baseSha); - + if (accepted) { shouldRun = true; } @@ -333,8 +350,8 @@ private boolean checkCommit(GHPullRequest pr) { private void checkComment(GHIssueComment comment) throws IOException { GHUser sender = comment.getUser(); String body = comment.getBody(); - - logger.log(Level.FINEST, "[{0}] Added comment: {1}", new Object[]{sender.getName(), body}); + + logger.log(Level.FINEST, "[{0}] Added comment: {1}", new Object[] { sender.getName(), body }); // Disabled until more advanced configs get set up // ignore comments from bot user, this fixes an issue where the bot would auto-whitelist @@ -384,7 +401,8 @@ private void checkComment(GHIssueComment comment) throws IOException { } } - private int checkComments(GHPullRequest ghpr, Date lastUpdatedTime) { + private int checkComments(GHPullRequest ghpr, + Date lastUpdatedTime) { int count = 0; logger.log(Level.FINEST, "Checking for comments after: {0}", lastUpdatedTime); try { @@ -471,6 +489,7 @@ public boolean isMergeable() { /** * Base and Ref are part of the PullRequest object + * * @return */ public String getTarget() { @@ -483,6 +502,7 @@ public String getTarget() { /** * Head and Ref are part of the PullRequest object + * * @return */ public String getSource() { @@ -493,9 +513,9 @@ public String getSource() { } } - /** * Title is part of the PullRequest object + * * @return */ public String getTitle() { @@ -515,10 +535,10 @@ public String getTitle() { public URL getUrl() throws IOException { return getPullRequest(false).getHtmlUrl(); } - /** * The description body is part of the PullRequest object + * * @return */ public String getDescription() { @@ -535,29 +555,59 @@ public GitUser getCommitAuthor() { /** * Author is part of the PullRequest Object + * * @return * @throws IOException */ public GHUser getPullRequestAuthor() throws IOException { return getPullRequest(false).getUser(); } - + /** * Get the PullRequest object for this PR + * * @param force - forces the code to go get the PullRequest from GitHub now * @return * @throws IOException */ public GHPullRequest getPullRequest(boolean force) throws IOException { if (this.pr == null || force) { - this.pr = repo.getActualPullRequest(this.id); + setPullRequest(repo.getActualPullRequest(this.id)); } return pr; } - + + private void setPullRequest(GHPullRequest pr) { + if (pr == null) { + return; + } + synchronized (this) { + this.pr = pr; + + try { + if (updated == null) { + setUpdated(pr.getCreatedAt()); + } + } catch (IOException e) { + logger.log(Level.WARNING, "Unable to get date for new PR", e); + setUpdated(new Date()); + } + + if (StringUtils.isEmpty(this.head)) { + GHCommitPointer prHead = pr.getHead(); + setHead(prHead.getSha()); + } + + if (StringUtils.isEmpty(this.base)) { + GHCommitPointer prBase = pr.getBase(); + setBase(prBase.getSha()); + } + } + } /** * Email address is collected from GitHub as extra information, so lets cache it. + * * @return */ public String getAuthorEmail() { @@ -576,7 +626,7 @@ public String getAuthorEmail() { public void setBuild(AbstractBuild build) { lastBuildId = build.getId(); } - + public String getLastBuildId() { return lastBuildId; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 9d21eb547..b2c40dd72 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -158,6 +158,7 @@ public Object readResolve() { } + @SuppressWarnings("deprecation") private void checkGitHubApiAuth() { if (gitHubApiAuth != null) { @@ -983,5 +984,4 @@ private void addIfMissing(GhprbExtension ext) { } - } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java index 5ee96679d..e34a4c18d 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestTest.java @@ -109,7 +109,7 @@ public void testInitRepoNameNull() throws IOException { verify(pr, times(1)).getHead(); verify(pr, times(1)).getBase(); verify(pr, times(1)).getNumber(); - verify(pr, times(1)).getUpdatedAt(); + verify(pr, times(1)).getCreatedAt(); verify(pr, times(3)).getUser(); Mockito.verifyNoMoreInteractions(pr); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 70b43a67d..66a61f695 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -202,6 +202,7 @@ public void testCheckMethodWithOnlyExistingPRs() throws IOException { verify(ghPullRequest, times(2)).getHead(); verify(ghPullRequest, times(2)).getNumber(); verify(ghPullRequest, times(1)).getUpdatedAt(); + verify(ghPullRequest, times(1)).getCreatedAt(); verify(ghPullRequest, times(1)).getUser(); verify(ghPullRequest, times(1)).getBase(); verifyNoMoreInteractions(ghPullRequest); From 0df575926231e93cb0966ae1b6ba36e2aea31007 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 11 Feb 2016 15:16:58 -0700 Subject: [PATCH 157/175] Add sync and move the skipBuild check into tryBuild --- .../plugins/ghprb/GhprbPullRequest.java | 81 ++++++++++--------- .../plugins/ghprb/GhprbTriggerTest.java | 12 ++- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index ea0613c01..1672de3fe 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -158,17 +158,18 @@ public void check(GHPullRequest ghpr) { updatePR(pr, pr.getUser()); - checkSkipBuild(pr); tryBuild(); } - private void checkSkipBuild(GHIssue issue) { - String skipBuildPhrase = helper.checkSkipBuild(issue); - if (!StringUtils.isEmpty(skipBuildPhrase)) { - logger.log(Level.INFO, - "Pull request commented with {0} skipBuildPhrase. Hence skipping the build.", - skipBuildPhrase); - shouldRun = false; + private void checkSkipBuild() { + synchronized (this) { + String skipBuildPhrase = helper.checkSkipBuild(this.pr); + if (!StringUtils.isEmpty(skipBuildPhrase)) { + logger.log(Level.INFO, + "Pull request commented with {0} skipBuildPhrase. Hence skipping the build.", + skipBuildPhrase); + shouldRun = false; + } } } @@ -198,7 +199,6 @@ public void check(GHIssueComment comment) { logger.log(Level.SEVERE, "Unable to get a new copy of the pull request!"); } - checkSkipBuild(comment.getParent()); tryBuild(); } } @@ -277,43 +277,46 @@ private boolean isUpdated(GHPullRequest pr) { } private void tryBuild() { - if (helper.isProjectDisabled()) { - logger.log(Level.FINEST, "Project is disabled, not trying to build"); - shouldRun = false; - triggered = false; - } - if (helper.ifOnlyTriggerPhrase() && !triggered) { - logger.log(Level.FINEST, "Trigger only phrase but we are not triggered"); - shouldRun = false; - } - triggered = false; // Once we have decided that we are triggered then the flag should be set to false. + synchronized (this) { + checkSkipBuild(); + if (helper.isProjectDisabled()) { + logger.log(Level.FINEST, "Project is disabled, not trying to build"); + shouldRun = false; + triggered = false; + } + if (helper.ifOnlyTriggerPhrase() && !triggered) { + logger.log(Level.FINEST, "Trigger only phrase but we are not triggered"); + shouldRun = false; + } + triggered = false; // Once we have decided that we are triggered then the flag should be set to false. - if (!isWhiteListedTargetBranch()) { - logger.log(Level.FINEST, "Branch is not whitelisted, skipping the build"); - return; - } - if (shouldRun) { - shouldRun = false; // Change the shouldRun flag as soon as we decide to build. - logger.log(Level.FINEST, "Running the build"); + if (!isWhiteListedTargetBranch()) { + logger.log(Level.FINEST, "Branch is not whitelisted, skipping the build"); + return; + } + if (shouldRun) { + shouldRun = false; // Change the shouldRun flag as soon as we decide to build. + logger.log(Level.FINEST, "Running the build"); - if (pr != null) { - logger.log(Level.FINEST, "PR is not null, checking if mergable"); - checkMergeable(); - try { - for (GHPullRequestCommitDetail commitDetails : pr.listCommits()) { - if (commitDetails.getSha().equals(getHead())) { - commitAuthor = commitDetails.getCommit().getCommitter(); - break; + if (pr != null) { + logger.log(Level.FINEST, "PR is not null, checking if mergable"); + checkMergeable(); + try { + for (GHPullRequestCommitDetail commitDetails : pr.listCommits()) { + if (commitDetails.getSha().equals(getHead())) { + commitAuthor = commitDetails.getCommit().getCommitter(); + break; + } } + } catch (Exception ex) { + logger.log(Level.INFO, "Unable to get PR commits: ", ex); } - } catch (Exception ex) { - logger.log(Level.INFO, "Unable to get PR commits: ", ex); + } + logger.log(Level.FINEST, "Running build..."); + build(); } - - logger.log(Level.FINEST, "Running build..."); - build(); } } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java index b4817eedb..55cfcc7ef 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java @@ -17,6 +17,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.kohsuke.github.GHIssue; +import org.kohsuke.github.GHPullRequest; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -34,7 +35,7 @@ public class GhprbTriggerTest { @Test public void testCheckSkipBuild() throws Exception { - GHIssue issue = mock(GHIssue.class); + GHPullRequest issue = mock(GHPullRequest.class); boolean skipBuild = false; boolean build = true; @@ -67,8 +68,13 @@ public void testCheckSkipBuild() throws Exception { comment.put(fullSkipCi, skipBuild); stringsToTest.put("\\[skip ci\\]\n.*\\[skip\\W+ci\\].*\nskip ci", comment); - Method checkSkip = GhprbPullRequest.class.getDeclaredMethod("checkSkipBuild", GHIssue.class); + Method checkSkip = GhprbPullRequest.class.getDeclaredMethod("checkSkipBuild"); checkSkip.setAccessible(true); + + + Field prField = GhprbPullRequest.class.getDeclaredField("pr"); + prField.setAccessible(true); + prField.set(pr, issue); Field shouldRun = GhprbPullRequest.class.getDeclaredField("shouldRun"); shouldRun.setAccessible(true); @@ -104,7 +110,7 @@ public void testCheckSkipBuild() throws Exception { given(helper.checkSkipBuild(issue)).willReturn(skipPhrase); shouldRun.set(pr, true); - checkSkip.invoke(pr, issue); + checkSkip.invoke(pr); String errorMessage = String.format("Comment does %scontain skip phrase \n(\n%s\n)\n[\n%s\n]", shouldBuild ? "not ": "", nextComment, skipPhrases); if (shouldBuild) { From 728e6c2b9bd5740d1d6a2e38f262e2ef437a9260 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 12 Feb 2016 09:51:05 -0700 Subject: [PATCH 158/175] [maven-release-plugin] prepare release ghprb-1.30.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 182f59564..d085e49b2 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.31-SNAPSHOT + 1.30.2 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.30.2 From 18fe1f89fdd1499980f18d2afb83fff270c53fda Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 12 Feb 2016 09:51:08 -0700 Subject: [PATCH 159/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d085e49b2..dc4c308f6 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30.2 + 1.30.3-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.30.2 + HEAD From 31ea36ea314f94d9eaf22fd25a1e51abfb8510ca Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 13 Feb 2016 10:23:33 -0700 Subject: [PATCH 160/175] All getters should use get, and not is --- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 2 +- .../plugins/ghprb/GhprbPullRequestMerge.java | 24 +++---- .../plugins/ghprb/GhprbRepository.java | 2 +- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 13 +++- .../GhprbTriggerBackwardsCompatible.java | 1 - .../comments/GhprbPublishJenkinsUrl.java | 2 +- .../extensions/status/GhprbSimpleStatus.java | 2 +- .../jenkinsci/plugins/ghprb/GeneralTest.java | 66 +++++++++++++++++++ .../plugins/ghprb/GhprbTestUtil.java | 42 ++++++++++++ .../plugins/ghprb/GhprbTriggerTest.java | 3 +- 10 files changed, 136 insertions(+), 21 deletions(-) create mode 100644 src/test/java/org/jenkinsci/plugins/ghprb/GeneralTest.java diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index d31817325..41b9d214d 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -195,7 +195,7 @@ public void onCompleted(AbstractBuild build, TaskListener listener) { commentOnBuildResult(build, listener, state, c); // close failed pull request automatically - if (state == GHCommitState.FAILURE && trigger.isAutoCloseFailedPullRequests()) { + if (state == GHCommitState.FAILURE && trigger.getAutoCloseFailedPullRequests()) { closeFailedRequest(listener, c); } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java index 16f45cb0e..2f920afc3 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMerge.java @@ -57,19 +57,19 @@ public String getMergeComment() { return mergeComment; } - public boolean isOnlyAdminsMerge() { + public boolean getOnlyAdminsMerge() { return onlyAdminsMerge == null ? false : onlyAdminsMerge; } - public boolean isDisallowOwnCode() { + public boolean getDisallowOwnCode() { return disallowOwnCode == null ? false : disallowOwnCode; } - public boolean isFailOnNonMerge() { + public boolean getFailOnNonMerge() { return failOnNonMerge == null ? false : failOnNonMerge; } - public boolean isDeleteOnMerge() { + public boolean getDeleteOnMerge() { return deleteOnMerge == null ? false : deleteOnMerge; } @@ -77,10 +77,10 @@ public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.BUILD; } - private GhprbTrigger trigger; - private Ghprb helper; - private GhprbCause cause; - private GHPullRequest pr; + private transient GhprbTrigger trigger; + private transient Ghprb helper; + private transient GhprbCause cause; + private transient GHPullRequest pr; @VisibleForTesting void setHelper(Ghprb helper) { @@ -134,7 +134,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build } // If there is no intention to merge there is no point checking - if (intendToMerge && isOnlyAdminsMerge() && (triggerSender == null || !helper.isAdmin(triggerSender))) { + if (intendToMerge && getOnlyAdminsMerge() && (triggerSender == null || !helper.isAdmin(triggerSender))) { canMerge = false; logger.println("Only admins can merge this pull request, " + (triggerSender != null ? triggerSender.getLogin() + " is not an admin" : " and build was triggered via automation") + "."); if (triggerSender != null) { @@ -143,7 +143,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build } // If there is no intention to merge there is no point checking - if (intendToMerge && isDisallowOwnCode() && (triggerSender == null || isOwnCode(pr, triggerSender))) { + if (intendToMerge && getDisallowOwnCode() && (triggerSender == null || isOwnCode(pr, triggerSender))) { canMerge = false; if (triggerSender != null) { logger.println("The commentor is also one of the contributors."); @@ -181,7 +181,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build } // We should only fail the build if there is an intent to merge - if (intendToMerge && !canMerge && isFailOnNonMerge()) { + if (intendToMerge && !canMerge && getFailOnNonMerge()) { listener.finished(Result.FAILURE); } else { listener.finished(Result.SUCCESS); @@ -190,7 +190,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, final Build } private void deleteBranch(AbstractBuild build, Launcher launcher, final BuildListener listener) { - if (!isDeleteOnMerge()) { + if (!getDeleteOnMerge()) { return; } String branchName = pr.getHead().getRef(); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 120ff709e..e83072247 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -51,10 +51,10 @@ public class GhprbRepository implements Saveable{ private static final transient EnumSet HOOK_EVENTS = EnumSet.of(GHEvent.ISSUE_COMMENT, GHEvent.PULL_REQUEST); private final String reponame; + private final Map pullRequests; private transient GHRepository ghRepository; private transient GhprbTrigger trigger; - private final Map pullRequests; public GhprbRepository(String reponame, GhprbTrigger trigger) { this.pullRequests = new ConcurrentHashMap(); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index b2c40dd72..ccc5849c8 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -80,6 +80,7 @@ public class GhprbTrigger extends GhprbTriggerBackwardsCompatible { private Boolean displayBuildErrorsOnDownstreamBuilds; private List whiteListTargetBranches; private String gitHubAuthId; + private String triggerPhrase; private transient Ghprb helper; @@ -348,6 +349,10 @@ private String escapeText(String text) { return text.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\\\""); } + public String getGitHubAuthId() { + return gitHubAuthId == null ? "" : gitHubAuthId; + } + public GhprbGitHubAuth getGitHubApiAuth() { if (gitHubAuthId == null) { for (GhprbGitHubAuth auth: getDescriptor().getGithubAuth()){ @@ -488,7 +493,7 @@ public Boolean getPermitAll() { return permitAll != null && permitAll; } - public Boolean isAutoCloseFailedPullRequests() { + public Boolean getAutoCloseFailedPullRequests() { if (autoCloseFailedPullRequests == null) { Boolean autoClose = getDescriptor().getAutoCloseFailedPullRequests(); return (autoClose != null && autoClose); @@ -496,7 +501,7 @@ public Boolean isAutoCloseFailedPullRequests() { return autoCloseFailedPullRequests; } - public Boolean isDisplayBuildErrorsOnDownstreamBuilds() { + public Boolean getDisplayBuildErrorsOnDownstreamBuilds() { if (displayBuildErrorsOnDownstreamBuilds == null) { Boolean displayErrors = getDescriptor().getDisplayBuildErrorsOnDownstreamBuilds(); return (displayErrors != null && displayErrors); @@ -807,6 +812,10 @@ public Boolean getDisplayBuildErrorsOnDownstreamBuilds() { public GHCommitState getUnstableAs() { return unstableAs; } + + public Integer getConfigVersion() { + return configVersion; + } public boolean isUseComments() { return (useComments != null && useComments); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java index a67506220..db4a51705 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java @@ -26,7 +26,6 @@ public abstract class GhprbTriggerBackwardsCompatible extends Trigger build) { return ""; } JobConfiguration jobConfiguration = JobConfiguration.builder() - .printStackTrace(trigger.isDisplayBuildErrorsOnDownstreamBuilds()).build(); + .printStackTrace(trigger.getDisplayBuildErrorsOnDownstreamBuilds()).build(); GhprbBuildManager buildManager = GhprbBuildManagerFactoryUtil.getBuildManager(build, jobConfiguration); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index befefb18d..70519dfda 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -172,7 +172,7 @@ public void onBuildComplete(AbstractBuild build, TaskListener listener, GH if (trigger == null) { listener.getLogger().println("Unable to get pull request builder trigger!!"); } else { - JobConfiguration jobConfiguration = JobConfiguration.builder().printStackTrace(trigger.isDisplayBuildErrorsOnDownstreamBuilds()).build(); + JobConfiguration jobConfiguration = JobConfiguration.builder().printStackTrace(trigger.getDisplayBuildErrorsOnDownstreamBuilds()).build(); GhprbBuildManager buildManager = GhprbBuildManagerFactoryUtil.getBuildManager(build, jobConfiguration); sb.append(buildManager.getOneLineTestResults()); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GeneralTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GeneralTest.java new file mode 100644 index 000000000..e5b72caed --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GeneralTest.java @@ -0,0 +1,66 @@ +package org.jenkinsci.plugins.ghprb; + +import static org.fest.assertions.Assertions.assertThat; + +import java.util.List; + +import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildLog; +import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; +import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildStatus; +import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbCommentFile; +import org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class GeneralTest { + + private void checkClassForGetters(Class clazz) { + List errors = GhprbTestUtil.checkClassForGetters(clazz); + assertThat(errors).isEmpty(); + } + + @Test + public void checkTriggerForGetters() { + checkClassForGetters(GhprbTrigger.class); + } + + @Test + public void checkTriggerDescriptorForGetters() { + checkClassForGetters(GhprbTrigger.DescriptorImpl.class); + } + + @Test + public void checkPullRequestMergeForGetters() { + checkClassForGetters(GhprbPullRequestMerge.class); + } + + @Test + public void checkBuildLogForGetters() { + checkClassForGetters(GhprbBuildLog.class); + } + + + @Test + public void checkBuildResultMessageForGetters() { + checkClassForGetters(GhprbBuildResultMessage.class); + } + + @Test + public void checkBuildStatusForGetters() { + checkClassForGetters(GhprbBuildStatus.class); + } + + @Test + public void checkCommentFileForGetters() { + checkClassForGetters(GhprbCommentFile.class); + } + + + @Test + public void checkSimpleStatusForGetters() { + checkClassForGetters(GhprbSimpleStatus.class); + } + +} diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java index caafef707..e7410d653 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java @@ -15,16 +15,24 @@ package org.jenkinsci.plugins.ghprb; import static com.google.common.collect.Lists.newArrayList; +import static org.fest.assertions.Assertions.assertThat; import static org.mockito.BDDMockito.given; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.codehaus.plexus.util.StringUtils; import org.joda.time.DateTime; +import org.junit.Test; import org.kohsuke.github.GHCommitPointer; import org.kohsuke.github.GHPullRequest; import org.kohsuke.github.GHRateLimit; @@ -406,6 +414,40 @@ public static void triggerRunAndWait(int numOfTriggers, GhprbTrigger trigger, Ab } } + + + public static List checkClassForGetters(Class clazz) { + Field[] fields = clazz.getDeclaredFields(); + List xmlFields = new ArrayList(); + List errors = new ArrayList(); + + for (Field field : fields) { + int modifiers = field.getModifiers(); + if (modifiers == (Modifier.PRIVATE) || modifiers == (Modifier.PRIVATE | Modifier.FINAL)) { + xmlFields.add(field); + } + } + + for (Field field : xmlFields) { + String getter = "get" + StringUtils.capitalise(field.getName()); + try { + Method method = clazz.getDeclaredMethod(getter); + int modifier = method.getModifiers(); + if (!Modifier.isPublic(modifier)) { + errors.add(getter + " is not a public method"); + } + } catch (Exception e) { + String wrongGetter = "is" + StringUtils.capitalise(field.getName()); + try { + clazz.getDeclaredMethod(wrongGetter); + errors.add("Setter is using the wrong name, is " + wrongGetter + " and should be " + getter); + } catch(Exception err) { + errors.add("Missing " + getter); + } + } + } + return errors; + } private GhprbTestUtil() {} diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java index 55cfcc7ef..f3d07da66 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java @@ -16,7 +16,6 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.kohsuke.github.GHIssue; import org.kohsuke.github.GHPullRequest; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -123,7 +122,7 @@ public void testCheckSkipBuild() throws Exception { } } - } + } From 840d30a7f71e60eae61376595f38e5eb77a5d86c Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 13 Feb 2016 19:54:10 -0700 Subject: [PATCH 161/175] [maven-release-plugin] prepare release ghprb-1.30.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index dc4c308f6..89677a2e8 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30.3-SNAPSHOT + 1.30.3 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.30.3 From be92de7d5e36fdd2761d93e4ff2b9e1b3f153793 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Sat, 13 Feb 2016 19:54:13 -0700 Subject: [PATCH 162/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 89677a2e8..1049c2441 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30.3 + 1.30.4-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.30.3 + HEAD From 46e5df1b44bbdd23c2c4a4fc8fb0184dec398509 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Wed, 17 Feb 2016 21:12:46 -0800 Subject: [PATCH 163/175] Fix NPE Ghprb.extractTrigger could return null --- .../java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 0a9c46e4e..3cdb73632 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -182,6 +182,10 @@ private Set getTriggers(String repoName, String body, String signa if (projects != null) { for (AbstractProject project : projects) { GhprbTrigger trigger = Ghprb.extractTrigger(project); + if (trigger == null) { + logger.log(Level.WARNING, "Warning, trigger unexpectedly null for project " + project.getFullName()); + continue; + } if (trigger.matchSignature(body, signature)) { triggers.add(trigger); } From 6220ae18c3c215939f92a06b482e7d16db898f72 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 19 Feb 2016 13:59:37 -0700 Subject: [PATCH 164/175] [maven-release-plugin] prepare release ghprb-1.30.4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1049c2441..b41bf975c 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30.4-SNAPSHOT + 1.30.4 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.30.4 From 3a417172f14d8f762f0ad42dbdf7fb5e01ec1687 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 19 Feb 2016 13:59:40 -0700 Subject: [PATCH 165/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b41bf975c..c8c9f17f8 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30.4 + 1.30.5-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.30.4 + HEAD From 9fc10582b255d8e86ceefccbc7ba428daf016741 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 23 Feb 2016 10:21:13 -0700 Subject: [PATCH 166/175] Add a build step extension that executes when a new build is scheduled. When the build is scheduled, add an extension that will go back and cancel queued builds, and abort running builds. Fixes #272 and fixes #241 --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 19 +++- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 14 ++- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 27 ++++- .../ghprb/extensions/GhprbBuildStep.java | 12 +++ .../build/GhprbCancelBuildsOnUpdate.java | 102 ++++++++++++++++++ .../GhprbCancelBuildsOnUpdate/config.jelly | 2 + 6 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbBuildStep.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 062f9dc1b..95b481df1 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -19,8 +19,9 @@ import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Cause; -import hudson.model.Item; +import hudson.model.Queue; import hudson.model.Result; +import hudson.model.Run; import hudson.model.Saveable; import hudson.model.TaskListener; import hudson.security.ACL; @@ -277,7 +278,7 @@ public static Set createSet(String list) { } - public static GhprbCause getCause(AbstractBuild build) { + public static GhprbCause getCause(Run build) { Cause cause = build.getCause(GhprbCause.class); if (cause == null || (!(cause instanceof GhprbCause))) { return null; @@ -285,6 +286,16 @@ public static GhprbCause getCause(AbstractBuild build) { return (GhprbCause) cause; } + + public static GhprbCause getCause(Queue.Item item) { + for (Cause cause : item.getCauses()){ + if (cause instanceof GhprbCause) { + return (GhprbCause) cause; + } + } + return null; + } + public static GhprbTrigger extractTrigger(AbstractBuild build) { return extractTrigger(build.getProject()); } @@ -395,7 +406,7 @@ public static void addIfMissing(DescribableList build, TaskListener listener) { // remove the BuildData action that we may have added earlier to avoid // having two of them, and because the one we added isn't correct // @see GhprbTrigger - BuildData fakeOne = null; for (BuildData data : build.getActions(BuildData.class)) { if (data.getLastBuiltRevision() != null && !data.getLastBuiltRevision().getSha1String().equals(c.getCommit())) { - fakeOne = data; + build.getActions().remove(data); break; } } - if (fakeOne != null) { - build.getActions().remove(fakeOne); + + + if (build.getResult() == Result.ABORTED) { + GhprbBuildStep abortAction = build.getAction(GhprbBuildStep.class); + if (abortAction != null) { + return; + } } for (GhprbExtension ext : Ghprb.getJobExtensions(trigger, GhprbCommitStatus.class)) { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index ccc5849c8..e3bf7aae1 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -28,7 +28,9 @@ import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; +import org.jenkinsci.plugins.ghprb.extensions.GhprbBuildStep; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatus; +import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtensionDescriptor; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildLog; @@ -280,8 +282,17 @@ public void run() { this.repository.check(); } + public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { + + + for (GhprbExtension ext : Ghprb.getJobExtensions(this, GhprbBuildStep.class)) { + if (ext instanceof GhprbBuildStep) { + ((GhprbBuildStep)ext).onStartBuild(super.job, cause); + } + } + ArrayList values = getDefaultParameters(); final String commitSha = cause.isMerged() ? "origin/pr/" + cause.getPullID() + "/merge" : cause.getCommit(); values.add(new StringParameterValue("sha1", commitSha)); @@ -695,7 +706,19 @@ public DescriptorImpl() { if (repoJobs == null) { repoJobs = new ConcurrentHashMap>>(); } - save(); + saveAfterPause(); + } + + private void saveAfterPause() { + new java.util.Timer().schedule( + new java.util.TimerTask() { + @Override + public void run() { + save(); + } + }, + 5000 + ); } @Override @@ -737,7 +760,7 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc readBackFromLegacy(); - save(); + saveAfterPause(); return super.configure(req, formData); } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbBuildStep.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbBuildStep.java new file mode 100644 index 000000000..9458d0f22 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbBuildStep.java @@ -0,0 +1,12 @@ +package org.jenkinsci.plugins.ghprb.extensions; + +import org.jenkinsci.plugins.ghprb.GhprbCause; + +import hudson.model.AbstractProject; +import hudson.model.Action; + +public interface GhprbBuildStep extends Action { + public static String buildStep = "GhprbBuildStep"; + + public void onStartBuild(AbstractProject project, GhprbCause cause); +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java new file mode 100644 index 000000000..81ee75703 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java @@ -0,0 +1,102 @@ +package org.jenkinsci.plugins.ghprb.extensions.build; + +import java.util.logging.Logger; + +import org.jenkinsci.plugins.ghprb.Ghprb; +import org.jenkinsci.plugins.ghprb.GhprbCause; +import org.jenkinsci.plugins.ghprb.extensions.GhprbBuildStep; +import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; +import org.jenkinsci.plugins.ghprb.extensions.GhprbExtensionDescriptor; +import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalExtension; +import org.jenkinsci.plugins.ghprb.extensions.GhprbProjectExtension; +import org.kohsuke.stapler.DataBoundConstructor; + +import hudson.Extension; +import hudson.model.AbstractProject; +import hudson.model.Queue; +import hudson.model.Result; +import hudson.model.Run; +import hudson.util.RunList; +import jenkins.model.Jenkins; + +public class GhprbCancelBuildsOnUpdate extends GhprbExtension implements GhprbBuildStep, GhprbProjectExtension { + + @Extension + public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); + private static final Logger logger = Logger.getLogger(GhprbCancelBuildsOnUpdate.class.getName()); + + @DataBoundConstructor + public GhprbCancelBuildsOnUpdate() { + + } + + private void cancelCurrentBuilds(AbstractProject project, + Integer prId) { + + Queue queue = Jenkins.getInstance().getQueue(); + for (Queue.Item item : queue.getItems(project)) { + GhprbCause cause = Ghprb.getCause(item); + if (cause == null) { + continue; + } + if (cause.getPullID() == prId) { + queue.cancel(item); + } + } + + RunList runs = project.getBuilds(); + for (Run run : runs) { + if (!run.isBuilding() && !run.hasntStartedYet()) { + break; + } + GhprbCause cause = Ghprb.getCause(run); + if (cause == null) { + continue; + } + if (cause.getPullID() == prId) { + run.addAction(this); + run.getExecutor().interrupt(Result.ABORTED); + } + } + + } + + public void onStartBuild(AbstractProject project, + GhprbCause cause) { + + if (project == null || cause == null) { + return; + } + if (project.isBuilding() || project.isInQueue()) { + cancelCurrentBuilds(project, cause.getPullID()); + } + } + + @Override + public DescriptorImpl getDescriptor() { + return DESCRIPTOR; + } + + public static final class DescriptorImpl extends GhprbExtensionDescriptor + implements GhprbGlobalExtension, GhprbProjectExtension { + + @Override + public String getDisplayName() { + return "Cancel build on update"; + } + } + + public String getIconFileName() { + // TODO Auto-generated method stub + return null; + } + + public String getDisplayName() { + return "Cancel Build on Pull Request Update"; + } + + public String getUrlName() { + return null; + } + +} diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly new file mode 100644 index 000000000..d439808e2 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly @@ -0,0 +1,2 @@ + + From 70c4cd7b890d4ea385d2b78cb7525747521fb2f5 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 23 Feb 2016 17:08:40 -0700 Subject: [PATCH 167/175] Add some tests. Make it so that extensions we want to default from global make it to the project. --- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 11 ++- .../ghprb/extensions/GhprbGlobalDefault.java | 5 ++ .../build/GhprbCancelBuildsOnUpdate.java | 38 +++++---- .../extensions/comments/GhprbBuildLog.java | 1 - .../extensions/comments/GhprbBuildStatus.java | 2 - .../comments/GhprbPublishJenkinsUrl.java | 9 ++- .../extensions/status/GhprbSimpleStatus.java | 78 +++++++++++++------ .../GhprbCancelBuildsOnUpdate/config.jelly | 3 + .../jenkinsci/plugins/ghprb/GeneralTest.java | 6 ++ .../plugins/ghprb/GhprbTriggerTest.java | 21 +++++ 10 files changed, 129 insertions(+), 45 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbGlobalDefault.java diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index e3bf7aae1..d465a2be8 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -33,6 +33,9 @@ import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtensionDescriptor; +import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalDefault; +import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalExtension; +import org.jenkinsci.plugins.ghprb.extensions.GhprbProjectExtension; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildLog; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildStatus; @@ -109,8 +112,12 @@ private void setExtensions(List extensions) { GhprbCommitStatus.class ); - // Now make sure we have at least one of the types we need one of. - Ghprb.addIfMissing(this.extensions, Ghprb.getGlobal(GhprbSimpleStatus.class), GhprbCommitStatus.class); + // Make sure we have at least one of the types we need one of. + for (GhprbExtension ext : getDescriptor().getExtensions()) { + if (ext instanceof GhprbGlobalDefault) { + Ghprb.addIfMissing(this.extensions, Ghprb.getGlobal(ext.getClass()), ext.getClass()); + } + } } @DataBoundConstructor diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbGlobalDefault.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbGlobalDefault.java new file mode 100644 index 000000000..dcbd3986c --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbGlobalDefault.java @@ -0,0 +1,5 @@ +package org.jenkinsci.plugins.ghprb.extensions; + +public interface GhprbGlobalDefault { + +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java index 81ee75703..07c88e0be 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java @@ -7,6 +7,7 @@ import org.jenkinsci.plugins.ghprb.extensions.GhprbBuildStep; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtensionDescriptor; +import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalDefault; import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbProjectExtension; import org.kohsuke.stapler.DataBoundConstructor; @@ -19,15 +20,21 @@ import hudson.util.RunList; import jenkins.model.Jenkins; -public class GhprbCancelBuildsOnUpdate extends GhprbExtension implements GhprbBuildStep, GhprbProjectExtension { +public class GhprbCancelBuildsOnUpdate extends GhprbExtension implements GhprbBuildStep, GhprbGlobalExtension, GhprbProjectExtension, GhprbGlobalDefault { @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); private static final Logger logger = Logger.getLogger(GhprbCancelBuildsOnUpdate.class.getName()); + + private final Boolean overrideGlobal; @DataBoundConstructor - public GhprbCancelBuildsOnUpdate() { - + public GhprbCancelBuildsOnUpdate(Boolean overrideGlobal) { + this.overrideGlobal = overrideGlobal; + } + + public Boolean getOverrideGlobal() { + return overrideGlobal == null ? false : overrideGlobal; } private void cancelCurrentBuilds(AbstractProject project, @@ -72,6 +79,19 @@ public void onStartBuild(AbstractProject project, } } + public String getIconFileName() { + // TODO Auto-generated method stub + return null; + } + + public String getDisplayName() { + return "Cancel Build on Pull Request Update"; + } + + public String getUrlName() { + return null; + } + @Override public DescriptorImpl getDescriptor() { return DESCRIPTOR; @@ -86,17 +106,5 @@ public String getDisplayName() { } } - public String getIconFileName() { - // TODO Auto-generated method stub - return null; - } - - public String getDisplayName() { - return "Cancel Build on Pull Request Update"; - } - - public String getUrlName() { - return null; - } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog.java index 6d2c8006e..8ceeabc9a 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildLog.java @@ -61,7 +61,6 @@ public String postBuildComment(AbstractBuild build, TaskListener listener) public boolean ignorePublishedUrl() { return false; } - @Override public DescriptorImpl getDescriptor() { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus.java index 3a3cf5b04..9bd5f6d90 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbBuildStatus.java @@ -8,7 +8,6 @@ import hudson.model.AbstractBuild; import org.jenkinsci.plugins.ghprb.Ghprb; -import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommentAppender; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtensionDescriptor; @@ -31,7 +30,6 @@ public GhprbBuildStatus(List messages) { public List getMessages() { return messages == null ? new ArrayList(0) : messages; } - public String postBuildComment(AbstractBuild build, TaskListener listener) { StringBuilder msg = new StringBuilder(); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbPublishJenkinsUrl.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbPublishJenkinsUrl.java index 1e8dffdf4..efed7e559 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbPublishJenkinsUrl.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/comments/GhprbPublishJenkinsUrl.java @@ -41,7 +41,10 @@ public String postBuildComment(AbstractBuild build, TaskListener listener) return msg.toString(); } - + + public boolean addIfMissing() { + return false; + } private String generateCustomizedMessage(AbstractBuild build) { GhprbTrigger trigger = Ghprb.extractTrigger(build); @@ -75,6 +78,10 @@ public static final class DescriptorImpl extends GhprbExtensionDescriptor implem public String getDisplayName() { return "Add link to Jenkins"; } + + public boolean addIfMissing() { + return false; + } } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java index 70519dfda..b6df911db 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/status/GhprbSimpleStatus.java @@ -21,6 +21,7 @@ import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtensionDescriptor; +import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalDefault; import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbProjectExtension; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; @@ -31,7 +32,8 @@ import org.kohsuke.github.GHRepository; import org.kohsuke.stapler.DataBoundConstructor; -public class GhprbSimpleStatus extends GhprbExtension implements GhprbCommitStatus, GhprbGlobalExtension, GhprbProjectExtension { +public class GhprbSimpleStatus extends GhprbExtension + implements GhprbCommitStatus, GhprbGlobalExtension, GhprbProjectExtension, GhprbGlobalDefault { @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); @@ -41,23 +43,21 @@ public class GhprbSimpleStatus extends GhprbExtension implements GhprbCommitStat private final String startedStatus; private final String statusUrl; private final List completedStatus; - - + public GhprbSimpleStatus() { this(null, null, null, null, new ArrayList(0)); } - + public GhprbSimpleStatus(String commitStatusContext) { this(commitStatusContext, null, null, null, new ArrayList(0)); } @DataBoundConstructor - public GhprbSimpleStatus( - String commitStatusContext, - String statusUrl, - String triggeredStatus, - String startedStatus, - List completedStatus) { + public GhprbSimpleStatus(String commitStatusContext, + String statusUrl, + String triggeredStatus, + String startedStatus, + List completedStatus) { this.statusUrl = statusUrl; this.commitStatusContext = commitStatusContext == null ? "" : commitStatusContext; this.triggeredStatus = triggeredStatus; @@ -85,7 +85,15 @@ public List getCompletedStatus() { return completedStatus == null ? new ArrayList(0) : completedStatus; } -public void onBuildTriggered(AbstractProject project, String commitSha, boolean isMergeable, int prId, GHRepository ghRepository) throws GhprbCommitStatusException { + public boolean addIfMissing() { + return true; + } + + public void onBuildTriggered(AbstractProject project, + String commitSha, + boolean isMergeable, + int prId, + GHRepository ghRepository) throws GhprbCommitStatusException { StringBuilder sb = new StringBuilder(); GHCommitState state = GHCommitState.PENDING; String triggeredStatus = getDescriptor().getTriggeredStatusDefault(this); @@ -113,7 +121,7 @@ public void onBuildTriggered(AbstractProject project, String commitSha, bo } String url = Ghprb.replaceMacros(project, statusUrl); - if (StringUtils.equals( statusUrl, "--none--")) { + if (StringUtils.equals(statusUrl, "--none--")) { url = ""; } @@ -125,12 +133,16 @@ public void onBuildTriggered(AbstractProject project, String commitSha, bo } } - public void onEnvironmentSetup(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { + public void onEnvironmentSetup(AbstractBuild build, + TaskListener listener, + GHRepository repo) throws GhprbCommitStatusException { // no need to create a commit here -- the onBuildStart() event will fire // soon and will respect's the user's settings for startedStatus. } - public void onBuildStart(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { + public void onBuildStart(AbstractBuild build, + TaskListener listener, + GHRepository repo) throws GhprbCommitStatusException { String startedStatus = getDescriptor().getStartedStatusDefault(this); // check if we even need to update @@ -149,9 +161,11 @@ public void onBuildStart(AbstractBuild build, TaskListener listener, GHRep createCommitStatus(build, listener, sb.toString(), repo, GHCommitState.PENDING); } - public void onBuildComplete(AbstractBuild build, TaskListener listener, GHRepository repo) throws GhprbCommitStatusException { + public void onBuildComplete(AbstractBuild build, + TaskListener listener, + GHRepository repo) throws GhprbCommitStatusException { List completedStatus = getDescriptor().getCompletedStatusDefault(this); - + GHCommitState state = Ghprb.getState(build); StringBuilder sb = new StringBuilder(); @@ -172,7 +186,9 @@ public void onBuildComplete(AbstractBuild build, TaskListener listener, GH if (trigger == null) { listener.getLogger().println("Unable to get pull request builder trigger!!"); } else { - JobConfiguration jobConfiguration = JobConfiguration.builder().printStackTrace(trigger.getDisplayBuildErrorsOnDownstreamBuilds()).build(); + JobConfiguration jobConfiguration = + JobConfiguration.builder() + .printStackTrace(trigger.getDisplayBuildErrorsOnDownstreamBuilds()).build(); GhprbBuildManager buildManager = GhprbBuildManagerFactoryUtil.getBuildManager(build, jobConfiguration); sb.append(buildManager.getOneLineTestResults()); @@ -181,10 +197,14 @@ public void onBuildComplete(AbstractBuild build, TaskListener listener, GH createCommitStatus(build, listener, sb.toString(), repo, state); } - private void createCommitStatus(AbstractBuild build, TaskListener listener, String message, GHRepository repo, GHCommitState state) throws GhprbCommitStatusException { + private void createCommitStatus(AbstractBuild build, + TaskListener listener, + String message, + GHRepository repo, + GHCommitState state) throws GhprbCommitStatusException { Map envVars = Ghprb.getEnvVars(build, listener); - + String sha1 = envVars.get("ghprbActualCommit"); Integer pullId = Integer.parseInt(envVars.get("ghprbPullId")); @@ -195,17 +215,21 @@ private void createCommitStatus(AbstractBuild build, TaskListener listener if (StringUtils.isEmpty(url)) { url = Jenkins.getInstance().getRootUrl() + build.getUrl(); } - + if (StringUtils.equals(statusUrl, "--none--")) { url = ""; } else if (!StringUtils.isEmpty(statusUrl)) { - url = Ghprb.replaceMacros(build, listener, statusUrl); + url = Ghprb.replaceMacros(build, listener, statusUrl); } - + String context = Util.fixEmpty(commitStatusContext); context = Ghprb.replaceMacros(build, listener, context); - listener.getLogger().println(String.format("Setting status of %s to %s with url %s and message: '%s'", sha1, state, url, message)); + listener.getLogger().println(String.format("Setting status of %s to %s with url %s and message: '%s'", + sha1, + state, + url, + message)); if (context != null) { listener.getLogger().println(String.format("Using context: " + context)); } @@ -221,7 +245,8 @@ public DescriptorImpl getDescriptor() { return DESCRIPTOR; } - public static final class DescriptorImpl extends GhprbExtensionDescriptor implements GhprbGlobalExtension, GhprbProjectExtension { + public static final class DescriptorImpl extends GhprbExtensionDescriptor + implements GhprbGlobalExtension, GhprbProjectExtension { @Override public String getDisplayName() { @@ -247,5 +272,10 @@ public List getCompletedStatusDefault(GhprbSimpleStatus public String getCommitStatusContextDefault(GhprbSimpleStatus local) { return Ghprb.getDefaultValue(local, GhprbSimpleStatus.class, "getCommitStatusContext"); } + + public boolean addIfMissing() { + return false; + } + } } diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly index d439808e2..f21c98ece 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly @@ -1,2 +1,5 @@ + + + diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GeneralTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GeneralTest.java index e5b72caed..7a62ce65e 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GeneralTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GeneralTest.java @@ -4,6 +4,7 @@ import java.util.List; +import org.jenkinsci.plugins.ghprb.extensions.build.GhprbCancelBuildsOnUpdate; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildLog; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildStatus; @@ -63,4 +64,9 @@ public void checkSimpleStatusForGetters() { checkClassForGetters(GhprbSimpleStatus.class); } + @Test + public void checkCancelBuildsOnUpdateForGetters() { + checkClassForGetters(GhprbCancelBuildsOnUpdate.class); + } + } diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java index f3d07da66..b7853f827 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTriggerTest.java @@ -14,8 +14,13 @@ import java.util.Set; import java.util.regex.Pattern; +import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; +import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalDefault; +import org.jenkinsci.plugins.ghprb.extensions.build.GhprbCancelBuildsOnUpdate; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.jvnet.hudson.test.JenkinsRule; import org.kohsuke.github.GHPullRequest; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -26,11 +31,27 @@ @RunWith(MockitoJUnitRunner.class) public class GhprbTriggerTest { + @Rule + public JenkinsRule jenkinsRule = new JenkinsRule(); + @Mock private GhprbPullRequest pr; @Mock private Ghprb helper; + + @Test + public void testGlobalExtensions() throws Exception { + GhprbTrigger.getDscp().getExtensions().add(new GhprbCancelBuildsOnUpdate(false)); + + GhprbTrigger trigger = GhprbTestUtil.getTrigger(); + + for (GhprbExtension ext : trigger.getDescriptor().getExtensions()) { + if (ext instanceof GhprbGlobalDefault) { + assertThat(trigger.getExtensions().contains(ext)); + } + } + } @Test public void testCheckSkipBuild() throws Exception { From 65088f9deaf7ef77944d9dd0f4a20cd92cd80e55 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 23 Feb 2016 17:10:07 -0700 Subject: [PATCH 168/175] Add the ignore global setting. This way if there is a global default, you can still turn it off locally --- .../ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java | 5 ++++- .../extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java index 07c88e0be..50e8ea484 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java @@ -39,7 +39,10 @@ public Boolean getOverrideGlobal() { private void cancelCurrentBuilds(AbstractProject project, Integer prId) { - + if (overrideGlobal) { + return; + } + Queue queue = Jenkins.getInstance().getQueue(); for (Queue.Item item : queue.getItems(project)) { GhprbCause cause = Ghprb.getCause(item); diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly index f21c98ece..eb333a89f 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/extensions/builds/GhprbCancelBuildsOnUpdate/config.jelly @@ -1,5 +1,5 @@ - + From da1a9d4254823735aa8eaae647ab56d8e095507c Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 23 Feb 2016 18:34:33 -0700 Subject: [PATCH 169/175] Rename methods to explain what is going on, schedule instead of start --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java | 2 +- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 4 ++-- .../jenkinsci/plugins/ghprb/extensions/GhprbBuildStep.java | 2 +- .../ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java | 2 +- .../java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index d538305ce..4b2446af9 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -77,7 +77,7 @@ public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) } } } - QueueTaskFuture build = trigger.startJob(cause, repo); + QueueTaskFuture build = trigger.scheduleBuild(cause, repo); if (build == null) { logger.log(Level.SEVERE, "Job did not start"); } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index d465a2be8..dbbf9d675 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -291,12 +291,12 @@ public void run() { } - public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { + public QueueTaskFuture scheduleBuild(GhprbCause cause, GhprbRepository repo) { for (GhprbExtension ext : Ghprb.getJobExtensions(this, GhprbBuildStep.class)) { if (ext instanceof GhprbBuildStep) { - ((GhprbBuildStep)ext).onStartBuild(super.job, cause); + ((GhprbBuildStep)ext).onScheduleBuild(super.job, cause); } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbBuildStep.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbBuildStep.java index 9458d0f22..6a0ca7292 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbBuildStep.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/GhprbBuildStep.java @@ -8,5 +8,5 @@ public interface GhprbBuildStep extends Action { public static String buildStep = "GhprbBuildStep"; - public void onStartBuild(AbstractProject project, GhprbCause cause); + public void onScheduleBuild(AbstractProject project, GhprbCause cause); } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java index 50e8ea484..d50817f26 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/extensions/build/GhprbCancelBuildsOnUpdate.java @@ -71,7 +71,7 @@ private void cancelCurrentBuilds(AbstractProject project, } - public void onStartBuild(AbstractProject project, + public void onScheduleBuild(AbstractProject project, GhprbCause cause) { if (project == null || cause == null) { diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java index 66a61f695..3a519f8ae 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRepositoryTest.java @@ -117,7 +117,7 @@ public void setUp() throws Exception { pulls = new ConcurrentHashMap(); - doReturn(mock(QueueTaskFuture.class)).when(trigger).startJob(any(GhprbCause.class), any(GhprbRepository.class)); + doReturn(mock(QueueTaskFuture.class)).when(trigger).scheduleBuild(any(GhprbCause.class), any(GhprbRepository.class)); initGHPRWithTestData(); given(ghPullRequest.getUser()).willReturn(ghUser); From dcf3b9a9e1dd73ddce8441831f4774e24811c6b4 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 23 Feb 2016 18:46:52 -0700 Subject: [PATCH 170/175] Pull in Queue.item just to the extension. Add some try catch clauses to canceling queue items and active run objects. --- .../org/jenkinsci/plugins/ghprb/Ghprb.java | 15 ++-------- .../build/GhprbCancelBuildsOnUpdate.java | 29 ++++++++++++++----- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 95b481df1..fc704f912 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -19,7 +19,7 @@ import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Cause; -import hudson.model.Queue; +import hudson.model.Item; import hudson.model.Result; import hudson.model.Run; import hudson.model.Saveable; @@ -287,15 +287,6 @@ public static GhprbCause getCause(Run build) { } - public static GhprbCause getCause(Queue.Item item) { - for (Cause cause : item.getCauses()){ - if (cause instanceof GhprbCause) { - return (GhprbCause) cause; - } - } - return null; - } - public static GhprbTrigger extractTrigger(AbstractBuild build) { return extractTrigger(build.getProject()); } @@ -406,7 +397,7 @@ public static void addIfMissing(DescribableList project, Queue queue = Jenkins.getInstance().getQueue(); for (Queue.Item item : queue.getItems(project)) { - GhprbCause cause = Ghprb.getCause(item); - if (cause == null) { + GhprbCause qcause = null; + for (Cause cause : item.getCauses()){ + if (cause instanceof GhprbCause) { + qcause = (GhprbCause) cause; + } + } + if (qcause == null) { continue; } - if (cause.getPullID() == prId) { - queue.cancel(item); + if (qcause.getPullID() == prId) { + try { + queue.cancel(item); + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to cancel queued build", e); + } } } @@ -64,8 +75,13 @@ private void cancelCurrentBuilds(AbstractProject project, continue; } if (cause.getPullID() == prId) { - run.addAction(this); - run.getExecutor().interrupt(Result.ABORTED); + try { + run.addAction(this); + run.getExecutor().interrupt(Result.ABORTED); + } catch (Exception e) { + run.getActions().remove(this); + logger.log(Level.SEVERE, "Unable to interrupt build!", e); + } } } @@ -83,7 +99,6 @@ public void onScheduleBuild(AbstractProject project, } public String getIconFileName() { - // TODO Auto-generated method stub return null; } From f34441ebc455ffacf1e7b706e49f822a07fcd346 Mon Sep 17 00:00:00 2001 From: Vaughn Dice Date: Wed, 24 Feb 2016 16:38:10 -0700 Subject: [PATCH 171/175] update 'githubPullRequest' to 'pullRequest' in Job DSL section --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 718d8beb0..5dd379097 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ job('upstreamJob') { } triggers { - githubPullRequest { + pullRequest { admin('user_1') admins(['user_2', 'user_3']) userWhitelist('you@you.com') From 3f0a66810d80236fecbce047b3ab21f6fd797d27 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquet Date: Thu, 25 Feb 2016 11:16:18 -0500 Subject: [PATCH 172/175] Fix NPE when last build has been deleted --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index ccc5849c8..8802297e1 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -295,7 +295,9 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { BuildData buildData = null; if (!(job instanceof MatrixProject) && !StringUtils.isEmpty(lastBuildId)) { AbstractBuild lastBuild = job.getBuild(lastBuildId); - buildData = lastBuild.getAction(BuildData.class); + if (lastBuild != null) { + buildData = lastBuild.getAction(BuildData.class); + } } try { From 622c84aab507c8069cafb7f2b04d0f2f3a62a95d Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 25 Feb 2016 16:45:17 -0700 Subject: [PATCH 173/175] Trigger should only be applicable to AbstractProject items --- src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 92f74ff36..71ddd54a4 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -30,12 +30,9 @@ import org.apache.commons.lang.StringUtils; import org.jenkinsci.plugins.ghprb.extensions.GhprbBuildStep; import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatus; -import org.jenkinsci.plugins.ghprb.extensions.GhprbCommitStatusException; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtensionDescriptor; import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalDefault; -import org.jenkinsci.plugins.ghprb.extensions.GhprbGlobalExtension; -import org.jenkinsci.plugins.ghprb.extensions.GhprbProjectExtension; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildLog; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildStatus; @@ -732,7 +729,7 @@ public void run() { @Override public boolean isApplicable(Item item) { - return true; + return item instanceof AbstractProject; } @Override From 26c63102b13f0dea3d1afc6361d8be6eb04c885f Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 25 Feb 2016 20:44:55 -0700 Subject: [PATCH 174/175] [maven-release-plugin] prepare release ghprb-1.30.5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c8c9f17f8..528ef294e 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30.5-SNAPSHOT + 1.30.5 hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - HEAD + ghprb-1.30.5 From 697b7a2ea8fec1c53d97d4189c13a39e747b2da5 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Thu, 25 Feb 2016 20:44:59 -0700 Subject: [PATCH 175/175] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 528ef294e..e444d48b2 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.30.5 + 1.30.6-SNAPSHOT hpi https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin @@ -31,7 +31,7 @@ scm:git:ssh://github.com/jenkinsci/ghprb-plugin.git scm:git:ssh://git@github.com/jenkinsci/ghprb-plugin.git https://github.com/jenkinsci/ghprb-plugin - ghprb-1.30.5 + HEAD