From 621795c8fe439fed631e4431b46bb01f81d09a57 Mon Sep 17 00:00:00 2001 From: Aaron Whiteside Date: Sat, 26 Jan 2019 21:31:33 +1100 Subject: [PATCH 1/4] Improve support for getting and setting a PRs milestone ExtendedGitHubClient.java ExtendedPullRequestService.java - expanded the UncheckedIOException love to more places. ExtendedIssueService.java - added a method to set an issues milestone ExtendedMilestone.java ExtendedMilestoneService.java - added to support updatedAt and closedAt fields MilestoneGroovyObject.java - wrapper over ExtendedMilestone PullRequestGroovyObject.java - getMilestone() now return MilestoneGroovyObject - setMilestone() is now @Whitelisted - overloaded setMilestone to take both int and MilestoneGroovyObject - cleaned up some IOException uglyness --- README.md | 23 ++++- .../github/MilestoneGroovyObject.java | 86 +++++++++++++++++++ .../github/PullRequestGroovyObject.java | 60 +++++++------ .../github/client/ExtendedGitHubClient.java | 29 +++++-- .../github/client/ExtendedIssueService.java | 13 +++ .../github/client/ExtendedMilestone.java | 31 +++++++ .../client/ExtendedMilestoneService.java | 48 +++++++++++ .../client/ExtendedPullRequestService.java | 2 +- 8 files changed, 256 insertions(+), 36 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/pipeline/github/MilestoneGroovyObject.java create mode 100644 src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestone.java create mode 100644 src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestoneService.java diff --git a/README.md b/README.md index 2044baf..500f496 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ issueUrl | `String` | false title | `String` | **true** body | `String` | **true** locked | `Boolean` | **true** | Accepts `true`, `false` or `'true'`, `'false'` -milestone | `Integer` | **true** +milestone | `Milestone` | **true** | Setter accepts int or Milestone class. head | `String` | false | Revision (SHA) of the head commit of this pull request headRef | `String` | false | Name of the branch this pull request is created for base | `String` | **true** | Name of the base branch in the current repository this pull request targets @@ -364,6 +364,27 @@ state | `String` | One of APPROVED, PENDING, CHANGES_REQUESTED, DISMISSED, COMME ### Methods None. +## Milestone +### Properties +Name | Type | Setter | Description +-----|------|----------|------------ +number | `Integer` | false +createdAt | `Date` | false +dueOn | `Date` | false +updatedAt | `Date` | false +closedAt | `Date` | false +closedIssues | `Integer` | false +openIssues | `Integer` | false +description | `String` | false +state | `String` | false +title | `String` | false +url | `String` | false +creator | `String` | false + +### Methods +None. + + # Examples ## Pull Requests diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/MilestoneGroovyObject.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/MilestoneGroovyObject.java new file mode 100644 index 0000000..420437d --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/MilestoneGroovyObject.java @@ -0,0 +1,86 @@ +package org.jenkinsci.plugins.pipeline.github; + +import groovy.lang.GroovyObjectSupport; +import org.eclipse.egit.github.core.Milestone; +import org.jenkinsci.plugins.pipeline.github.client.ExtendedMilestone; +import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted; + +import java.io.Serializable; +import java.util.Date; + +/** + * Groovy wrapper over {@link Milestone} + * + * @author Aaron Whiteside + * @see Milestone + */ +public class MilestoneGroovyObject extends GroovyObjectSupport implements Serializable { + private static final long serialVersionUID = 1L; + + private final ExtendedMilestone milestone; + + MilestoneGroovyObject(final ExtendedMilestone milestone) { + this.milestone = milestone; + } + + @Whitelisted + public Date getCreatedAt() { + return milestone.getCreatedAt(); + } + + @Whitelisted + public Date getDueOn() { + return milestone.getDueOn(); + } + + @Whitelisted + public int getClosedIssues() { + return milestone.getClosedIssues(); + } + + @Whitelisted + public int getNumber() { + return milestone.getNumber(); + } + + @Whitelisted + public int getOpenIssues() { + return milestone.getOpenIssues(); + } + + @Whitelisted + public String getDescription() { + return milestone.getDescription(); + } + + @Whitelisted + public String getState() { + return milestone.getState(); + } + + @Whitelisted + public String getTitle() { + return milestone.getTitle(); + } + + @Whitelisted + public String getUrl() { + return milestone.getUrl(); + } + + @Whitelisted + public String getCreator() { + return milestone.getCreator().getLogin(); + } + + @Whitelisted + public Date getUpdatedAt() { + return milestone.getUpdatedAt(); + } + + @Whitelisted + public Date getClosedAt() { + return milestone.getClosedAt(); + } + +} diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/PullRequestGroovyObject.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/PullRequestGroovyObject.java index a79bba1..45e75fb 100644 --- a/src/main/java/org/jenkinsci/plugins/pipeline/github/PullRequestGroovyObject.java +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/PullRequestGroovyObject.java @@ -7,6 +7,7 @@ import org.eclipse.egit.github.core.Comment; import org.eclipse.egit.github.core.CommitStatus; import org.eclipse.egit.github.core.Label; +import org.eclipse.egit.github.core.Milestone; import org.eclipse.egit.github.core.PullRequestMarker; import org.eclipse.egit.github.core.RepositoryId; import org.eclipse.egit.github.core.User; @@ -16,6 +17,7 @@ import org.jenkinsci.plugins.pipeline.github.client.ExtendedGitHubClient; import org.jenkinsci.plugins.pipeline.github.client.ExtendedIssueService; import org.jenkinsci.plugins.pipeline.github.client.ExtendedMergeStatus; +import org.jenkinsci.plugins.pipeline.github.client.ExtendedMilestoneService; import org.jenkinsci.plugins.pipeline.github.client.ExtendedPullRequest; import org.jenkinsci.plugins.pipeline.github.client.ExtendedPullRequestService; import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted; @@ -61,6 +63,7 @@ public class PullRequestGroovyObject extends GroovyObjectSupport implements Seri private final ExtendedPullRequestService pullRequestService; private final ExtendedIssueService issueService; private final ExtendedCommitService commitService; + private final ExtendedMilestoneService milestoneService; private ExtendedPullRequest pullRequest; PullRequestGroovyObject(@Nonnull final CpsScript script) throws Exception { @@ -79,6 +82,7 @@ public class PullRequestGroovyObject extends GroovyObjectSupport implements Seri this.pullRequestService = new ExtendedPullRequestService(gitHubClient); this.issueService = new ExtendedIssueService(gitHubClient); this.commitService = new ExtendedCommitService(gitHubClient); + this.milestoneService = new ExtendedMilestoneService(gitHubClient); this.pullRequest = pullRequestService.getPullRequest(base, pullRequestHead.getNumber()); } @@ -133,8 +137,12 @@ public boolean isLocked() { } @Whitelisted - public int getMilestone() { - return pullRequest.getMilestone().getNumber(); + public MilestoneGroovyObject getMilestone() { + return Optional.ofNullable(pullRequest.getMilestone()) + .map(Milestone::getNumber) + .map(m -> milestoneService.getMilestone(base, m)) + .map(MilestoneGroovyObject::new) + .orElse(null); } @Whitelisted @@ -335,8 +343,24 @@ public Iterable getFiles() { } } + @Whitelisted public void setMilestone(final int milestoneNumber) { - // todo + pullRequest.setMilestone( + issueService.setMilestone(base, pullRequest.getNumber(), milestoneNumber) + .getMilestone()); + } + + @Whitelisted + public void setMilestone(final MilestoneGroovyObject milestone) { + if (milestone == null) { + // call setMilestone because the caller might not have the right permissions to remove + // the milestone and it'll return the current milestone. + pullRequest.setMilestone( + issueService.setMilestone(base, pullRequest.getNumber(), null) + .getMilestone()); + } else { + setMilestone(milestone.getNumber()); + } } @Whitelisted @@ -359,11 +383,7 @@ public void setTitle(final String title) { ExtendedPullRequest edit = new ExtendedPullRequest(); edit.setNumber(pullRequest.getNumber()); edit.setTitle(title); - try { - pullRequest = pullRequestService.editPullRequest(base, edit); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } + pullRequest = pullRequestService.editPullRequest(base, edit); } @Whitelisted @@ -373,11 +393,7 @@ public void setBody(final String body) { ExtendedPullRequest edit = new ExtendedPullRequest(); edit.setNumber(pullRequest.getNumber()); edit.setBody(body); - try { - pullRequest = pullRequestService.editPullRequest(base, edit); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } + pullRequest = pullRequestService.editPullRequest(base, edit); } @Whitelisted @@ -387,11 +403,7 @@ public void setState(final String state) { ExtendedPullRequest edit = new ExtendedPullRequest(); edit.setNumber(pullRequest.getNumber()); edit.setState(state); - try { - pullRequest = pullRequestService.editPullRequest(base, edit); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } + pullRequest = pullRequestService.editPullRequest(base, edit); } @Whitelisted @@ -401,11 +413,7 @@ public void setBase(final String newBase) { ExtendedPullRequest edit = new ExtendedPullRequest(); edit.setNumber(pullRequest.getNumber()); edit.setBase(new PullRequestMarker().setRef(newBase)); - try { - pullRequest = pullRequestService.editPullRequest(base, edit); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } + pullRequest = pullRequestService.editPullRequest(base, edit); } @Whitelisted @@ -413,11 +421,7 @@ public void setMaintainerCanModify(final boolean value) { ExtendedPullRequest edit = new ExtendedPullRequest(); edit.setNumber(pullRequest.getNumber()); edit.setMaintainerCanModify(value); - try { - pullRequest = pullRequestService.editPullRequest(base, edit); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } + pullRequest = pullRequestService.editPullRequest(base, edit); } @Whitelisted diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedGitHubClient.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedGitHubClient.java index 7fb3cc8..8d23a73 100644 --- a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedGitHubClient.java +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedGitHubClient.java @@ -1,9 +1,12 @@ package org.jenkinsci.plugins.pipeline.github.client; import org.eclipse.egit.github.core.client.GitHubClient; +import org.eclipse.egit.github.core.client.GitHubRequest; +import org.eclipse.egit.github.core.client.GitHubResponse; import org.eclipse.egit.github.core.client.RequestException; import java.io.IOException; +import java.io.UncheckedIOException; import java.lang.reflect.Type; import java.net.HttpURLConnection; @@ -23,16 +26,20 @@ public ExtendedGitHubClient(final String hostname, final int port, final String super(hostname, port, scheme); } - public V patch(final String uri, final Object params, final Type type) throws IOException { + public V patch(final String uri, final Object params, final Type type) { return patch(uri, params, type, null); } - public V patch(final String uri, final Object params, final Type type, final String accept) throws IOException { - HttpURLConnection request = this.createPatch(uri); - if (accept != null) { - request.setRequestProperty("Accept", accept); + public V patch(final String uri, final Object params, final Type type, final String accept) { + try { + final HttpURLConnection request = createPatch(uri); + if (accept != null) { + request.setRequestProperty("Accept", accept); + } + return this.sendJson(request, params, type); + } catch (final IOException e) { + throw new UncheckedIOException(e); } - return this.sendJson(request, params, type); } protected HttpURLConnection createPatch(final String uri) throws IOException { @@ -84,4 +91,14 @@ private V sendJson(final HttpURLConnection request, final Object params, fin throw this.createException(this.getStream(request), code, request.getResponseMessage()); } } + + // UncheckedIOException version of get(GitHubRequest) + public GitHubResponse getUnchecked(final GitHubRequest request) { + try { + return get(request); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + } diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedIssueService.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedIssueService.java index 1fd8d9c..47ca6a1 100644 --- a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedIssueService.java +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedIssueService.java @@ -75,6 +75,19 @@ public void removeAssignees(final IRepositoryIdProvider repository, getClient().delete(uri.toString(), params); } + public Issue setMilestone(final IRepositoryIdProvider repository, + final int issueNumber, + final Integer milestoneNumber) { + String repoId = this.getId(repository); + StringBuilder uri = new StringBuilder("/repos"); + uri.append('/').append(repoId); + uri.append("/issues"); + uri.append('/').append(issueNumber); + Map params = new HashMap<>(1, 1.0F); + params.put("milestone", milestoneNumber); + return getClient().patch(uri.toString(), params, Issue.class); + } + public void setAssignees(final IRepositoryIdProvider repository, final int issueNumber, final List assignees) throws IOException { diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestone.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestone.java new file mode 100644 index 0000000..a5b13c5 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestone.java @@ -0,0 +1,31 @@ +package org.jenkinsci.plugins.pipeline.github.client; + +import org.eclipse.egit.github.core.Milestone; + +import java.util.Date; + +/** + * @author Aaron Whiteside + */ +public class ExtendedMilestone extends Milestone { + private static final long serialVersionUID = 8017385076255266092L; + + private Date updatedAt; + private Date closedAt; + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public Date getClosedAt() { + return closedAt; + } + + public void setClosedAt(Date closedAt) { + this.closedAt = closedAt; + } +} diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestoneService.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestoneService.java new file mode 100644 index 0000000..1dbcdb9 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestoneService.java @@ -0,0 +1,48 @@ +package org.jenkinsci.plugins.pipeline.github.client; + +import org.eclipse.egit.github.core.IRepositoryIdProvider; +import org.eclipse.egit.github.core.client.GitHubRequest; +import org.eclipse.egit.github.core.service.MilestoneService; + +/** + * @author Aaron Whiteside + */ +public class ExtendedMilestoneService extends MilestoneService { + + public ExtendedMilestoneService(final ExtendedGitHubClient client) { + super(client); + } + + @Override + public ExtendedGitHubClient getClient() { + return (ExtendedGitHubClient) super.getClient(); + } + + @Override + public ExtendedMilestone getMilestone(final IRepositoryIdProvider repository, final int number) { + return getMilestone(repository, Integer.toString(number)); + } + + @Override + public ExtendedMilestone getMilestone(final IRepositoryIdProvider repository, final String number) { + String repoId = getId(repository); + return getMilestone(repoId, number); + } + + private ExtendedMilestone getMilestone(final String id, final String number) { + if (number == null) { + throw new IllegalArgumentException("Milestone cannot be null"); + } else if (number.length() == 0) { + throw new IllegalArgumentException("Milestone cannot be empty"); + } else { + StringBuilder uri = new StringBuilder("/repos"); + uri.append('/').append(id); + uri.append("/milestones"); + uri.append('/').append(number); + GitHubRequest request = createRequest(); + request.setUri(uri); + request.setType(ExtendedMilestone.class); + return (ExtendedMilestone)getClient().getUnchecked(request).getBody(); + } + } +} diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedPullRequestService.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedPullRequestService.java index b255728..dc4d020 100644 --- a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedPullRequestService.java +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedPullRequestService.java @@ -28,7 +28,7 @@ public ExtendedGitHubClient getClient() { return (ExtendedGitHubClient) super.getClient(); } - public ExtendedPullRequest editPullRequest(final IRepositoryIdProvider repository, final ExtendedPullRequest request) throws IOException { + public ExtendedPullRequest editPullRequest(final IRepositoryIdProvider repository, final ExtendedPullRequest request) { Objects.requireNonNull(request, "request cannot be null"); String id = this.getId(repository); From 00ca68436473e8de0d80a614f6f03b651fbdd0ca Mon Sep 17 00:00:00 2001 From: Aaron Whiteside Date: Mon, 28 Jan 2019 20:16:41 +1100 Subject: [PATCH 2/4] ExtendedMilestone.java - fixed fingbugs errors --- .../pipeline/github/client/ExtendedMilestone.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestone.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestone.java index a5b13c5..6037018 100644 --- a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestone.java +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedMilestone.java @@ -1,6 +1,7 @@ package org.jenkinsci.plugins.pipeline.github.client; import org.eclipse.egit.github.core.Milestone; +import org.eclipse.egit.github.core.util.DateUtils; import java.util.Date; @@ -14,18 +15,18 @@ public class ExtendedMilestone extends Milestone { private Date closedAt; public Date getUpdatedAt() { - return updatedAt; + return DateUtils.clone(this.updatedAt); } - public void setUpdatedAt(Date updatedAt) { - this.updatedAt = updatedAt; + public void setUpdatedAt(final Date updatedAt) { + this.updatedAt = DateUtils.clone(updatedAt); } public Date getClosedAt() { - return closedAt; + return DateUtils.clone(this.closedAt); } - public void setClosedAt(Date closedAt) { - this.closedAt = closedAt; + public void setClosedAt(final Date closedAt) { + this.closedAt = DateUtils.clone(closedAt); } } From 47891dee197f7adc509c4bac5839e9cc7d0f8b68 Mon Sep 17 00:00:00 2001 From: Aaron Whiteside Date: Mon, 28 Jan 2019 20:21:01 +1100 Subject: [PATCH 3/4] ExtendedPullRequestService.java PullRequestGroovyObject.java - less check IOException's --- .../plugins/pipeline/github/PullRequestGroovyObject.java | 6 +----- .../pipeline/github/client/ExtendedPullRequestService.java | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/PullRequestGroovyObject.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/PullRequestGroovyObject.java index 45e75fb..e126886 100644 --- a/src/main/java/org/jenkinsci/plugins/pipeline/github/PullRequestGroovyObject.java +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/PullRequestGroovyObject.java @@ -688,11 +688,7 @@ public String merge(final String commitTitle, @Whitelisted public void refresh() { - try { - pullRequest = pullRequestService.getPullRequest(base, pullRequest.getNumber()); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } + pullRequest = pullRequestService.getPullRequest(base, pullRequest.getNumber()); } @Whitelisted diff --git a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedPullRequestService.java b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedPullRequestService.java index dc4d020..d153b3b 100644 --- a/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedPullRequestService.java +++ b/src/main/java/org/jenkinsci/plugins/pipeline/github/client/ExtendedPullRequestService.java @@ -67,7 +67,7 @@ protected Map editPrMap(final ExtendedPullRequest request) { @Override - public ExtendedPullRequest getPullRequest(final IRepositoryIdProvider repository, final int id) throws IOException { + public ExtendedPullRequest getPullRequest(final IRepositoryIdProvider repository, final int id) { String repoId = this.getId(repository); StringBuilder uri = new StringBuilder("/repos"); uri.append('/').append(repoId); @@ -76,7 +76,7 @@ public ExtendedPullRequest getPullRequest(final IRepositoryIdProvider repository GitHubRequest request = this.createRequest(); request.setUri(uri); request.setType(ExtendedPullRequest.class); - return (ExtendedPullRequest) getClient().get(request).getBody(); + return (ExtendedPullRequest) getClient().getUnchecked(request).getBody(); } public ExtendedMergeStatus merge(final IRepositoryIdProvider repository, From 3e77ce62cd5c3262cc63dcfea5beeaf0be5ee10a Mon Sep 17 00:00:00 2001 From: Aaron Whiteside Date: Mon, 28 Jan 2019 20:28:43 +1100 Subject: [PATCH 4/4] pom.xml - bump github client version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f81903..2aee46e 100644 --- a/pom.xml +++ b/pom.xml @@ -96,7 +96,7 @@ org.eclipse.mylyn.github org.eclipse.egit.github.core - 5.0.0.201806131550-r + 5.2.0.201812061821-r