View Javadoc
1   /**
2    * Copyright (c) 2013-2023, jcabi.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the jcabi.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.jcabi.github;
31  
32  import com.jcabi.aspects.Immutable;
33  import com.jcabi.aspects.Loggable;
34  import java.io.IOException;
35  import java.net.URL;
36  import java.text.ParseException;
37  import java.util.Date;
38  import javax.json.Json;
39  import javax.json.JsonObject;
40  import lombok.EqualsAndHashCode;
41  import lombok.ToString;
42  
43  /**
44   * Github pull request.
45   *
46   * @author Yegor Bugayenko (yegor256@gmail.com)
47   * @version $Id: 8c1a5879029374700381f530af7b63d90de3fb00 $
48   * @since 0.3
49   * @see <a href="https://developer.github.com/v3/pulls/">Pull Request API</a>
50   * @checkstyle MultipleStringLiterals (500 lines)
51   *
52   */
53  @Immutable
54  @SuppressWarnings("PMD.TooManyMethods")
55  public interface Pull extends Comparable<Pull>, JsonReadable, JsonPatchable {
56  
57      /**
58       * Repo we're in.
59       * @return Repo
60       */
61      Repo repo();
62  
63      /**
64       * Get its number.
65       * @return Pull request number
66       */
67      int number();
68  
69      /**
70       * Get its base ref.
71       * @return Base ref
72       * @throws IOException If there is any I/O problem
73       */
74      PullRef base() throws IOException;
75  
76      /**
77       * Get its head ref.
78       * @return Head ref
79       * @throws IOException If there is any I/O problem
80       */
81      PullRef head() throws IOException;
82  
83      /**
84       * Get all commits of the pull request.
85       * @return Commits
86       * @throws IOException If there is any I/O problem
87       * @see <a href="https://developer.github.com/v3/pulls/#list-commits-on-a-pull-request">List Commits on a Pull Request</a>
88       */
89      Iterable<Commit> commits() throws IOException;
90  
91      /**
92       * List all files of the pull request.
93       * @return Files
94       * @throws IOException If there is any I/O problem
95       * @see <a href="https://developer.github.com/v3/pulls/#list-pull-requests-files">List Pull Request Files</a>
96       */
97      Iterable<JsonObject> files() throws IOException;
98  
99      /**
100      * Merge it.
101      * @param msg Commit message
102      * @throws IOException If there is any I/O problem
103      * @see <a href="https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-buttontrade">Merge a Pull Request</a>
104      */
105     void merge(String msg)
106         throws IOException;
107 
108     /**
109      * Merge it.
110      * @param msg Commit message
111      * @param sha Optional SHA hash for head comparison
112      * @return State of the Merge
113      * @throws IOException IOException If there is any I/O problem
114      */
115     MergeState merge(String msg,
116         String sha
117     ) throws IOException;
118 
119     /**
120      * Get Pull Comments.
121      * @return Comments.
122      * @throws IOException If there is any I/O problem
123      * @see <a href="https://developer.github.com/v3/pulls/#link-relations">Link Relations - Review Comments</a>
124      */
125     PullComments comments() throws IOException;
126 
127     /**
128      * Get Pull Checks.
129      * @return Checks.
130      * @throws IOException If there is any I/O problem.
131      * @see <a href="https://developer.github.com/v3/checks/runs/">Checks API</a>
132      * @since 1.6.0
133      */
134     Checks checks() throws IOException;
135 
136     /**
137      * Smart pull request with extra features.
138      */
139     @Immutable
140     @ToString
141     @Loggable(Loggable.DEBUG)
142     @EqualsAndHashCode(of = {"pull", "jsn"})
143     final class Smart implements Pull {
144         /**
145          * Encapsulated pull request.
146          */
147         private final transient Pull pull;
148         /**
149          * SmartJson object for convenient JSON parsing.
150          */
151         private final transient SmartJson jsn;
152 
153         /**
154          * Public ctor.
155          * @param pll Pull request
156          */
157         public Smart(
158             final Pull pll
159         ) {
160             this.pull = pll;
161             this.jsn = new SmartJson(pll);
162         }
163 
164         /**
165          * Is it open?
166          * @return TRUE if it's open
167          * @throws IOException If there is any I/O problem
168          */
169         public boolean isOpen() throws IOException {
170             return Issue.OPEN_STATE.equals(this.state());
171         }
172 
173         /**
174          * Get its state.
175          * @return State of pull request
176          * @throws IOException If there is any I/O problem
177          */
178         public String state() throws IOException {
179             return this.jsn.text("state");
180         }
181 
182         /**
183          * Change its state.
184          * @param state State of pull request
185          * @throws IOException If there is any I/O problem
186          */
187         public void state(
188             final String state
189         ) throws IOException {
190             this.pull.patch(
191                 Json.createObjectBuilder().add("state", state).build()
192             );
193         }
194 
195         /**
196          * Get its title.
197          * @return Title of pull request
198          * @throws IOException If there is any I/O problem
199          */
200         public String title() throws IOException {
201             return this.jsn.text("title");
202         }
203 
204         /**
205          * Change its title.
206          * @param text Title of pull request
207          * @throws IOException If there is any I/O problem
208          */
209         public void title(
210             final String text
211         ) throws IOException {
212             this.pull.patch(
213                 Json.createObjectBuilder().add("title", text).build()
214             );
215         }
216 
217         /**
218          * Get its body.
219          * @return Body of pull request
220          * @throws IOException If there is any I/O problem
221          */
222         public String body() throws IOException {
223             return this.jsn.text("body");
224         }
225 
226         /**
227          * Change its body.
228          * @param text Body of pull request
229          * @throws IOException If there is any I/O problem
230          */
231         public void body(
232             final String text
233         ) throws IOException {
234             this.pull.patch(
235                 Json.createObjectBuilder().add("body", text).build()
236             );
237         }
238 
239         /**
240          * Get its URL.
241          * @return URL of pull request
242          * @throws IOException If there is any I/O problem
243          */
244         public URL url() throws IOException {
245             return new URL(this.jsn.text("url"));
246         }
247 
248         /**
249          * Get its HTML URL.
250          * @return URL of pull request
251          * @throws IOException If there is any I/O problem
252          */
253         public URL htmlUrl() throws IOException {
254             return new URL(this.jsn.text("html_url"));
255         }
256 
257         /**
258          * When this pull request was created.
259          * @return Date of creation
260          * @throws IOException If there is any I/O problem
261          */
262         public Date createdAt() throws IOException {
263             try {
264                 return new Github.Time(
265                     this.jsn.text("created_at")
266                 ).date();
267             } catch (final ParseException ex) {
268                 throw new IllegalStateException(ex);
269             }
270         }
271 
272         /**
273          * When this pull request was updated.
274          * @return Date of update
275          * @throws IOException If there is any I/O problem
276          */
277         public Date updatedAt() throws IOException {
278             try {
279                 return new Github.Time(
280                     this.jsn.text("updated_at")
281                 ).date();
282             } catch (final ParseException ex) {
283                 throw new IllegalStateException(ex);
284             }
285         }
286 
287         /**
288          * When this pull request was closed.
289          * @return Date of closing
290          * @throws IOException If there is any I/O problem
291          */
292         public Date closedAt() throws IOException {
293             try {
294                 return new Github.Time(
295                     this.jsn.text("closed_at")
296                 ).date();
297             } catch (final ParseException ex) {
298                 throw new IllegalStateException(ex);
299             }
300         }
301 
302         /**
303          * When this pull request was merged.
304          * @return Date of merging
305          * @throws IOException If there is any I/O problem
306          */
307         public Date mergedAt() throws IOException {
308             try {
309                 return new Github.Time(
310                     this.jsn.text("merged_at")
311                 ).date();
312             } catch (final ParseException ex) {
313                 throw new IllegalStateException(ex);
314             }
315         }
316 
317         /**
318          * Get its author.
319          * @return Author of pull request (who submitted it)
320          * @throws IOException If there is any I/O problem
321          */
322         public User author() throws IOException {
323             return this.pull.repo().github().users().get(
324                 this.jsn.value(
325                     "user", JsonObject.class
326                 ).getString("login")
327             );
328         }
329 
330         /**
331          * Get an issue where the pull request is submitted.
332          * @return Issue
333          */
334         public Issue issue() {
335             return this.pull.repo().issues().get(this.pull.number());
336         }
337 
338         /**
339          * Get comments count.
340          * @return Count of comments
341          * @throws IOException If there is any I/O problem
342          * @since 0.8
343          */
344         public int commentsCount() throws IOException {
345             return this.jsn.number("comments");
346         }
347 
348         @Override
349         public Repo repo() {
350             return this.pull.repo();
351         }
352 
353         @Override
354         public int number() {
355             return this.pull.number();
356         }
357 
358         @Override
359         public Iterable<Commit> commits() throws IOException {
360             return this.pull.commits();
361         }
362 
363         @Override
364         public Iterable<JsonObject> files() throws IOException {
365             return this.pull.files();
366         }
367 
368         @Override
369         public void merge(
370             final String msg
371         ) throws IOException {
372             this.pull.merge(msg);
373         }
374 
375         @Override
376         public MergeState merge(
377             final String msg,
378             final String sha
379         )
380             throws IOException {
381             return this.pull.merge(msg, sha);
382         }
383 
384         @Override
385         public PullComments comments() throws IOException {
386             return this.pull.comments();
387         }
388 
389         /**
390          * Retrieve a PR check runs.
391          * @return Checks
392          * @throws IOException If there is any I/O problem.
393          * @since 1.6.0
394          */
395         @Override
396         public Checks checks() throws IOException {
397             return this.pull.checks();
398         }
399 
400         @Override
401         public JsonObject json() throws IOException {
402             return this.pull.json();
403         }
404 
405         @Override
406         public void patch(
407             final JsonObject json
408         ) throws IOException {
409             this.pull.patch(json);
410         }
411 
412         @Override
413         public int compareTo(
414             final Pull obj
415         ) {
416             return this.pull.compareTo(obj);
417         }
418 
419         @Override
420         public PullRef base() throws IOException {
421             return this.pull.base();
422         }
423 
424         @Override
425         public PullRef head() throws IOException {
426             return this.pull.head();
427         }
428     }
429 }