From 892ac3d9de7370db366c8349dde7c63f515409c8 Mon Sep 17 00:00:00 2001 From: Jo Shields Date: Wed, 22 Apr 2015 16:56:01 +0100 Subject: [PATCH 01/11] Attempt to append test result statistics to status message sent to GH --- .../jenkinsci/plugins/ghprb/GhprbBuilds.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index e8c8690ae..eece07aea 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -116,8 +116,31 @@ public void onCompleted(AbstractBuild build, TaskListener listener) { } GHCommitState state; - state = Ghprb.getState(build); - repo.createCommitStatus(build, state, "Build finished.", c.getPullID(), trigger.getCommitStatusContext(), listener.getLogger()); + if (build.getResult() == Result.SUCCESS) { + state = GHCommitState.SUCCESS; + } else if (build.getResult() == Result.UNSTABLE) { + state = GHCommitState.valueOf(GhprbTrigger.getDscp().getUnstableAs()); + } else { + state = GHCommitState.FAILURE; + } + + JobConfiguration jobConfiguration = + JobConfiguration.builder() + .printStackTrace(trigger.isDisplayBuildErrorsOnDownstreamBuilds()) + .build(); + + GhprbBuildManager buildManager = + GhprbBuildManagerFactoryUtil.getBuildManager(build, jobConfiguration); + + StringBuilder replyMessage = new StringBuilder(); + + if (c.isMerged()) { + replyMessage.append("Merged build finished. "); + } else { + replyMessage.append("Build finished. "); + } + replyMessage.append(buildManager.getTestResults()); + repo.createCommitStatus(build, state, replyMessage.toString(), c.getPullID(), trigger.getCommitStatusContext(), listener.getLogger()); buildResultMessage(build, listener, state, c); // close failed pull request automatically From ffbc581d2712d6b99b9c6d0b081d7895a5ee8039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Thu, 23 Apr 2015 20:40:32 +0200 Subject: [PATCH 02/11] Add test results to commit status message. --- .../org/jenkinsci/plugins/ghprb/GhprbBuilds.java | 2 +- .../plugins/ghprb/manager/GhprbBuildManager.java | 7 +++++++ .../ghprb/manager/impl/GhprbBaseBuildManager.java | 14 +++++++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java index eece07aea..499c73ee3 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbBuilds.java @@ -139,7 +139,7 @@ public void onCompleted(AbstractBuild build, TaskListener listener) { } else { replyMessage.append("Build finished. "); } - replyMessage.append(buildManager.getTestResults()); + replyMessage.append(buildManager.getOneLineTestResults()); repo.createCommitStatus(build, state, replyMessage.toString(), c.getPullID(), trigger.getCommitStatusContext(), listener.getLogger()); buildResultMessage(build, listener, state, c); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/manager/GhprbBuildManager.java b/src/main/java/org/jenkinsci/plugins/ghprb/manager/GhprbBuildManager.java index 7ff51b264..cb24acea0 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/manager/GhprbBuildManager.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/manager/GhprbBuildManager.java @@ -21,6 +21,13 @@ public interface GhprbBuildManager { */ Iterator downstreamProjects(); + /** + * Print tests result of a build in one line. + * + * @return the tests result + */ + String getOneLineTestResults(); + /** * Print tests result of a build * 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 68b602660..97ad4acad 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 @@ -13,10 +13,12 @@ import hudson.model.AbstractProject; import hudson.model.Result; 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; +import org.jenkinsci.plugins.ghprb.GhprbTrigger; import org.jenkinsci.plugins.ghprb.manager.configuration.JobConfiguration; import org.jenkinsci.plugins.ghprb.manager.GhprbBuildManager; @@ -168,10 +170,20 @@ protected String getAggregatedTestResults(AbstractBuild build) { protected static final Logger LOGGER = Logger.getLogger(GhprbBaseBuildManager.class.getName()); + public String getOneLineTestResults() { + + TestResultAction testResultAction = build.getAction(TestResultAction.class); + + if (testResultAction == null) { + return "No test results found."; + } + return String.format("%d tests run, %d skipped, %d failed.", testResultAction.getTotalCount(), testResultAction.getSkipCount(), testResultAction.getFailCount()); + } + protected AbstractBuild build; private static final int _MAX_LINES_COUNT = 25; private JobConfiguration jobConfiguration; -} \ No newline at end of file +} From 885038230250abbeb1e8d2afa98bbe280d1a82b6 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 3 Jun 2015 13:44:55 -0600 Subject: [PATCH 03/11] Working on GitHub auth. Start using credentials for both the token and username password. Make appropriate changes throughout the code base. Updating some of the config files to groovy --- pom.xml | 10 + .../org/jenkinsci/plugins/ghprb/Ghprb.java | 70 +++++- .../jenkinsci/plugins/ghprb/GhprbGitHub.java | 42 +--- .../plugins/ghprb/GhprbGitHubAuth.java | 234 ++++++++++++++++++ .../plugins/ghprb/GhprbRepository.java | 6 +- .../plugins/ghprb/GhprbRootAction.java | 58 ++--- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 194 ++++++++++----- .../GhprbTriggerBackwardsCompatible.java | 2 +- .../jenkinsci/plugins/ghprb/GhprbWebHook.java | 72 ++++++ .../extensions/comments/GhprbBuildStatus.java | 9 - .../ghprb/GhprbGitHubAuth/config.groovy | 49 ++++ .../plugins/ghprb/GhprbTrigger/config.groovy | 66 +++++ .../{config.jelly => config.jelly.tmp} | 0 .../plugins/ghprb/GhprbTrigger/global.groovy | 52 ++++ .../{global.jelly => global.jelly.tmp} | 3 + .../comments/GhprbBuildStatus/config.jelly | 2 +- .../org/jenkinsci/plugins/ghprb/GhprbIT.java | 22 +- .../ghprb/GhprbPullRequestMergeTest.java | 3 +- .../plugins/ghprb/GhprbRootActionTest.java | 23 +- .../plugins/ghprb/GhprbTestUtil.java | 124 ++++++---- .../status/GhprbSimpleStatusTest.java | 1 - .../impl/GhprbDefaultBuildManagerTest.java | 17 +- .../BuildFlowBuildManagerTest.java | 8 +- 23 files changed, 814 insertions(+), 253 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java create mode 100644 src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/config.groovy rename src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/{config.jelly => config.jelly.tmp} (100%) create mode 100644 src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.groovy rename src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/{global.jelly => global.jelly.tmp} (93%) diff --git a/pom.xml b/pom.xml index 993da5137..b551f0f2b 100644 --- a/pom.xml +++ b/pom.xml @@ -94,6 +94,16 @@ 0.12 true + + org.jenkins-ci.plugins + credentials + 1.21 + + + org.jenkins-ci.plugins + plain-credentials + 1.1 + diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java index 12b093094..c8948b081 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/Ghprb.java @@ -1,15 +1,31 @@ package org.jenkinsci.plugins.ghprb; +import com.cloudbees.plugins.credentials.CredentialsMatchers; +import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.CredentialsScope; +import com.cloudbees.plugins.credentials.CredentialsStore; +import com.cloudbees.plugins.credentials.SystemCredentialsProvider; +import com.cloudbees.plugins.credentials.common.StandardCredentials; +import com.cloudbees.plugins.credentials.domains.Domain; +import com.cloudbees.plugins.credentials.domains.DomainSpecification; +import com.cloudbees.plugins.credentials.domains.HostnamePortSpecification; +import com.cloudbees.plugins.credentials.domains.HostnameSpecification; +import com.cloudbees.plugins.credentials.domains.PathSpecification; +import com.cloudbees.plugins.credentials.domains.SchemeSpecification; +import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl; import com.coravy.hudson.plugins.github.GithubProjectProperty; import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Cause; +import hudson.model.Item; import hudson.model.Result; import hudson.model.Saveable; +import hudson.security.ACL; import hudson.util.DescribableList; import hudson.util.LogTaskListener; +import hudson.util.Secret; import org.apache.commons.collections.Predicate; import org.apache.commons.collections.PredicateUtils; @@ -17,9 +33,12 @@ import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.jenkinsci.plugins.ghprb.extensions.GhprbExtensionDescriptor; import org.jenkinsci.plugins.ghprb.extensions.GhprbProjectExtension; +import org.jenkinsci.plugins.gitclient.GitURIRequirementsBuilder; +import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl; import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GHUser; +import java.net.URI; import java.util.*; import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; @@ -108,7 +127,7 @@ public GhprbRepository getRepository() { } public GhprbGitHub getGitHub() { - return trigger.getDescriptor().getGitHub(); + return new GhprbGitHub(trigger); } void run() { @@ -330,4 +349,53 @@ public static void addIfMissing(DescribableList specifications = new ArrayList(2); + + URI serverUri = new URI(serverAPIUrl); + + if (serverUri.getPort() > 0) { + specifications.add(new HostnamePortSpecification(serverUri.getHost() + ":" + serverUri.getPort(), null)); + } else { + specifications.add(new HostnameSpecification(serverUri.getHost(), null)); + } + + specifications.add(new SchemeSpecification(serverUri.getScheme())); + specifications.add(new PathSpecification(serverUri.getPath(), null, false)); + + + + Domain domain = new Domain(serverAPIUrl, "Auto generated credentials domain", specifications); + CredentialsStore provider = new SystemCredentialsProvider.StoreImpl(); + provider.addDomain(domain, credentials); + return credentials.getId(); + } } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHub.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHub.java index bf44025d0..625dcf4da 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHub.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHub.java @@ -7,54 +7,22 @@ import org.kohsuke.github.GHOrganization; import org.kohsuke.github.GHUser; import org.kohsuke.github.GitHub; -import org.kohsuke.github.GitHubBuilder; - -import com.google.common.annotations.VisibleForTesting; /** * @author janinko */ public class GhprbGitHub { private static final Logger logger = Logger.getLogger(GhprbGitHub.class.getName()); - private GitHub gh; - - private void connect() throws IOException { - String accessToken = GhprbTrigger.getDscp().getAccessToken(); - String serverAPIUrl = GhprbTrigger.getDscp().getServerAPIUrl(); - if (accessToken != null && !accessToken.isEmpty()) { - try { - gh = new GitHubBuilder() - .withEndpoint(serverAPIUrl) - .withOAuthToken(accessToken) - .withConnector(new HttpConnectorWithJenkinsProxy()) - .build(); - } catch (IOException e) { - logger.log(Level.SEVERE, "Can''t connect to {0} using oauth", serverAPIUrl); - throw e; - } - } else { - if (serverAPIUrl.contains("api/v3")) { - gh = GitHub.connectToEnterprise(serverAPIUrl, - GhprbTrigger.getDscp().getUsername(), GhprbTrigger.getDscp().getPassword()); - } else { - gh = new GitHubBuilder().withPassword(GhprbTrigger.getDscp().getUsername(), - GhprbTrigger.getDscp().getPassword()).withConnector(new HttpConnectorWithJenkinsProxy()).build(); - } - } + private final GhprbTrigger trigger; + + public GhprbGitHub(GhprbTrigger trigger) { + this.trigger = trigger; } public GitHub get() throws IOException { - if (gh == null) { - connect(); - } - return gh; + return trigger.getGitHub(); } - @VisibleForTesting - void setGitHub(GitHub gh) { - this.gh = gh; - } - public boolean isUserMemberOfOrganization(String organisation, GHUser member) { boolean orgHasMember = false; try { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java new file mode 100644 index 000000000..6883a97bf --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java @@ -0,0 +1,234 @@ +package org.jenkinsci.plugins.ghprb; + +import static hudson.Util.fixEmpty; +import static hudson.Util.fixEmptyAndTrim; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.kohsuke.github.GHAuthorization; +import org.kohsuke.github.GitHub; +import org.kohsuke.github.GitHubBuilder; +import org.kohsuke.stapler.AncestorInPath; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.export.Exported; + +import com.cloudbees.plugins.credentials.CredentialsMatchers; +import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.common.StandardCredentials; +import com.cloudbees.plugins.credentials.common.StandardListBoxModel; +import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; +import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials; +import com.cloudbees.plugins.credentials.domains.DomainRequirement; +import com.cloudbees.plugins.credentials.domains.HostnamePortRequirement; +import com.cloudbees.plugins.credentials.domains.HostnameRequirement; +import com.cloudbees.plugins.credentials.domains.PathRequirement; +import com.cloudbees.plugins.credentials.domains.SchemeRequirement; +import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder; + +import org.apache.commons.lang.StringUtils; +import org.jenkinsci.plugins.plaincredentials.StringCredentials; + +import hudson.Extension; +import hudson.model.AbstractDescribableImpl; +import hudson.model.Descriptor; +import hudson.model.Item; +import hudson.security.ACL; +import hudson.util.FormValidation; +import hudson.util.ListBoxModel; + +public class GhprbGitHubAuth extends AbstractDescribableImpl { + private static final Logger logger = Logger.getLogger(GhprbGitHubAuth.class.getName()); + + @Extension + public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); + + private final String serverAPIUrl; + private final String credentialsId; + private final String id; + private final String description; + + @DataBoundConstructor + public GhprbGitHubAuth(String serverAPIUrl, String credentialsId, String description, String id) { + if (StringUtils.isEmpty(serverAPIUrl)) { + serverAPIUrl = "https://api.github.com"; + } + this.serverAPIUrl = fixEmptyAndTrim(serverAPIUrl); + this.credentialsId = fixEmpty(credentialsId); + if (StringUtils.isEmpty(id)) { + id = UUID.randomUUID().toString(); + } + + this.id = id; + this.description = description; + } + + @Exported + public String getServerAPIUrl() { + return serverAPIUrl; + } + + @Exported + public String getCredentialsId() { + return credentialsId; + } + + @Exported + public String getDescription() { + return description; + } + + @Exported + public String getId() { + return id; + } + + public GitHub getConnection(Item context) throws IOException { + GitHub gh = null; + + if (credentialsId == null) { + return GitHub.connectAnonymously(); + } + + GitHubBuilder builder = new GitHubBuilder() + .withEndpoint(serverAPIUrl) + .withConnector(new HttpConnectorWithJenkinsProxy()); + StandardCredentials credentials = CredentialsMatchers + .firstOrNull( + CredentialsProvider.lookupCredentials(StandardCredentials.class, context, + ACL.SYSTEM, URIRequirementBuilder.fromUri(serverAPIUrl).build()), + CredentialsMatchers.allOf(CredentialsMatchers.withId(credentialsId))); + + if (credentials instanceof StringCredentials) { + String accessToken = ((StringCredentials) credentials).getSecret().getPlainText(); + builder.withOAuthToken(accessToken); + } else if (credentials instanceof UsernamePasswordCredentials){ + UsernamePasswordCredentials creds = (UsernamePasswordCredentials) credentials; + String username = creds.getUsername(); + String password = creds.getPassword().getPlainText(); + builder.withPassword(username, password); + } + try { + gh = builder.build(); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to connect using credentials: " + credentialsId, e); + } + + return gh; + } + + @Override + public DescriptorImpl getDescriptor() { + return DESCRIPTOR; + } + + public static final class DescriptorImpl extends Descriptor { + + @Override + public String getDisplayName() { + return "GitHub Auth"; + } + + /** + * Stapler helper method. + * + * @param context + * the context. + * @param remoteBase + * the remote base. + * @return list box model. + * @throws URISyntaxException + */ + public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context, @QueryParameter String serverAPIUrl) throws URISyntaxException { + List domainRequirements = getDomainReqs(serverAPIUrl); + + return new StandardListBoxModel() + .withEmptySelection() + .withMatching( + CredentialsMatchers.anyOf( + CredentialsMatchers.instanceOf(StandardUsernamePasswordCredentials.class), + CredentialsMatchers.instanceOf(StringCredentials.class)), + CredentialsProvider.lookupCredentials(StandardCredentials.class, + context, + ACL.SYSTEM, + domainRequirements) + ); + } + + + public FormValidation doCreateApiToken( + @QueryParameter("serverAPIUrl") final String serverAPIUrl, + @QueryParameter("credentialsId") final String credentialsId, + @QueryParameter("username") final String username, + @QueryParameter("password") final String password) { + try { + GitHub gh; + + if (StringUtils.isEmpty(credentialsId)) { + if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { + return FormValidation.error("Username and Password required"); + } + gh = GitHub.connectToEnterprise(serverAPIUrl, username, password); + } else { + StandardCredentials credentials = Ghprb.lookupCredentials(null, credentialsId, serverAPIUrl); + if (credentials instanceof StandardUsernamePasswordCredentials) { + StandardUsernamePasswordCredentials upCredentials = (StandardUsernamePasswordCredentials) credentials; + gh = GitHub.connectToEnterprise(serverAPIUrl, upCredentials.getUsername(), upCredentials.getPassword().getPlainText()); + } else { + return FormValidation.error("No credentials provided"); + } + } + GHAuthorization token = gh.createToken(Arrays.asList(GHAuthorization.REPO_STATUS, + GHAuthorization.REPO), "Jenkins GitHub Pull Request Builder", null); + String tokenId; + try { + tokenId = Ghprb.createCredentials(serverAPIUrl, token.getToken()); + } catch (Exception e) { + tokenId = "Unable to create credentials: " + e.getMessage(); + } + + return FormValidation.ok("Access token created: " + token.getToken() + " token CredentialsID: " + tokenId); + } catch (IOException ex) { + return FormValidation.error("GitHub API token couldn't be created: " + ex.getMessage()); + } + } + + private List getDomainReqs(String serverAPIUrl) throws URISyntaxException { + List requirements = new ArrayList(2); + + URI serverUri = new URI(serverAPIUrl); + + if (serverUri.getPort() > 0) { + requirements.add(new HostnamePortRequirement(serverUri.getHost(), serverUri.getPort())); + } else { + requirements.add(new HostnameRequirement(serverUri.getHost())); + } + + requirements.add(new SchemeRequirement(serverUri.getScheme())); + if (!StringUtils.isEmpty(serverUri.getPath())) { + requirements.add(new PathRequirement(serverUri.getPath())); + } + return requirements; + } + + public FormValidation doCheckServerAPIUrl(@QueryParameter String value) { + if ("https://api.github.com".equals(value)) { + return FormValidation.ok(); + } + if (value.endsWith("/api/v3") || value.endsWith("/api/v3/")) { + return FormValidation.ok(); + } + return FormValidation.warning("GitHub API URI is \"https://api.github.com\". GitHub Enterprise API URL ends with \"/api/v3\""); + } + + } + +} diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 90807e90b..ad5b49b44 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -54,7 +54,11 @@ public void init() { private boolean initGhRepository() { GitHub gitHub = null; try { - gitHub = helper.getGitHub().get(); + GhprbGitHub repo = helper.getGitHub(); + if (repo == null) { + return false; + } + gitHub = repo.get(); if (gitHub.getRateLimit().remaining == 0) { return false; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 1215e2b64..0579474be 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -81,45 +81,18 @@ public void doIndex(StaplerRequest req, StaplerResponse resp) { return; } - GhprbGitHub gh = GhprbTrigger.getDscp().getGitHub(); - - logger.log(Level.INFO, "Got payload event: {0}", event); - try { - if ("issue_comment".equals(event)) { - GHEventPayload.IssueComment issueComment = gh.get() - .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 (GhprbRepository repo : getRepos(issueComment.getRepository())) { - logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", - new Object[] { issueComment.getComment(), repo.getName() } - ); - repo.onIssueCommentHook(issueComment); - } - } else if ("pull_request".equals(event)) { - GHEventPayload.PullRequest pr = gh.get().parseEventPayload(new StringReader(payload), GHEventPayload.PullRequest.class); - for (GhprbRepository repo : getRepos(pr.getPullRequest().getRepository())) { - logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repo.getName(), pr.getNumber() }); - repo.onPullRequestHook(pr); - } - } else { - logger.log(Level.WARNING, "Request not known"); + for (GhprbWebHook webHook : getWebHooks()) { + try { + webHook.handleWebHook(event, payload); + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to process web hook for: " + webHook.getProjectName(), e); } - } catch (IOException ex) { - logger.log(Level.SEVERE, "Failed to parse github hook payload.", ex); } + } - - private Set getRepos(GHRepository repo) { - return getRepos(repo.getFullName()); - } - - private Set getRepos(String repo) { - final Set ret = new HashSet(); + + private Set getWebHooks() { + final Set webHooks = new HashSet(); // We need this to get access to list of repositories Authentication old = SecurityContextHolder.getContext().getAuthentication(); @@ -128,23 +101,20 @@ private Set getRepos(String repo) { try { for (AbstractProject job : Jenkins.getInstance().getAllItems(AbstractProject.class)) { GhprbTrigger trigger = job.getTrigger(GhprbTrigger.class); - if (trigger == null || trigger.getRepository() == null) { + if (trigger == null || trigger.getWebHook() == null) { continue; } - GhprbRepository r = trigger.getRepository(); - if (repo.equalsIgnoreCase(r.getName())) { - ret.add(r); - } + webHooks.add(trigger.getWebHook()); } } finally { SecurityContextHolder.getContext().setAuthentication(old); } - if (ret.size() == 0) { - logger.log(Level.WARNING, "No repos with plugin trigger found for GitHub repo named {0}", repo); + if (webHooks.size() == 0) { + logger.log(Level.WARNING, "No projects found using GitHub pull request trigger"); } - return ret; + return webHooks; } @Extension diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 8a0cd0b0e..3eebb1064 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -8,13 +8,14 @@ import hudson.Extension; import hudson.Util; import hudson.model.*; +import hudson.model.AbstractProject; import hudson.model.queue.QueueTaskFuture; import hudson.plugins.git.util.BuildData; import hudson.triggers.TriggerDescriptor; import hudson.util.DescribableList; import hudson.util.FormValidation; import hudson.util.ListBoxModel; -import net.sf.json.JSONArray; +import hudson.util.ListBoxModel.Option; import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; @@ -26,7 +27,6 @@ import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildStatus; import org.jenkinsci.plugins.ghprb.extensions.comments.GhprbPublishJenkinsUrl; import org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus; -import org.kohsuke.github.GHAuthorization; import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GitHub; import org.kohsuke.stapler.DataBoundConstructor; @@ -43,6 +43,8 @@ import java.util.logging.Logger; import java.util.regex.Pattern; +import jenkins.model.Jenkins; + /** * @author Honza Brázdil */ @@ -65,9 +67,9 @@ public class GhprbTrigger extends GhprbTriggerBackwardsCompatible { private List whiteListTargetBranches; private transient Ghprb helper; private String project; + private GhprbGitHubAuth gitHubApiAuth; - private DescribableList extensions; public DescribableList getExtensions() { @@ -108,6 +110,7 @@ public GhprbTrigger(String adminlist, String msgSuccess, String msgFailure, String commitStatusContext, + String gitHubAuthId, List extensions ) throws ANTLRException { super(cron); @@ -122,6 +125,7 @@ public GhprbTrigger(String adminlist, this.autoCloseFailedPullRequests = autoCloseFailedPullRequests; this.displayBuildErrorsOnDownstreamBuilds = displayBuildErrorsOnDownstreamBuilds; this.whiteListTargetBranches = whiteListTargetBranches; + this.gitHubApiAuth = getDescriptor().getGitHubAuth(gitHubAuthId); this.allowMembersOfWhitelistedOrgsAsAdmin = allowMembersOfWhitelistedOrgsAsAdmin; setExtensions(extensions); configVersion = 1; @@ -234,6 +238,35 @@ public QueueTaskFuture startJob(GhprbCause cause, GhprbRepository repo) { // one isn't there return this.job.scheduleBuild2(job.getQuietPeriod(), cause, new ParametersAction(values), findPreviousBuildForPullId(pullIdPv)); } + + + public GhprbGitHubAuth getGitHubApiAuth() { + if (gitHubApiAuth == null) { + for (GhprbGitHubAuth auth: getDescriptor().getGithubAuth()){ + gitHubApiAuth = auth; + break; + } + } + return gitHubApiAuth; + } + + + public GitHub getGitHub() throws IOException { + GhprbGitHubAuth auth = getGitHubApiAuth(); + if (auth == null) { + return null; + } + @SuppressWarnings("rawtypes") + List projects = Jenkins.getInstance().getAllItems(AbstractProject.class); + + for (AbstractProject project : projects) { + if (project.getFullName().equals(this.project)) { + return auth.getConnection(project); + } + } + + return gitHubApiAuth.getConnection(null); + } private void setCommitAuthor(GhprbCause cause, ArrayList values) { String authorName = ""; @@ -322,6 +355,10 @@ public String getCron() { return cron; } + public String getProject() { + return project; + } + public String getTriggerPhrase() { if (triggerPhrase == null) { return ""; @@ -364,6 +401,10 @@ public List getWhiteListTargetBranches() { return whiteListTargetBranches; } + public GhprbWebHook getWebHook() { + GhprbWebHook webHook = new GhprbWebHook(this); + return webHook; + } @Override public DescriptorImpl getDescriptor() { @@ -404,7 +445,6 @@ public static final class DescriptorImpl extends TriggerDescriptor { * value in the global.jelly file as this value is dynamic and will not be * retained once configure() is called. */ - private String serverAPIUrl = "https://api.github.com"; private String whitelistPhrase = ".*add\\W+to\\W+whitelist.*"; private String okToTestPhrase = ".*ok\\W+to\\W+test.*"; private String retestPhrase = ".*test\\W+this\\W+please.*"; @@ -416,15 +456,51 @@ public static final class DescriptorImpl extends TriggerDescriptor { private List whiteListTargetBranches; private Boolean autoCloseFailedPullRequests = false; private Boolean displayBuildErrorsOnDownstreamBuilds = false; + + private List githubAuth; + + public GhprbGitHubAuth getGitHubAuth(String gitHubAuthId) { + + if (gitHubAuthId == null) { + return getGithubAuth().get(0); + } + + GhprbGitHubAuth firstAuth = null; + for (GhprbGitHubAuth auth : getGithubAuth()) { + if (firstAuth == null) { + firstAuth = auth; + } + if (auth.getId().equals(gitHubAuthId)) { + return auth; + } + } + return firstAuth; + } + + public List getGithubAuth() { + if (githubAuth == null || githubAuth.size() == 0) { + githubAuth = new ArrayList(1); + githubAuth.add(new GhprbGitHubAuth(null, null, "Blank description", null)); + } + return githubAuth; + } + + public List getDefaultAuth(List githubAuth) { + if (githubAuth != null && githubAuth.size() > 0) { + return githubAuth; + } + List defaults = new ArrayList(1); + defaults.add(new GhprbGitHubAuth(null, null, "Blank description", null)); + return defaults; + } + + - private String username; - private String password; - private String accessToken; private String adminlist; private String requestForTestingPhrase; - private transient GhprbGitHub gh; + // map of jobs (by their fullName) and their map of pull requests private Map> jobs; @@ -465,10 +541,6 @@ public String getDisplayName() { @Override public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { - serverAPIUrl = formData.getString("serverAPIUrl"); - username = formData.getString("username"); - password = formData.getString("password"); - accessToken = formData.getString("accessToken"); adminlist = formData.getString("adminlist"); requestForTestingPhrase = formData.getString("requestForTestingPhrase"); whitelistPhrase = formData.getString("whitelistPhrase"); @@ -482,6 +554,8 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc autoCloseFailedPullRequests = formData.getBoolean("autoCloseFailedPullRequests"); displayBuildErrorsOnDownstreamBuilds = formData.getBoolean("displayBuildErrorsOnDownstreamBuilds"); + githubAuth = req.bindJSONToList(GhprbGitHubAuth.class, formData.getJSONObject("githubAuth")); + extensions = new DescribableList(Saveable.NOOP); try { @@ -493,7 +567,6 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc readBackFromLegacy(); save(); - gh = new GhprbGitHub(); return super.configure(req, formData); } @@ -505,16 +578,6 @@ public FormValidation doCheckAdminlist(@QueryParameter String value) throws Serv } return FormValidation.ok(); } - - public FormValidation doCheckServerAPIUrl(@QueryParameter String value) { - if ("https://api.github.com".equals(value)) { - return FormValidation.ok(); - } - if (value.endsWith("/api/v3") || value.endsWith("/api/v3/")) { - return FormValidation.ok(); - } - return FormValidation.warning("GitHub API URI is \"https://api.github.com\". GitHub Enterprise API URL ends with \"/api/v3\""); - } public ListBoxModel doFillUnstableAsItems() { ListBoxModel items = new ListBoxModel(); @@ -529,19 +592,7 @@ public ListBoxModel doFillUnstableAsItems() { return items; } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public String getAccessToken() { - return accessToken; - } - + public String getAdminlist() { return adminlist; } @@ -587,10 +638,6 @@ public Boolean getDisplayBuildErrorsOnDownstreamBuilds() { return displayBuildErrorsOnDownstreamBuilds; } - public String getServerAPIUrl() { - return serverAPIUrl; - } - public GHCommitState getUnstableAs() { return unstableAs; } @@ -603,19 +650,22 @@ public boolean isUseDetailedComments() { return (useDetailedComments != null && useDetailedComments); } - public GhprbGitHub getGitHub() { - if (gh == null) { - gh = new GhprbGitHub(); + public ListBoxModel doFillGitHubAuthIdItems(@QueryParameter("gitHubAuth") String gitHubAuthId) { + ListBoxModel model = new ListBoxModel(); + for (GhprbGitHubAuth auth : githubAuth) { + String description = Util.fixNull(auth.getDescription()); + int length = description.length(); + length = length > 15 ? 15 : length; + Option next = new Option(auth.getServerAPIUrl() + description.substring(0, length), auth.getId()); + if (!StringUtils.isEmpty(gitHubAuthId) && gitHubAuthId.equals(auth.getId())) { + next.selected = true; + } + model.add(next); } - return gh; + return model; } - @VisibleForTesting - void setGitHub(GhprbGitHub gh) { - this.gh = gh; - } - public ConcurrentMap getPullRequests(String projectName) { ConcurrentMap ret; if (jobs.containsKey(projectName)) { @@ -632,18 +682,6 @@ public ConcurrentMap getPullRequests(String projectNa return ret; } - public FormValidation doCreateApiToken(@QueryParameter("username") final String username, - @QueryParameter("password") final String password) { - try { - GitHub gh = GitHub.connectToEnterprise(this.serverAPIUrl, username, password); - GHAuthorization token = gh.createToken(Arrays.asList(GHAuthorization.REPO_STATUS, - GHAuthorization.REPO), "Jenkins GitHub Pull Request Builder", null); - return FormValidation.ok("Access token created: " + token.getToken()); - } catch (IOException ex) { - return FormValidation.error("GitHub API token couldn't be created: " + ex.getMessage()); - } - } - public List getWhiteListTargetBranches() { return whiteListTargetBranches; } @@ -659,6 +697,14 @@ public List getWhiteListTargetBranches() { private transient String msgFailure; @Deprecated private transient String commitStatusContext; + @Deprecated + private transient String accessToken; + @Deprecated + private transient String username; + @Deprecated + private transient String password; + @Deprecated + private transient String serverAPIUrl; public void readBackFromLegacy() { if (configVersion == null) { @@ -692,6 +738,29 @@ public void readBackFromLegacy() { commitStatusContext = null; } + if (!StringUtils.isEmpty(accessToken)) { + try { + GhprbGitHubAuth auth = new GhprbGitHubAuth(serverAPIUrl, Ghprb.createCredentials(serverAPIUrl, accessToken), "Pre credentials Token", null); + getGithubAuth().add(auth); + accessToken = null; + serverAPIUrl = null; + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (!StringUtils.isEmpty(username) || !StringUtils.isEmpty(password)) { + try { + GhprbGitHubAuth auth = new GhprbGitHubAuth(serverAPIUrl, Ghprb.createCredentials(serverAPIUrl, username, password), "Pre credentials username and password", null); + getGithubAuth().add(auth); + username = null; + password = null; + serverAPIUrl = null; + } catch (Exception e) { + e.printStackTrace(); + } + } + configVersion = 1; } @@ -704,4 +773,7 @@ private void addIfMissing(GhprbExtension ext) { } } + + + } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java index bf1aebec7..ab6a36bfb 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTriggerBackwardsCompatible.java @@ -49,7 +49,7 @@ protected void convertPropertiesToExtensions() { checkBuildStatusMessages(); checkCommitStatusContext(); - configVersion = 1; + configVersion = 2; } private void checkBuildStatusMessages() { diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java new file mode 100644 index 000000000..715529610 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbWebHook.java @@ -0,0 +1,72 @@ +package org.jenkinsci.plugins.ghprb; + +import java.io.IOException; +import java.io.StringReader; +import java.util.logging.Level; +import java.util.logging.Logger; + +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) { + + GhprbRepository repo = trigger.getRepository(); + + 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())) { + logger.log(Level.INFO, "Checking issue comment ''{0}'' for repo {1}", + new Object[] { issueComment.getComment(), repo.getName() } + ); + repo.onIssueCommentHook(issueComment); + } + + } else if ("pull_request".equals(event)) { + GHEventPayload.PullRequest pr = gh.parseEventPayload( + new StringReader(payload), + GHEventPayload.PullRequest.class); + if (matchRepo(repo, pr.getPullRequest().getRepository())) { + logger.log(Level.INFO, "Checking PR #{1} for {0}", new Object[] { repo.getName(), 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); + } + } + + private boolean matchRepo(GhprbRepository ghprbRepo, GHRepository ghRepo) { + return ghprbRepo.getName().equals(ghRepo.getFullName()); + } + + public String getProjectName() { + return trigger.getProject(); + } + +} 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 037313886..7a7aca3eb 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 @@ -49,20 +49,11 @@ public DescriptorImpl getDescriptor() { public static class DescriptorImpl extends GhprbExtensionDescriptor implements GhprbGlobalExtension, GhprbProjectExtension { - public final Class resultMessageClazz = GhprbBuildResultMessage.class; - public final GhprbBuildResultMessage.DescriptorImpl messageIt = new GhprbBuildResultMessage.DescriptorImpl(); - @Override public String getDisplayName() { return "Build Status Messages"; } - public List getBuildResultMessages() { - List list = new ArrayList(1); - list.add(new GhprbBuildResultMessage.DescriptorImpl()); - return list; - } - public List getMessageList(List messages) { List newMessages = new ArrayList(10); diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy new file mode 100644 index 000000000..9a5c57c7e --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth/config.groovy @@ -0,0 +1,49 @@ +package hudson.plugins.git.GhprbGitHubAuth; + +f = namespace(lib.FormTagLib) +c = namespace(lib.CredentialsTagLib) + +f.entry(title:_("GitHub Server API URL"), field:"serverAPIUrl") { + f.textbox() +} + +f.entry(title:_("Credentials"), field:"credentialsId") { + c.select(onchange="""{ + var self = this.targetElement ? this.targetElement : this; + var r = findPreviousFormItem(self,'serverAPIUrl'); + r.onchange(r); + self = null; + r = null; + }""" /* workaround for JENKINS-19124 */) +} + +f.advanced(title:_("Test Credentials")) { + f.entry(title:_("Test Credentials")) { + f.validateButton(title:_("Connect to API"), progress:_("Connecting..."), with:"credentialsId", method:"connectToAPI") + f.entry(title:_("Username temp"), field:"username") { + f.textbox() + } + f.entry(title:_("Password temp"), field:"password") { + f.password() + } + f.validateButton(title:_("Create Token"), progress:_("Creating..."), with:"serverAPIUrl,credentialsId,username,password", method:"createApiToken") + } +} + +f.entry(field: "description", title: _("Description")) { + f.textbox() +} + +f.advanced() { + f.entry(field: instance != null ? null : 'id', title: _("ID")) { + f.textbox(name: "_.id", value: instance != null ? instance.id : null, readonly: instance != null ? 'readonly' : null) + } +} + +f.entry { + div(align:"right") { + + input (type:"button", value:_("Add Server"), class:"repeatable-add show-if-last") + input (type:"button", value:_("Delete Server"), class:"repeatable-delete") + } +} diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/config.groovy b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/config.groovy new file mode 100644 index 000000000..cf7363a3a --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/config.groovy @@ -0,0 +1,66 @@ +// Namespaces +xml = namespace("http://www.w3.org/XML/1998/namespace") +j = namespace("jelly:core") +f = namespace("/lib/form") + +f.entry(field: "gitHubAuthId", title:_("GitHub API credentials")) { + f.select() +} + +f.entry(field: "adminlist", title: _("Admin list")) { + f.textarea(default: descriptor.adminlist) +} +f.entry(field: "useGitHubHooks", title: "Use github hooks for build triggering") { + f.checkbox() +} +f.advanced() { + f.entry(field: "triggerPhrase", title: _("Trigger phrase")) { + f.textbox() + } + f.entry(field: "onlyTriggerPhrase", title: "Only use trigger phrase for build triggering") { + f.checkbox() + } + f.entry(field: "autoCloseFailedPullRequests", title: _("Close failed pull request automatically?")) { + f.checkbox(default: descriptor.autoCloseFailedPullRequests) + } + f.entry(field: "skipBuildPhrase", title: _("Skip build phrase")) { + f.textarea(default: descriptor.skipBuildPhrase) + } + f.entry(field: "displayBuildErrorsOnDownstreamBuilds", title: _("Display build errors on downstream builds?")) { + f.checkbox(default: descriptor.displayBuildErrorsOnDownstreamBuilds) + } + f.entry(field: "cron", title: _("Crontab line"), help: "/descriptor/hudson.triggers.TimerTrigger/help/spec") { + f.textbox(default: descriptor.cron, checkUrl: "'descriptorByName/hudson.triggers.TimerTrigger/checkSpec?value=' + encodeURIComponent(this.value)") + } + f.entry(field: "whitelist", title: _("White list")) { + f.textarea() + } + f.entry(field: "orgslist", title: _("List of organizations. Their members will be whitelisted.")) { + f.textarea() + } + f.entry(field: "allowMembersOfWhitelistedOrgsAsAdmin", title: "Allow members of whitelisted organizations as admins") { + f.checkbox() + } + f.entry(field: "permitAll", title: "Build every pull request automatically without asking (Dangerous!).") { + f.checkbox() + } + f.entry(field: "whiteListTargetBranches", title: _("Whitelist Target Branches:")) { + f.repeatable(field: "whiteListTargetBranches", minimum: "1", add: "Add Branch") { + table(width: "100%") { + f.entry(field: "branch") { + f.textbox() + } + f.entry(title: "") { + div(align: "right") { + f.repeatableDeleteButton(value: "Delete Branch") + } + } + } + } + } +} +f.advanced(title: _("Trigger Setup")) { + f.entry(title: _("Trigger Setup")) { + f.hetero_list(items: instance.extensions, name: "extensions", oneEach: "true", hasHeader: "true", descriptors: descriptor.getExtensionDescriptors()) + } +} diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/config.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/config.jelly.tmp similarity index 100% rename from src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/config.jelly rename to src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/config.jelly.tmp diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.groovy b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.groovy new file mode 100644 index 000000000..6b6884dd5 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.groovy @@ -0,0 +1,52 @@ +// Namespaces +xml = namespace("http://www.w3.org/XML/1998/namespace") +j = namespace("jelly:core") +f = namespace("/lib/form") + + +f.section(title: descriptor.displayName) { + f.entry(field: "githubAuth", title: _("GitHub Auth")) { + f.repeatableProperty(field: "githubAuth", default: descriptor.getGithubAuth()) + } + f.entry(field: "useComments", title: _("Use comments to report results when updating commit status fails")) { + f.checkbox() + } + f.entry(field: "useDetailedComments", title: _("Use comments to report intermediate phases: triggered et al")) { + f.checkbox() + } + f.entry(field: "adminlist", title: _("Admin list")) { + f.textarea() + } + f.advanced() { + f.entry(field: "unstableAs", title: _("Mark Unstable build in github as")) { + f.select() + } + f.entry(field: "autoCloseFailedPullRequests", title: _("Close failed pull request automatically?")) { + f.checkbox() + } + f.entry(field: "displayBuildErrorsOnDownstreamBuilds", title: _("Display build errors on downstream builds?")) { + f.checkbox() + } + f.entry(field: "requestForTestingPhrase", title: _("Request for testing phrase")) { + f.textarea(default: "Can one of the admins verify this patch?") + } + f.entry(field: "whitelistPhrase", title: _("Add to white list phrase")) { + f.textbox(default: ".*add\\W+to\\W+whitelist.*") + } + f.entry(field: "okToTestPhrase", title: _("Accept to test phrase")) { + f.textbox(default: ".*ok\\W+to\\W+test.*") + } + f.entry(field: "retestPhrase", title: _("Test phrase")) { + f.textbox(default: ".*test\\W+this\\W+please.*") + } + f.entry(field: "skipBuildPhrase", title: _("Skip build phrase")) { + f.textbox(default: ".*\\[skip\\W+ci\\].*") + } + f.entry(field: "cron", title: _("Crontab line"), help: "/descriptor/hudson.triggers.TimerTrigger/help/spec") { + f.textbox(default: "H/5 * * * *", checkUrl: "'descriptorByName/hudson.triggers.TimerTrigger/checkSpec?value=' + encodeURIComponent(this.value)") + } + } + f.entry(title: _("Application Setup")) { + f.hetero_list(items: descriptor.extensions, name: "extensions", oneEach: "true", hasHeader: "true", descriptors: descriptor.getGlobalExtensionDescriptors()) + } +} diff --git a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.jelly b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.jelly.tmp similarity index 93% rename from src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.jelly rename to src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.jelly.tmp index 21bbccbfd..4f4c71578 100644 --- a/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ghprb/GhprbTrigger/global.jelly.tmp @@ -1,5 +1,8 @@ + + + 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 4ff36ae00..dcb6b0fe5 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/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java index e82bcab84..e79527e8d 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbIT.java @@ -5,7 +5,6 @@ import hudson.model.FreeStyleProject; import hudson.plugins.git.GitSCM; -import net.sf.json.JSONObject; import org.joda.time.DateTime; import org.junit.Before; @@ -15,6 +14,8 @@ import org.jvnet.hudson.test.JenkinsRule; import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GHIssueComment; +import org.kohsuke.stapler.RequestImpl; +import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import static com.google.common.collect.Lists.newArrayList; @@ -32,6 +33,9 @@ public class GhprbIT extends GhprbITBaseTestCase { @Rule public JenkinsRule jenkinsRule = new JenkinsRule(); + + @Mock + private RequestImpl req; @Before public void setUp() throws Exception { @@ -45,8 +49,7 @@ public void shouldBuildTriggersOnNewPR() throws Exception { FreeStyleProject project = jenkinsRule.createFreeStyleProject("PRJ"); GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); given(commitPointer.getSha()).willReturn("sha"); - JSONObject jsonObject = GhprbTestUtil.provideConfiguration(); - GhprbTrigger.getDscp().configure(null, jsonObject); + GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); given(ghPullRequest.getNumber()).willReturn(1); @@ -57,7 +60,6 @@ public void shouldBuildTriggersOnNewPR() throws Exception { // Configuring and adding Ghprb trigger project.addTrigger(trigger); - project.getTriggers().keySet().iterator().next().configure(null, jsonObject); // Configuring Git SCM GitSCM scm = GhprbTestUtil.provideGitSCM(); @@ -78,8 +80,7 @@ public void shouldBuildTriggersOnUpdatingNewCommitsPR() throws Exception { GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); given(commitPointer.getSha()).willReturn("sha").willReturn("sha").willReturn("newOne").willReturn("newOne"); given(ghPullRequest.getComments()).willReturn(Lists. newArrayList()); - JSONObject jsonObject = GhprbTestUtil.provideConfiguration(); - GhprbTrigger.getDscp().configure(null, jsonObject); + 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)); @@ -88,7 +89,6 @@ public void shouldBuildTriggersOnUpdatingNewCommitsPR() throws Exception { trigger.setHelper(ghprb); ghprb.getRepository().setHelper(ghprb); project.addTrigger(trigger); - project.getTriggers().keySet().iterator().next().configure(null, jsonObject); GitSCM scm = GhprbTestUtil.provideGitSCM(); project.setScm(scm); @@ -111,8 +111,7 @@ public void shouldBuildTriggersOnUpdatingRetestMessagePR() throws Exception { given(comment.getUser()).willReturn(ghUser); given(ghPullRequest.getComments()).willReturn(newArrayList(comment)); given(ghPullRequest.getNumber()).willReturn(5).willReturn(5); - JSONObject jsonObject = GhprbTestUtil.provideConfiguration(); - GhprbTrigger.getDscp().configure(null, jsonObject); + GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); Ghprb ghprb = spy(trigger.createGhprb(project)); @@ -121,7 +120,6 @@ public void shouldBuildTriggersOnUpdatingRetestMessagePR() throws Exception { trigger.setHelper(ghprb); ghprb.getRepository().setHelper(ghprb); project.addTrigger(trigger); - project.getTriggers().keySet().iterator().next().configure(null, jsonObject); GitSCM scm = GhprbTestUtil.provideGitSCM(); project.setScm(scm); @@ -144,8 +142,7 @@ public void shouldNotBuildDisabledBuild() throws Exception { given(comment.getUser()).willReturn(ghUser); given(ghPullRequest.getComments()).willReturn(newArrayList(comment)); given(ghPullRequest.getNumber()).willReturn(5); - JSONObject jsonObject = GhprbTestUtil.provideConfiguration(); - GhprbTrigger.getDscp().configure(null, jsonObject); + GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); Ghprb ghprb = spy(trigger.createGhprb(project)); @@ -154,7 +151,6 @@ public void shouldNotBuildDisabledBuild() throws Exception { trigger.setHelper(ghprb); ghprb.getRepository().setHelper(ghprb); project.addTrigger(trigger); - project.getTriggers().keySet().iterator().next().configure(null, jsonObject); GitSCM scm = GhprbTestUtil.provideGitSCM(); project.setScm(scm); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java index 74b665eaa..83e7dfc65 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbPullRequestMergeTest.java @@ -154,13 +154,14 @@ public void afterClass() { } + @SuppressWarnings("unchecked") private void setupConditions(String triggerLogin, String committerName, String comment) throws IOException { given(triggerSender.getLogin()).willReturn(triggerLogin); given(triggerSender.getName()).willReturn(committerName); given(committer.getName()).willReturn(this.committerName); PagedIterator itr = Mockito.mock(PagedIterator.class); - PagedIterable pagedItr = Mockito.mock(PagedIterable.class); + PagedIterable pagedItr = Mockito.mock(PagedIterable.class); Commit commit = mock(Commit.class); GHPullRequestCommitDetail commitDetail = mock(GHPullRequestCommitDetail.class); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java index 49e9ab38c..823c4b4a5 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbRootActionTest.java @@ -8,8 +8,6 @@ import java.io.InputStream; import java.io.InputStreamReader; -import net.sf.json.JSONObject; - import org.joda.time.DateTime; import org.junit.Before; import org.junit.Rule; @@ -87,17 +85,15 @@ public void setup() throws Exception { ghRateLimit.remaining = GhprbTestUtil.INITIAL_RATE_LIMIT; GhprbTestUtil.mockCommitList(ghPullRequest); - ghprbGitHub.setGitHub(gitHub); } @Test public void testUrlEncoded() throws Exception { // GIVEN FreeStyleProject project = jenkinsRule.createFreeStyleProject("testUrlEncoded"); - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); + GhprbTrigger trigger = spy(GhprbTestUtil.getTrigger(null)); given(commitPointer.getSha()).willReturn("sha1"); - JSONObject jsonObject = GhprbTestUtil.provideConfiguration(); - GhprbTrigger.getDscp().configure(null, jsonObject); + GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); given(ghPullRequest.getNumber()).willReturn(1); Ghprb ghprb = spy(trigger.createGhprb(project)); @@ -106,16 +102,14 @@ public void testUrlEncoded() throws Exception { trigger.setHelper(ghprb); ghprb.getRepository().setHelper(ghprb); project.addTrigger(trigger); - project.getTriggers().keySet().iterator().next().configure(null, jsonObject); GitSCM scm = GhprbTestUtil.provideGitSCM(); project.setScm(scm); GhprbTestUtil.triggerRunAndWait(10, trigger, project); assertThat(project.getBuilds().toArray().length).isEqualTo(1); - - GhprbTrigger.getDscp().setGitHub(ghprbGitHub); - doReturn(gitHub).when(ghprbGitHub).get(); + + doReturn(gitHub).when(trigger).getGitHub(); given(req.getContentType()).willReturn("application/x-www-form-urlencoded"); given(req.getParameter("payload")).willReturn(payload); @@ -132,10 +126,9 @@ public void testUrlEncoded() throws Exception { public void disabledJobsDontBuild() throws Exception { // GIVEN FreeStyleProject project = jenkinsRule.createFreeStyleProject("disabledJobsDontBuild"); - GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); + GhprbTrigger trigger = spy(GhprbTestUtil.getTrigger(null)); given(commitPointer.getSha()).willReturn("sha1"); - JSONObject jsonObject = GhprbTestUtil.provideConfiguration(); - GhprbTrigger.getDscp().configure(null, jsonObject); + GhprbTestUtil.setupGhprbTriggerDescriptor(null); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); given(ghPullRequest.getNumber()).willReturn(1); Ghprb ghprb = spy(trigger.createGhprb(project)); @@ -144,7 +137,6 @@ public void disabledJobsDontBuild() throws Exception { trigger.setHelper(ghprb); ghprb.getRepository().setHelper(ghprb); project.addTrigger(trigger); - project.getTriggers().keySet().iterator().next().configure(null, jsonObject); GitSCM scm = GhprbTestUtil.provideGitSCM(); project.setScm(scm); @@ -154,8 +146,7 @@ public void disabledJobsDontBuild() throws Exception { project.disable(); - GhprbTrigger.getDscp().setGitHub(ghprbGitHub); - doReturn(gitHub).when(ghprbGitHub).get(); + doReturn(gitHub).when(trigger).getGitHub(); given(req.getContentType()).willReturn("application/x-www-form-urlencoded"); given(req.getParameter("payload")).willReturn(payload); diff --git a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java index 611cad4ec..dbd3437c7 100644 --- a/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java +++ b/src/test/java/org/jenkinsci/plugins/ghprb/GhprbTestUtil.java @@ -19,28 +19,32 @@ import java.net.URL; import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.Map.Entry; -import org.jenkinsci.plugins.ghprb.extensions.GhprbExtension; import org.joda.time.DateTime; import org.kohsuke.github.GHCommitPointer; import org.kohsuke.github.GHPullRequest; import org.kohsuke.github.PagedIterable; import org.kohsuke.github.PagedIterator; +import org.kohsuke.stapler.BindInterceptor; +import org.kohsuke.stapler.RequestImpl; +import org.mockito.Mock; import org.mockito.Mockito; -import antlr.ANTLRException; import hudson.model.AbstractProject; import hudson.plugins.git.BranchSpec; import hudson.plugins.git.GitSCM; import hudson.plugins.git.UserRemoteConfig; import net.sf.json.JSONObject; +import static org.mockito.Matchers.any; public class GhprbTestUtil { public static final int INITIAL_RATE_LIMIT = 5000; public static final String GHPRB_PLUGIN_NAME = "ghprb"; + + private static RequestImpl req; @SuppressWarnings({ "rawtypes", "unchecked" }) public static void mockCommitList(GHPullRequest ghPullRequest) { @@ -70,8 +74,28 @@ public static void mockPR(GHPullRequest prToMock, GHCommitPointer commitPointer, given(prToMock.getUpdatedAt()).willReturn(updatedDate[0].toDate()); } } + + private static final String apiUrl = "https://api.github.com"; + + private static String setUpCredentials() throws Exception { + String credentialsId = Ghprb.createCredentials(apiUrl, "accessToken"); + return credentialsId; + } + + private static String credentialsId; + + private static String getCredentialsId() throws Exception { + if (credentialsId == null) { + credentialsId = setUpCredentials(); + } + return credentialsId; + } - public static JSONObject provideConfiguration() { + public static void setupGhprbTriggerDescriptor(Map config) throws Exception { + setupReq(); + if (config == null) { + config = new HashMap(); + } JSONObject jsonObject = new JSONObject(); jsonObject.put("serverAPIUrl", "https://api.github.com"); @@ -80,7 +104,7 @@ public static JSONObject provideConfiguration() { jsonObject.put("accessToken", "accessToken"); jsonObject.put("adminlist", "user"); jsonObject.put("allowMembersOfWhitelistedOrgsAsAdmin", "false"); - jsonObject.put("publishedURL", ""); + jsonObject.put("publishedURL", "defaultPublishedURL"); jsonObject.put("requestForTestingPhrase", "test this"); jsonObject.put("whitelistPhrase", ""); jsonObject.put("okToTestPhrase", "ok to test"); @@ -97,10 +121,33 @@ public static JSONObject provideConfiguration() { jsonObject.put("msgSuccess", "Success"); jsonObject.put("msgFailure", "Failure"); jsonObject.put("commitStatusContext", "Status Context"); + + JSONObject githubAuth = new JSONObject(); + githubAuth.put("credentialsId", getCredentialsId()); + githubAuth.put("serverAPIUrl", apiUrl); + + jsonObject.put("githubAuth", githubAuth); + - return jsonObject; + for ( Entry next: config.entrySet()) { + jsonObject.put(next.getKey(), next.getValue()); + } + + + GhprbTrigger.getDscp().configure(req, jsonObject); + } + + @SuppressWarnings("unchecked") + private static void setupReq() { + req = Mockito.mock(RequestImpl.class); + given(req.bindJSON(any(Class.class), any(JSONObject.class))).willCallRealMethod(); + given(req.bindJSON(any(Class.class), any(Class.class), any(JSONObject.class))).willCallRealMethod(); + given(req.setBindListener(any(BindInterceptor.class))).willCallRealMethod(); + req.setBindListener(BindInterceptor.NOOP); + } + public static GitSCM provideGitSCM() { return new GitSCM(newArrayList( new UserRemoteConfig("https://github.com/user/dropwizard", @@ -113,53 +160,31 @@ public static GitSCM provideGitSCM() { null); } - @SuppressWarnings("unchecked") - public static GhprbTrigger getTrigger(Map values) throws ANTLRException { + public static GhprbTrigger getTrigger(Map values) throws Exception { + setupReq(); if (values == null) { values = new HashMap(); } - Map defaultValues = new HashMap (){ - private static final long serialVersionUID = -6720840565156773837L; - - { - put("adminlist", "user"); - put("whitelist", "user"); - put("orgslist", ""); - put("cron", "0 0 31 2 0"); - put("triggerPhrase", "retest this please"); - put("onlyTriggerPhrase", false); - put("useGitHubHooks", false); - put("permitAll", false); - put("autoCloseFailedPullRequests", false); - put("displayBuildErrorsOnDownstreamBuilds", false); - put("commentFilePath", null); - put("whiteListTargetBranches", null); - put("allowMembersOfWhitelistedOrgsAsAdmin", false); - put("msgSuccess", null); - put("msgFailure", null); - put("commitStatusContext", null); - put("extensions", null); - }}; + JSONObject defaults = new JSONObject(); + defaults.put("adminlist", "user"); + defaults.put("whitelist", "user"); + defaults.put("orgslist", ""); + defaults.put("cron", "0 0 31 2 0"); + defaults.put("triggerPhrase", "retest this please"); + defaults.put("onlyTriggerPhrase", false); + defaults.put("useGitHubHooks", false); + defaults.put("permitAll", false); + defaults.put("autoCloseFailedPullRequests", false); + defaults.put("displayBuildErrorsOnDownstreamBuilds", false); + defaults.put("allowMembersOfWhitelistedOrgsAsAdmin", false); + defaults.put("gitHubApi", "https://api.github.com"); + + for ( Entry next: values.entrySet()) { + defaults.put(next.getKey(), next.getValue()); + } + + GhprbTrigger trigger = req.bindJSON(GhprbTrigger.class, defaults); - defaultValues.putAll(values); - GhprbTrigger trigger = new GhprbTrigger( - (String)defaultValues.get("adminlist"), - (String)defaultValues.get("whitelist"), - (String)defaultValues.get("orgslist"), - (String)defaultValues.get("cron"), - (String)defaultValues.get("triggerPhrase"), - (Boolean)defaultValues.get("onlyTriggerPhrase"), - (Boolean)defaultValues.get("useGitHubHooks"), - (Boolean)defaultValues.get("permitAll"), - (Boolean)defaultValues.get("autoCloseFailedPullRequests"), - (Boolean)defaultValues.get("displayBuildErrorsOnDownstreamBuilds"), - (String)defaultValues.get("commentFilePath"), - (List)defaultValues.get("whiteListTargetBranches"), - (Boolean)defaultValues.get("allowMembersOfWhitelistedOrgsAsAdmin"), - (String)defaultValues.get("msgSuccess"), - (String)defaultValues.get("msgFailure"), - (String)defaultValues.get("commitStatusContext"), - (List)defaultValues.get("extensions")); return trigger; } @@ -169,7 +194,6 @@ public static void waitForBuildsToFinish(AbstractProject project) throws I Thread.sleep(500); } } - public static void triggerRunAndWait(int numOfTriggers, GhprbTrigger trigger, AbstractProject project) throws InterruptedException { for (int i = 0; i < numOfTriggers; ++i) { 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 a57435e03..fd9120d1a 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 @@ -8,7 +8,6 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; 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 e74ee8213..3045eb833 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 @@ -1,30 +1,28 @@ package org.jenkinsci.plugins.ghprb.manager.impl; 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 net.sf.json.JSONObject; - 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; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.jvnet.hudson.test.JenkinsRule; - import org.mockito.runners.MockitoJUnitRunner; /** @@ -65,11 +63,12 @@ private MatrixProject givenThatGhprbHasBeenTriggeredForAMatrixProject() throws E GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); given(commitPointer.getSha()).willReturn("sha"); + + Map config = new HashMap(1); + config.put("publishedURL", "defaultPublishedURL"); - JSONObject jsonObject = GhprbTestUtil.provideConfiguration(); + GhprbTestUtil.setupGhprbTriggerDescriptor(config); - jsonObject.put("publishedURL", "defaultPublishedURL"); - GhprbTrigger.DESCRIPTOR.configure(null, jsonObject); project.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); @@ -87,8 +86,6 @@ private MatrixProject givenThatGhprbHasBeenTriggeredForAMatrixProject() throws E // Configuring and adding Ghprb trigger project.addTrigger(trigger); - project.getTriggers().keySet().iterator().next().configure(null, jsonObject); - // Configuring Git SCM project.setScm(GhprbTestUtil.provideGitSCM()); 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 4673ff307..99810ca93 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 @@ -12,8 +12,6 @@ import java.util.Iterator; -import net.sf.json.JSONObject; - import org.jenkinsci.plugins.ghprb.Ghprb; import org.jenkinsci.plugins.ghprb.GhprbITBaseTestCase; import org.jenkinsci.plugins.ghprb.GhprbTestUtil; @@ -107,9 +105,7 @@ private BuildFlow givenThatGhprbHasBeenTriggeredForABuildFlowProject() throws Ex GhprbTrigger trigger = GhprbTestUtil.getTrigger(null); given(commitPointer.getSha()).willReturn("sha"); - JSONObject jsonObject = GhprbTestUtil.provideConfiguration(); - - GhprbTrigger.DESCRIPTOR.configure(null, jsonObject); + GhprbTestUtil.setupGhprbTriggerDescriptor(null); buildFlowProject.addProperty(new GithubProjectProperty("https://github.com/user/dropwizard")); @@ -127,8 +123,6 @@ private BuildFlow givenThatGhprbHasBeenTriggeredForABuildFlowProject() throws Ex // Configuring and adding Ghprb trigger buildFlowProject.addTrigger(trigger); - buildFlowProject.getTriggers().keySet().iterator().next().configure(null, jsonObject); - // Configuring Git SCM buildFlowProject.setScm(GhprbTestUtil.provideGitSCM()); From 2a78c94a8ab4c95e8bf8199c587289914099301f Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 3 Jun 2015 15:51:21 -0600 Subject: [PATCH 04/11] Fix null pointer when ghRepository may not have been initialized. Addresses https://github.com/janinko/ghprb/issues/281 --- .../jenkinsci/plugins/ghprb/GhprbRepository.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 8e0d5061b..9ae8a71c2 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -189,7 +189,7 @@ public void addComment(int id, String comment, AbstractBuild build, TaskLi } try { - ghRepository.getPullRequest(id).comment(comment); + getGitHubRepo().getPullRequest(id).comment(comment); } catch (IOException ex) { logger.log(Level.SEVERE, "Couldn't add comment to pull request #" + id + ": '" + comment + "'", ex); } @@ -197,13 +197,14 @@ public void addComment(int id, String comment, AbstractBuild build, TaskLi public void closePullRequest(int id) { try { - ghRepository.getPullRequest(id).close(); + getGitHubRepo().getPullRequest(id).close(); } catch (IOException ex) { logger.log(Level.SEVERE, "Couldn't close the pull request #" + id + ": '", ex); } } private boolean hookExist() throws IOException { + GHRepository ghRepository = getGitHubRepo(); for (GHHook h : ghRepository.getHooks()) { if (!"web".equals(h.getName())) { continue; @@ -241,7 +242,7 @@ private static String getHookUrl() { } public GHPullRequest getPullRequest(int id) throws IOException { - return ghRepository.getPullRequest(id); + return getGitHubRepo().getPullRequest(id); } void onIssueCommentHook(IssueComment issueComment) throws IOException { @@ -255,13 +256,9 @@ void onIssueCommentHook(IssueComment issueComment) throws IOException { return; } - if (ghRepository == null) { - init(); - } - GhprbPullRequest pull = pulls.get(id); if (pull == null) { - pull = new GhprbPullRequest(ghRepository.getPullRequest(id), helper, this); + pull = new GhprbPullRequest(getGitHubRepo().getPullRequest(id), helper, this); pulls.put(id, pull); } pull.check(issueComment.getComment()); @@ -303,6 +300,9 @@ void setHelper(Ghprb helper) { } public GHRepository getGitHubRepo() { + if (ghRepository == null) { + init(); + } return ghRepository; } } \ No newline at end of file From 20d15f2602b2ab9c7c361f68d31c233fc06ab26e Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 3 Jun 2015 15:55:06 -0600 Subject: [PATCH 05/11] [maven-release-plugin] prepare release ghprb-1.22.4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 39dd9633c..b8e278d17 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.23-SNAPSHOT + 1.22.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.22.4 From e0522dbae2fe4d3de5f63f8c3ffa2dfbd2a2d542 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 3 Jun 2015 15:55:10 -0600 Subject: [PATCH 06/11] [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 b8e278d17..39dd9633c 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.22.4 + 1.23-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.22.4 + HEAD From 4102806fa37176304c7686663b31650bb0a12701 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 3 Jun 2015 20:17:05 -0600 Subject: [PATCH 07/11] Update readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 9b993db3c..8ee08d7c6 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,12 @@ If you want to manually build the job, in the job setting check ``This build is ### Updates +#### -> 1.22.x +* Fix issue where if a project was disabled the Jenkins Trigger process would crash +* Fix commit status context +* Add one line test results for downstream builds +* Miscellaneous bug fixes + #### -> 1.22 * Move commit status over to extension form. It is now configurable, satisfying #81, #73, and #19 at least. From ba96d0c31ae90bb5bca0c8ceeaed7ce1a68ffac1 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 3 Jun 2015 20:30:22 -0600 Subject: [PATCH 08/11] Add test encoding --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 44ce75260..56bcd0649 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ UTF-8 + UTF-8 From 7813810d2d026b332ca74efeb1ab14de4f54aeaf Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 12 Jun 2015 10:48:55 -0600 Subject: [PATCH 09/11] Fix conversion process GitHub auth list initialized with just one value. Update how auth items are listed for each job. --- .../plugins/ghprb/GhprbGitHubAuth.java | 38 +++++++++---------- .../plugins/ghprb/GhprbPullRequest.java | 1 - .../plugins/ghprb/GhprbRepository.java | 4 ++ .../plugins/ghprb/GhprbRootAction.java | 4 -- .../jenkinsci/plugins/ghprb/GhprbTrigger.java | 19 ++++++---- 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java index 6883a97bf..ec16b8025 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbGitHubAuth.java @@ -93,28 +93,26 @@ public String getId() { public GitHub getConnection(Item context) throws IOException { GitHub gh = null; - - if (credentialsId == null) { - return GitHub.connectAnonymously(); - } - GitHubBuilder builder = new GitHubBuilder() - .withEndpoint(serverAPIUrl) - .withConnector(new HttpConnectorWithJenkinsProxy()); - StandardCredentials credentials = CredentialsMatchers - .firstOrNull( - CredentialsProvider.lookupCredentials(StandardCredentials.class, context, - ACL.SYSTEM, URIRequirementBuilder.fromUri(serverAPIUrl).build()), - CredentialsMatchers.allOf(CredentialsMatchers.withId(credentialsId))); + .withEndpoint(serverAPIUrl) + .withConnector(new HttpConnectorWithJenkinsProxy()); - if (credentials instanceof StringCredentials) { - String accessToken = ((StringCredentials) credentials).getSecret().getPlainText(); - builder.withOAuthToken(accessToken); - } else if (credentials instanceof UsernamePasswordCredentials){ - UsernamePasswordCredentials creds = (UsernamePasswordCredentials) credentials; - String username = creds.getUsername(); - String password = creds.getPassword().getPlainText(); - builder.withPassword(username, password); + if (!StringUtils.isEmpty(credentialsId)) { + StandardCredentials credentials = CredentialsMatchers + .firstOrNull( + CredentialsProvider.lookupCredentials(StandardCredentials.class, context, + ACL.SYSTEM, URIRequirementBuilder.fromUri(serverAPIUrl).build()), + CredentialsMatchers.allOf(CredentialsMatchers.withId(credentialsId))); + + if (credentials instanceof StringCredentials) { + String accessToken = ((StringCredentials) credentials).getSecret().getPlainText(); + builder.withOAuthToken(accessToken); + } else if (credentials instanceof UsernamePasswordCredentials){ + UsernamePasswordCredentials creds = (UsernamePasswordCredentials) credentials; + String username = creds.getUsername(); + String password = creds.getPassword().getPlainText(); + builder.withPassword(username, password); + } } try { gh = builder.build(); diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java index 388771d62..e6bdc9352 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbPullRequest.java @@ -3,7 +3,6 @@ import com.google.common.base.Joiner; import org.apache.commons.lang.StringUtils; -import org.kohsuke.github.GHCommitState; import org.kohsuke.github.GHIssue; import org.kohsuke.github.GHIssueComment; import org.kohsuke.github.GHPullRequest; diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java index 8ba3c8396..38239fd6b 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRepository.java @@ -59,6 +59,10 @@ private boolean initGhRepository() { 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) { return false; } diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java index 0579474be..c59f77e87 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbRootAction.java @@ -10,15 +10,11 @@ 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.GHRepository; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import java.io.BufferedReader; import java.io.IOException; -import java.io.StringReader; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; diff --git a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java index 1a8737e22..66dfe7adc 100644 --- a/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java @@ -185,6 +185,7 @@ public void stop() { public void run() { // triggers are always triggered on the cron, but we just no-op if we are using GitHub hooks. if (getUseGitHubHooks()) { + logger.log(Level.FINE, "Use webHooks is set, so not running trigger"); return; } @@ -528,6 +529,7 @@ public DescriptorImpl() { if (jobs == null) { jobs = new HashMap>(); } +// save(); } @Override @@ -656,8 +658,8 @@ public ListBoxModel doFillGitHubAuthIdItems(@QueryParameter("gitHubAuth") String for (GhprbGitHubAuth auth : githubAuth) { String description = Util.fixNull(auth.getDescription()); int length = description.length(); - length = length > 15 ? 15 : length; - Option next = new Option(auth.getServerAPIUrl() + description.substring(0, length), auth.getId()); + length = length > 50 ? 50 : length; + Option next = new Option(auth.getServerAPIUrl() + " : " + description.substring(0, length), auth.getId()); if (!StringUtils.isEmpty(gitHubAuthId) && gitHubAuthId.equals(auth.getId())) { next.selected = true; } @@ -742,7 +744,10 @@ public void readBackFromLegacy() { if (!StringUtils.isEmpty(accessToken)) { try { GhprbGitHubAuth auth = new GhprbGitHubAuth(serverAPIUrl, Ghprb.createCredentials(serverAPIUrl, accessToken), "Pre credentials Token", null); - getGithubAuth().add(auth); + if (githubAuth == null) { + githubAuth = new ArrayList(1); + } + githubAuth.add(auth); accessToken = null; serverAPIUrl = null; } catch (Exception e) { @@ -753,7 +758,10 @@ 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); - getGithubAuth().add(auth); + if (githubAuth == null) { + githubAuth = new ArrayList(1); + } + githubAuth.add(auth); username = null; password = null; serverAPIUrl = null; @@ -762,7 +770,6 @@ public void readBackFromLegacy() { } } - configVersion = 1; } @@ -775,6 +782,4 @@ private void addIfMissing(GhprbExtension ext) { } - - } From b6b3766ea51cf9edcbaf2122536c7f2f06e878f6 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 12 Jun 2015 11:26:54 -0600 Subject: [PATCH 10/11] [maven-release-plugin] prepare release ghprb-1.23 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 56bcd0649..16f211f8c 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.23-SNAPSHOT + 1.23 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.23 From 2ffd677fb76141b132b30653b887268944544b20 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Fri, 12 Jun 2015 11:26:56 -0600 Subject: [PATCH 11/11] [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 16f211f8c..20e22118e 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ghprb GitHub Pull Request Builder - 1.23 + 1.24-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.23 + HEAD