Compare commits

..

886 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
13184e72e1 [maven-release-plugin] prepare release github-api-1.83 2017-01-09 16:37:56 -08:00
Kohsuke Kawaguchi
911e8d21a7 Made the test case runnable, at least for me 2017-01-09 16:26:58 -08:00
Kohsuke Kawaguchi
5b69a2925f Merge pull request #324 2017-01-09 16:18:48 -08:00
Kohsuke Kawaguchi
d1c900a620 Marking the fact that these APIs are still in preview and subject to change 2017-01-09 16:18:40 -08:00
Kohsuke Kawaguchi
6bfeb54f3c Just exposing permission type enum until there's more to this relation than one property 2017-01-09 16:14:30 -08:00
Kohsuke Kawaguchi
198fede915 Merge pull request #325 2017-01-09 16:06:14 -08:00
Kohsuke Kawaguchi
1212ae3eb3 Touch up for uniformity
- Prefer typed 'URL' over 'String' that is URL
- Mark API as @Preview to communicate that this is subject to change

More branch protection stuff needs to be added. See https://developer.github.com/v3/repos/branches/
2017-01-09 16:06:05 -08:00
Kohsuke Kawaguchi
1266dcc0c7 Merge pull request #327 from stephenc/expose-rate-limit-headers
Expose Rate Limit Headers
2017-01-10 08:57:07 +09:00
Stephen Connolly
6fcddf4a47 Some usage patterns require more pro-active rate limit queries 2017-01-05 10:25:40 +00:00
Stephen Connolly
dfea424b94 Expose the API url used by the GitHub 2017-01-05 09:36:58 +00:00
Stephen Connolly
9d03435aa1 Expose Rate Limit Headers
Exposes the rate limit header responses so that consumers of the API can proactively tune their usage
2017-01-05 09:21:32 +00:00
Jeffrey.Nelson
26c20a7a22 add branch protection attributes 2016-12-22 11:55:01 -06:00
Kohsuke Kawaguchi
470da06ecf Cleaning up javadoc warnings 2016-12-17 08:17:20 -08:00
Kohsuke Kawaguchi
a746a310bc [maven-release-plugin] prepare for next development iteration 2016-12-17 07:50:55 -08:00
Kohsuke Kawaguchi
3dbb516084 [maven-release-plugin] prepare release github-api-1.82 2016-12-17 07:50:48 -08:00
Kohsuke Kawaguchi
32177283b3 Fixed issue #317
There's no need for the library to replicate a logic when GitHub does
that (and does that correctly.)

Looking at the commit history, I couldn't see why this was added in the
first place.
2016-12-17 07:30:14 -08:00
Kohsuke Kawaguchi
3a66e90b7a Fixed issue #319
getApiUrl() is unreliable given that we collapse issue & PR into one
object.
2016-12-17 07:28:28 -08:00
Kohsuke Kawaguchi
a454fb10ec Tree traversal from commit & its associated tests 2016-12-17 07:21:31 -08:00
Kohsuke Kawaguchi
b5386a35ee Defining better traversal methods for apps that walk trees 2016-12-17 07:09:29 -08:00
Kohsuke Kawaguchi
11651da411 not always a blob, for example it could be a tree. 2016-12-17 07:04:31 -08:00
Kohsuke Kawaguchi
88d52c44ad Recording parent GHRepository 2016-12-17 07:03:40 -08:00
Kohsuke Kawaguchi
2d7d4bbd4e Merge pull request #320 with some additional changes 2016-12-17 06:56:41 -08:00
Kohsuke Kawaguchi
e6ee278fde Another version that directly reads BLOB without going through an intermediate object. 2016-12-17 06:55:44 -08:00
Kohsuke Kawaguchi
6380cf9ed0 Added a method to retrieve the actual bytes of BLOB
... which is probably more useful than the getContent() method
2016-12-17 06:47:24 -08:00
Kohsuke Kawaguchi
2e78dc52c7 Merge pull request #323 from jglick/bad-json
Fix syntactically malformed test JSON
2016-12-17 06:24:43 -08:00
Jesse Glick
ccb42d3249 [JENKINS-36240] Added GHRepository.getPermission(String). 2016-12-16 18:02:28 -05:00
Jesse Glick
c5009ab44b Fix syntactically malformed test JSON. 2016-12-16 15:04:10 -05:00
Jeff Nelson
9d15cd43a3 Merge pull request #1 from kohsuke/master
catchup
2016-12-14 12:12:57 -06:00
Kanstantsin Shautsou
0780e10fa2 Added ghRepo.getBlob(String) method
Signed-off-by: Kanstantsin Shautsou <kanstantsin.sha@gmail.com>
2016-12-13 15:28:08 +03:00
Kohsuke Kawaguchi
0731f63237 Added order parameter 2016-11-26 14:45:03 -08:00
Kohsuke Kawaguchi
a29896042b Merge pull request #315 from davidxia/dxia/patch1
Fix typos in javadocs
2016-11-26 14:38:45 -08:00
David Xia
68ebc08c9d Fix typos in javadocs
Replace "pagenated" with "paginated".
2016-11-26 00:44:52 -05:00
Kohsuke Kawaguchi
a1df526f93 [maven-release-plugin] prepare for next development iteration 2016-11-21 08:53:42 -08:00
Kohsuke Kawaguchi
0023ecefa4 [maven-release-plugin] prepare release github-api-1.81 2016-11-21 08:53:38 -08:00
Kohsuke Kawaguchi
511f156603 Added the membership API for the authenticated user. 2016-11-19 15:26:04 -08:00
Kohsuke Kawaguchi
3f223b1ba0 Support assignees when creating a new issue 2016-11-19 14:50:47 -08:00
Kohsuke Kawaguchi
a1528a1a63 API to add/set/remove assignees from an issue 2016-11-19 14:48:43 -08:00
Kohsuke Kawaguchi
b8bfddbf3a Code simplification 2016-11-19 14:30:35 -08:00
Kohsuke Kawaguchi
47fc813027 Assignees of the repository.
(Personally this concept makes no sense for me, so I don't know what this API really does. I'm just following their API docs)
2016-11-19 14:29:27 -08:00
Kohsuke Kawaguchi
c7f2228a44 [maven-release-plugin] prepare for next development iteration 2016-11-16 22:52:14 -08:00
Kohsuke Kawaguchi
b0e0f045f8 [maven-release-plugin] prepare release github-api-1.80 2016-11-16 22:52:10 -08:00
Kohsuke Kawaguchi
1296514794 this field is not yet used 2016-11-16 22:49:13 -08:00
Kohsuke Kawaguchi
18e797095f rewrote assert with JUnit ones 2016-11-16 22:36:16 -08:00
Kohsuke Kawaguchi
85aa2ad4e6 Added reaction API 2016-11-16 19:10:37 -08:00
Kohsuke Kawaguchi
818f6dc045 Issue #309: Added user listing 2016-11-16 18:26:49 -08:00
Kohsuke Kawaguchi
1c162c6390 Merge pull request #304 2016-11-16 18:19:26 -08:00
Kohsuke Kawaguchi
def3a28fb5 Restoring backward compatibility of names 2016-11-16 18:18:45 -08:00
Kohsuke Kawaguchi
d1378a0236 Merge pull request #306 from stephenc/offline-support
Add offline support to the API to make parsing events easier
2016-11-16 18:12:39 -08:00
Stephen Connolly
e544c7a65a Fix the push event payload 2016-11-14 12:52:22 +00:00
Kanstantsin Shautsou
24f48f668c Add portion of auth/application API. (#307)
* Add portion of auth/application API.

Signed-off-by: Kanstantsin Shautsou <kanstantsin.sha@gmail.com>

* fixup
2016-11-11 15:56:03 +01:00
Stephen Connolly
9988a090ac Add some more tests 2016-11-11 14:27:09 +00:00
Stephen Connolly
d36e145d06 Need to be able to tell if this is a creation / deletion of a ref for multibranch projects 2016-11-11 14:18:47 +00:00
Stephen Connolly
498d63ea00 Typos spotted by Jesse 2016-11-08 15:48:39 +00:00
Stephen Connolly
7dc620a3ba More details emerge on the PingEvent payload 2016-11-08 15:29:27 +00:00
Stephen Connolly
66145e1d23 Seems there is an undocumented but important PING event used by github-plugin 2016-11-08 15:26:33 +00:00
Stephen Connolly
7bf8621afe Need the pusher details for github-plugin 2016-11-08 15:14:42 +00:00
Stephen Connolly
ce3f74232e Ensure a use case required by github-plugin is valid 2016-11-08 15:11:35 +00:00
Stephen Connolly
5b92d4b88c Fix findbugs false alarms 2016-11-08 15:04:02 +00:00
Stephen Connolly
4daf6ba057 Add offline support to the API to make parsing events easier
- When we receive events from a webhook, it is non-trivial to determine which GitHub instance the event came from
  or for that matter even if the event actually came from GitHub or GitHub Enterprise.
- In order to ensure that the logic for parsing events does not get replicated in clients, we need to be
  able to call GitHub.parseEventPayload(Reader,Class) without knowing which GitHub the event originates from
  and without the resulting objects triggering API calls back to a GitHub
- Thus we add GitHub.offline() to provide an off-line connection
- Thus we modify some of the object classes to return best-effort objects when off-line
- Add support for more of the event types into GHEventPayload
- Add tests of the event payload and accessing critical fields when using GitHub.offline()
2016-11-08 12:56:52 +00:00
Jason Song
955e9899af Fix fields of GHRepository 2016-11-04 00:09:59 +08:00
Kohsuke Kawaguchi
fa3d0887ef [maven-release-plugin] prepare for next development iteration 2016-10-24 19:23:18 -07:00
Kohsuke Kawaguchi
5d5c6cf71c [maven-release-plugin] prepare release github-api-1.79 2016-10-24 19:23:14 -07:00
Kohsuke Kawaguchi
89aac45f41 Merge pull request #299 2016-10-24 19:15:46 -07:00
Kohsuke Kawaguchi
4965fd5f4c Noting possible TODO for the future 2016-10-24 19:15:38 -07:00
Kohsuke Kawaguchi
87fbb8ec98 Copy/paste error 2016-10-24 19:07:32 -07:00
Kohsuke Kawaguchi
0d92d4ba61 [maven-release-plugin] prepare for next development iteration 2016-10-24 14:10:35 -07:00
Kohsuke Kawaguchi
b0df93bbcb [maven-release-plugin] prepare release github-api-1.78 2016-10-24 14:10:30 -07:00
Kohsuke Kawaguchi
290d0b226a Merge pull request #295 from jglick/pageSize
Use maximum permitted page size
2016-10-24 14:04:05 -07:00
Kohsuke Kawaguchi
8b3469610c Merge pull request #300 from stephenc/commit-dates
Expose the commit dates
2016-10-24 14:03:14 -07:00
Stephen Connolly
50b47fb73b Expose the commit dates 2016-10-24 21:12:56 +01:00
Ben Sheats
5334cb8688 url encode hashes in ref names 2016-10-21 11:40:01 -04:00
Jesse Glick
38983df42d If we are a returning a collection of all things, we might as well use the maximum page size to minimize HTTP requests. 2016-09-19 09:48:23 -07:00
Kohsuke Kawaguchi
df963cb71c [maven-release-plugin] prepare for next development iteration 2016-08-05 21:32:15 -07:00
Kohsuke Kawaguchi
e9368fb04e [maven-release-plugin] prepare release github-api-1.77 2016-08-05 21:32:10 -07:00
Kohsuke Kawaguchi
e2a1630cf4 findbug taming 2016-08-05 21:28:54 -07:00
Kohsuke Kawaguchi
4f15b7c9fa NPE fix. type can be null 2016-08-05 21:19:32 -07:00
Kohsuke Kawaguchi
63f500ad7f Fixed issue #286
List commit API (https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository) already populates short info, and so populate() call could be excessive.

 It's possible that the short info is always available and therefore there's never a need to call populate(), but that assumption is hard to test, so I'm leaving that in
2016-08-05 21:11:00 -07:00
Kohsuke Kawaguchi
a9fb4546e1 Constants for preview media types 2016-08-05 20:56:11 -07:00
Kohsuke Kawaguchi
cabbbf7f02 Handle 404 that represents "no license" 2016-08-05 20:50:39 -07:00
Kohsuke Kawaguchi
59324b0082 Add preview media type header explicitly 2016-08-05 20:47:08 -07:00
Kohsuke Kawaguchi
6a356c82a5 Fixed up tests 2016-08-05 20:44:45 -07:00
Kohsuke Kawaguchi
70f0f5714a While a use of custom HttpConnector is clever, it doesn't fit the current idiom of this library. 2016-08-05 20:44:10 -07:00
Kohsuke Kawaguchi
07b527a0f2 Enumeration in GitHub should be PagedIterable 2016-08-05 20:40:34 -07:00
Kohsuke Kawaguchi
80aa75aab1 Added the wrap() method for a backpointer 2016-08-05 20:40:23 -07:00
Kohsuke Kawaguchi
0cf4211aa5 Merged GHLicense & GHLicenseBase
Elsewhere in this library, whenever there are multiple forms of the same
object, we map that to the same class and use lazy data retrieval to
fill missing fields.
2016-08-05 20:36:46 -07:00
Kohsuke Kawaguchi
1de02a5099 Added a marker for preview APIs 2016-08-05 20:19:36 -07:00
Duncan Dickinson
bb1cecb95b PR-284: license API support
Had to do git-diff | git-apply to avoid whitespe changes to GHRepository
2016-08-05 20:11:33 -07:00
Kohsuke Kawaguchi
d82397a173 doc fix 2016-08-05 20:00:05 -07:00
Kohsuke Kawaguchi
856cf5e568 Better type safety by splitting RateLimitHandler and AbuseLimitHandler
While the signature is the same, headers that they expect are different,
so any non-trivial logic cannot be reused.
2016-08-05 19:58:04 -07:00
Matt Mitchell
9f5a6ee549 Implement an abuse handler
If too many requests are made within X amount of time (not the traditional hourly rate limit), github may begin returning 403.  Then we should wait for a bit to attempt to access the API again.  In this case, we parse out the Retry-After field returned and sleep until that (it's usually 60 seconds)
2016-07-22 13:16:12 -07:00
Kohsuke Kawaguchi
a2f0837d14 Issue #279: added another overload that takes permission 2016-06-03 20:56:17 -07:00
Kohsuke Kawaguchi
c7f6889534 Issue #258: updated OkHttp that handles Cache control headers better 2016-06-03 20:31:12 -07:00
Kohsuke Kawaguchi
0415326d09 Issue #261: handle 204 no content correctly 2016-06-03 20:27:29 -07:00
Kohsuke Kawaguchi
16a0f8ece0 [maven-release-plugin] prepare for next development iteration 2016-06-03 00:19:15 -07:00
Kohsuke Kawaguchi
5d1ef296b3 [maven-release-plugin] prepare release github-api-1.76 2016-06-03 00:19:09 -07:00
Kohsuke Kawaguchi
16dbcde90b Shut up FindBugs! 2016-06-03 00:16:20 -07:00
Kohsuke Kawaguchi
50cbf25c72 Shut up FindBugs 2016-06-03 00:09:25 -07:00
Kohsuke Kawaguchi
7b87de2b4c Giving it a bit of delay in the hope that it removes flakiness of tests 2016-06-03 00:04:36 -07:00
Kohsuke Kawaguchi
1ce54a7925 Bug fix in toString() 2016-06-02 23:55:55 -07:00
Kohsuke Kawaguchi
1bfe7dd99b Issue #264: wait for the repo to finish forking 2016-06-02 23:50:18 -07:00
Kohsuke Kawaguchi
27e855ddbd Issue 262: added support for branch protection API 2016-06-02 23:40:37 -07:00
Kohsuke Kawaguchi
3d1bed0f8f In JDK I'm using (Java8), I get a delegating HttpURLConnection that breaks the hack to set the method.
This change makes this hack even worse, but this is the only way I can think of, since I cannot update HttpURLConnection.methods that is static final.
2016-06-02 23:40:14 -07:00
Kohsuke Kawaguchi
5c9ea9b63a Added a fluent version 2016-06-02 23:27:52 -07:00
Kohsuke Kawaguchi
7c034f5670 Doc improvement 2016-06-02 22:43:58 -07:00
Kohsuke Kawaguchi
3b9f5a417a Formatting changes 2016-06-02 22:43:06 -07:00
Kohsuke Kawaguchi
cde501af8d More meaningful toString() method
Produce toString without dilligently adding it to every single class.
Rely on heuristics to cut down the number of fields to show.
2016-06-02 22:38:38 -07:00
Kohsuke Kawaguchi
3c5592c1c8 Following the convention with GHMyself.getEmails2()
This way the method is more discoverable with IDE auto-completion
2016-06-02 22:05:24 -07:00
Kohsuke Kawaguchi
2508e022bb Merge pull request #272 from noctarius/master
Added support for the extended stargazers API in Github V3 API
2016-06-03 14:04:24 +09:00
Kohsuke Kawaguchi
01fcbc24e8 Merge pull request #282 from apemberton/org-fix
related to JENKINS-34834. updating test for similar condition
2016-06-03 13:52:26 +09:00
Kohsuke Kawaguchi
204e639679 Merge pull request #281 from apemberton/master
Add Slug to GHTeam per v3 API: https://developer.github.com/v3/orgs/t…
2016-06-03 13:51:47 +09:00
Kohsuke Kawaguchi
3d301ec730 Merge pull request #278 from jglick/javadoc
Fixed broken link
2016-06-03 13:50:37 +09:00
Kohsuke Kawaguchi
9ab6d57019 Merge pull request #277 from rhels/patch-1
Updated Date was wrong
2016-06-03 13:50:22 +09:00
Kohsuke Kawaguchi
37c473130f Merge pull request #276 from thug-gamer/patch-1
Add support to delete a team
2016-06-03 13:50:11 +09:00
Andy Pemberton
5f95987a48 related to JENKINS-34834. updating test for similar condition 2016-05-14 20:07:04 -04:00
Andy Pemberton
d530b34073 Add Slug to GHTeam per v3 API: https://developer.github.com/v3/orgs/teams/ 2016-05-14 08:58:42 -04:00
Jesse Glick
35dec7a5ec Fixed broken link. 2016-05-03 18:19:57 -04:00
Konda Reddy
baedad8124 Updated Date was wrong 2016-04-30 13:20:44 -05:00
thug-gamer
007378c3a6 Add support to delete a team
Add a method to delete a team.
2016-04-29 11:41:14 +02:00
noctarius
beae9fd6ec Added support for the extended stargazers API in Github V3 API 2016-04-14 07:22:17 +02:00
Kohsuke Kawaguchi
b7507076c6 Merge pull request #270 from szpak/issue/269-reopenMilestone
[#269] Add reopen method on GHMilestone
2016-04-13 16:15:39 -07:00
Kohsuke Kawaguchi
6b5ade3ca0 [maven-release-plugin] prepare for next development iteration 2016-04-13 13:08:02 -07:00
Kohsuke Kawaguchi
715192d26c [maven-release-plugin] prepare release github-api-1.75 2016-04-13 13:07:58 -07:00
Marcin Zajaczkowski
ce140460af [#269] Add reopen method on GHMilestone 2016-04-04 17:54:55 +02:00
Kohsuke Kawaguchi
d30b0403ce [maven-release-plugin] prepare for next development iteration 2016-03-18 19:22:37 -07:00
Kohsuke Kawaguchi
255c993548 [maven-release-plugin] prepare release github-api-1.74 2016-03-18 19:22:34 -07:00
Kohsuke Kawaguchi
557ae4165c Not important 2016-03-18 19:19:51 -07:00
Kohsuke Kawaguchi
a31395ed80 Signature fix for Java5 2016-03-18 19:15:52 -07:00
Kohsuke Kawaguchi
397886d289 Excluding a flaky test 2016-03-18 19:08:51 -07:00
Kohsuke Kawaguchi
7307bec2ae Merge pull request #259 from Shredder121/animal-sniffer
Animal sniffer
2016-03-18 18:27:22 -07:00
Ruben Dijkstra
0cd5147e1a Java 5 doesn't have TimeUnit.HOURS
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/TimeUnit.html
2016-03-12 22:01:25 +01:00
Ruben Dijkstra
36d5b092d7 Java 5 doesn't have new String(byte[], Charset)
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html
2016-03-12 21:59:51 +01:00
Ruben Dijkstra
f9014dbab3 Convert to legacy Throwable.initCause() 2016-03-12 21:58:27 +01:00
Ruben Dijkstra
755d5f77ea Java 5 doesn't have Arrays.copyOf()
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Arrays.html
2016-03-12 21:56:56 +01:00
Ruben Dijkstra
906d9af7b7 Include the animal sniffer plugin
7a78f9f5aa set the compiler level back to 5, but there are no guarantees that we don't accidentally use any features from newer class libraries.
2016-03-12 21:48:50 +01:00
Kohsuke Kawaguchi
14dcb37ee1 Not all caller wants GET 2016-03-11 23:29:58 -08:00
Kohsuke Kawaguchi
c1c2a27358 Doc improvement 2016-03-11 23:21:07 -08:00
Kohsuke Kawaguchi
5ab9657f9c Merge branch 'master' of github.com:kohsuke/github-api 2016-03-11 23:16:37 -08:00
Kohsuke Kawaguchi
7a78f9f5aa No need to require 1.6 2016-03-11 23:16:24 -08:00
Kohsuke Kawaguchi
ac8c65f062 Merge pull request #251
Conflicts:
	src/main/java/org/kohsuke/github/GitHub.java
2016-03-11 23:14:01 -08:00
Kohsuke Kawaguchi
1954a9f3f8 This isn't just about API URL but it also checks the valid credential 2016-03-11 23:12:50 -08:00
Kohsuke Kawaguchi
3b764f9c90 Don't lose the original problem 2016-03-11 23:11:22 -08:00
Kohsuke Kawaguchi
10f55cc549 Checking another header
I think it's better to pick a header that's unique to GitHub.
2016-03-11 23:10:41 -08:00
Kohsuke Kawaguchi
cd8d955646 Documenting what one gets 2016-03-11 23:06:21 -08:00
Kohsuke Kawaguchi
bba07c9080 Merge pull request #253 from cyrille-leclerc/fix-infinite-loop
Fix #252: infinite loop because the "hypertext engine" generates invalid URLs
2016-03-11 22:59:00 -08:00
Kohsuke Kawaguchi
dba84a33b9 Logger should be static 2016-03-11 22:55:58 -08:00
Kohsuke Kawaguchi
ae49166aa2 No such parameter exists on this method 2016-03-11 22:55:44 -08:00
Kohsuke Kawaguchi
e09185fd0e Logger should be static 2016-03-11 22:51:48 -08:00
Cyrille Le Clerc
56379bb3b9 Fix broken log message in GitHub.java and cleanup code as recommended by @jglick 2016-03-07 19:25:42 +01:00
Cyrille Le Clerc
027e4b4f25 Better error message: introduce HttpException, subclass of IOException with url, http responseCode and http responseMessage to help exception handling. 2016-03-06 18:34:27 +01:00
Cyrille Le Clerc
ba951cb6e3 Fix #252: infinite loop because the "hypertext engine" may duplicate '?' generating invalid "https://api.github.com/notifications?all=true&page=2?all=true" instead of "https://api.github.com/notifications?all=true&page=2&all=true". A better fix will be to prevent duplication of parameters ("all=true" in this case). 2016-03-06 18:27:05 +01:00
Manuel Recena
ae85cf4b6c Improve checkApiUrlValidity() method to support the private mode in GitHub Enterprise servers 2016-03-05 17:42:25 +01:00
Kohsuke Kawaguchi
dbc79f8c42 Fixing issue raised in https://github.com/kohsuke/github-api/pull/247
From Shredder121,
--------------------
Only the HttpURLConnection.method was set by that change. Not the
Requester.method.

This means that Requester.method is still set to POST, isMethodWithBody
will return true, and uc.setDoOutput(true) will be called.

I use Okhttp, and their HttpURLConnectionImpl's method changes to POST
if you tell it to open a stream to write to.
2016-03-01 19:46:50 -08:00
Kohsuke Kawaguchi
54c3070607 [maven-release-plugin] prepare for next development iteration 2016-02-29 21:03:34 -08:00
Kohsuke Kawaguchi
013eaa30b6 [maven-release-plugin] prepare release github-api-1.73 2016-02-29 21:03:31 -08:00
Kohsuke Kawaguchi
751043bf81 change in the markup generated 2016-02-29 21:01:18 -08:00
Kohsuke Kawaguchi
14f7198a07 Handle "all" webhook correctly
This fixes #250
2016-02-29 20:56:47 -08:00
Kohsuke Kawaguchi
94af819ae5 Merge pull request #249 from zapelin/master
Added getHtmlUrl() to GHCommit
2016-02-29 20:48:19 -08:00
Kohsuke Kawaguchi
dbcc9afbc7 Merge pull request #248 from daniel-beck/populate-commit
Populate commit with data for getCommitShortInfo
2016-02-29 20:47:52 -08:00
Kohsuke Kawaguchi
8556033ae6 Merge pull request #245 from daniel-beck/email-hook-error
Fix error when creating email service hook
2016-02-29 20:45:40 -08:00
Kohsuke Kawaguchi
650493f863 Merge pull request #244 from benbek/patch-1
Minor amendment to the documentation
2016-02-29 19:57:47 -08:00
Kohsuke Kawaguchi
d80ad77871 Use builder pattern to support all the other options 2016-02-29 19:57:16 -08:00
Artem Gubanov
f4b129b9f1 Added getHtmlUrl() to GHCommit 2016-02-25 10:46:17 +02:00
Daniel Beck
c0a05e0650 Populate commit with data for getCommitShortInfo 2016-02-21 01:26:43 +01:00
Daniel Beck
33d95d3e3a Fix error when creating email service hook 2016-01-20 23:30:10 +01:00
benbek
f573f83fb9 Amendment to the documentation
The status reported by GitHub for deleting a file is actually "removed", not "deleted".
2016-01-19 00:05:01 +02:00
Daniel Lovera
e94c36b7e6 clean: remove unused import 2015-12-13 21:05:36 +01:00
Daniel Lovera
c879e9e34d Support for auto_init parameter in organization
The GitHub api auto_init parameter allows to initialize created repository with a readme file.
Add createRepository methods in GHOrganization using auto_init parameter. Already existing createRepository methods use auto_init parameter as false for retro-compatibility.
2015-12-13 21:00:40 +01:00
Daniel Lovera
ac39b564a8 Support for auto_init parameter
The GitHub api auto_init parameter allows to initialize created repository with a readme file.
Add a createRepository method using auto_init parameter. Already existing createRepository method uses auto_init parameter as false for retro-compatibility.
2015-12-13 20:59:49 +01:00
Kohsuke Kawaguchi
d91388aba4 [maven-release-plugin] prepare for next development iteration 2015-12-10 07:00:06 -08:00
Kohsuke Kawaguchi
733d78abdd [maven-release-plugin] prepare release github-api-1.72 2015-12-10 06:59:37 -08:00
Kohsuke Kawaguchi
d5809e375c Simplification via enum handling in 'req.with' 2015-12-10 06:33:49 -08:00
Kohsuke Kawaguchi
2440a676bd Added more comprehensive API to list pull requests
This fixes issue #234
2015-12-10 06:26:04 -08:00
Kohsuke Kawaguchi
03ac6c72e7 Formatting change 2015-12-10 06:01:34 -08:00
Kohsuke Kawaguchi
1bbbcabae0 Making API flow better 2015-12-10 05:56:08 -08:00
Kohsuke Kawaguchi
9149b6b998 GHCommit might be only partially populated.
This fixes issue #230
2015-12-10 05:53:55 -08:00
Kohsuke Kawaguchi
2603b5a402 Added stargazers and stars 2015-12-03 17:55:06 +01:00
Kohsuke Kawaguchi
dbddf5b9eb Implemented pagenation size support. 2015-12-03 17:41:43 +01:00
Kohsuke Kawaguchi
841f77bac2 Naming anonymous iterator.
... in anticipation of the page size support.
2015-12-03 16:33:39 +01:00
Kohsuke Kawaguchi
83ffe75baa Fixed rate handling limit handling
Issue #220. If RateLimitHandler returns normally, it should retry.
2015-12-02 12:03:39 +01:00
Kohsuke Kawaguchi
8cb7094803 Added pagination for following & follower 2015-12-02 08:35:56 +01:00
Kohsuke Kawaguchi
ed8cd0ad19 Added getter for ID
And the actual value has already gone past 'int'

This fixes issue #199
2015-12-01 17:02:53 +01:00
Kohsuke Kawaguchi
90d8e65a3b [maven-release-plugin] prepare for next development iteration 2015-12-01 16:27:29 +01:00
Kohsuke Kawaguchi
b24fcb18af [maven-release-plugin] prepare release github-api-1.71 2015-12-01 16:27:24 +01:00
Kohsuke Kawaguchi
c2f2d0f8af Making FindBugs happy 2015-12-01 16:23:51 +01:00
Kohsuke Kawaguchi
e33bdd7e62 Two teams now.
I assume this is because 'owner' is now a team.
2015-12-01 16:17:03 +01:00
Kohsuke Kawaguchi
402adc3559 Merge pull request #232 2015-12-01 16:05:25 +01:00
Kohsuke Kawaguchi
0f45d03c51 Reworked this change a bit.
- GHApiInfo need not be public because it's not publicly exposed.
- Throwing an exception is better IMO as it allows richer error message,
  including the differentiation between unreachable host name vs wrong
  URL, and reporting the API endpoint URL that was actually tried.
2015-12-01 16:01:01 +01:00
Kohsuke Kawaguchi
0397d7ab53 Fixing a test problem 2015-12-01 15:39:19 +01:00
Kohsuke Kawaguchi
79f86b82e4 Merge pull request #237 2015-12-01 15:18:15 +01:00
Kohsuke Kawaguchi
261a7a34e3 Consolidated timeout handling 2015-12-01 15:17:54 +01:00
Kohsuke Kawaguchi
723bb89e10 Merge pull request #219 from if6was9/cross-fork-compare
#218 enable cross fork compare
2015-12-01 15:04:50 +01:00
Oliver Gondža
832e4f3c37 Use default timeouts for URLConnections 2015-12-01 14:58:46 +01:00
Kohsuke Kawaguchi
75a4081549 Follow up to PR #216 2015-12-01 14:57:30 +01:00
Kohsuke Kawaguchi
f9291f9fd1 Merge pull request #216 from if6was9/issue-215-download-failure
#215 fix read() failure with private repos
2015-12-01 14:56:49 +01:00
Kohsuke Kawaguchi
c3b4ee9321 Merge pull request #226 from Shredder121/oauth-credentials
Check builder result to either be a token or a user
2015-12-01 14:54:35 +01:00
Kohsuke Kawaguchi
f86896943d Merge pull request #224 from Shredder121/directory-content-trailing-slash
Remove trailing slash when requesting directory content
2015-12-01 14:53:56 +01:00
Kohsuke Kawaguchi
c33f05e8ca Merge pull request #225 from Shredder121/findbugs-changes
Overzealous FindBugs changes.
2015-12-01 14:51:53 +01:00
Oleg Nenashev
52727ded03 Merge pull request #233 from vparfonov/master
Add information about mirror url if it exist.
2015-11-30 18:18:44 +03:00
Manuel Recena
f7d132758e Merge pull request #231 from recena/MergeCommitSha
Support for merge_commit_sha
2015-11-25 23:22:10 +01:00
Manuel Recena
bb17ca9a53 Merge pull request #236 from recena/findbugs
Findbugs plugin has been upgraded
2015-11-25 23:06:57 +01:00
Manuel Recena
aab21c5b17 findbugs plugin has been upgraded 2015-11-23 10:29:04 +01:00
Manuel Recena
acbafee02a Removed unrelated changes. @KostyaSha's suggestion 2015-11-23 10:25:41 +01:00
Manuel Recena
c6d2b1a222 @deprecated annotations were removed 2015-11-23 09:33:32 +01:00
Vitaly Parfonov
b037f75fb0 Add information about mirror url if it exist. Like https://github.com/apache/tomee 2015-11-19 12:09:34 +02:00
Ruben Dijkstra
a1e79d3050 Add unit test to cover the truncation of ?ref 2015-11-16 18:33:51 +01:00
Manuel Recena
354969d5fa Javadoc comment reviewed 2015-11-16 11:16:58 +01:00
Manuel Recena
a371892409 Added a new method to validate the GitHub API URL 2015-11-15 16:36:27 +01:00
Manuel Recena
b0789a7ce7 Set merge_commit_sha as deprecated 2015-11-15 11:50:13 +01:00
Manuel Recena
08be8eb4f8 Added a new test testMergeCommitSHA() 2015-11-15 11:46:18 +01:00
Manuel Recena
bafddf4baf Initial source code modifications 2015-11-14 12:11:24 +01:00
Ruben Dijkstra
75b9184a00 Check builder result to either be a token or a user
Currently, a `user` property is always required (it not having content is also fine).

This adds support for only having the `oauth` key in the property file/environment.
2015-10-09 17:20:11 +02:00
Ruben Dijkstra
5dc83cf2bf Overzealous FindBugs changes.
Charsets that are standard on the JRE are try-lookuped,
bridge methods were removed and a stream that would be closed later is closed explicitly
2015-10-08 19:31:55 +02:00
Ruben Dijkstra
092e9062c8 Remove trailing slash when requesting directory content 2015-10-06 18:23:51 +02:00
Rob Schoening
512c921a81 enable cross fork compare 2015-09-27 07:50:11 -07:00
Kohsuke Kawaguchi
defcd6fe26 Merge pull request #217 from dblevins/closed_at
Support Milestone closed_at date
2015-09-17 19:23:00 -07:00
dblevins
025b6cbfb7 Support Milestone closed_at date 2015-09-14 10:53:07 -07:00
Rob Schoening
b0687dbeb5 Fix compilation errror: The constructor ArrayList<GHHook>(List<capture#1-of ? extends GHHook[]>) is undefined 2015-09-06 08:45:42 -07:00
Rob Schoening
e0b109cba6 fix read() failure with private repos
reorder buildRequest()
2015-09-06 08:28:20 -07:00
Kohsuke Kawaguchi
adaa8ece89 [maven-release-plugin] prepare for next development iteration 2015-08-15 07:19:25 -07:00
Kohsuke Kawaguchi
6516b20e16 [maven-release-plugin] prepare release github-api-1.70 2015-08-15 07:19:22 -07:00
Kohsuke Kawaguchi
839cb03690 Overzealous FindBugs changes.
String given without the encoding mandated by a protocol/design/etc should be converted with the platform default encoding. After all it exists for a reason!
2015-08-15 07:17:15 -07:00
Kohsuke Kawaguchi
2bcd99b14f Overzealous findbugs fix.
This method should rely on platform specific encoding
2015-08-14 11:59:55 -07:00
Kohsuke Kawaguchi
e3ebf6e8a1 Merge pull request #212 from umajeric/master
Added option to edit GitHub release once it is created
2015-08-11 09:24:30 +02:00
Uros Majeric
76d28314b0 Added option to edit GitHub release once it is created 2015-08-06 15:40:26 +02:00
Oleg Nenashev
ec450b8fd8 Merge pull request #210 from oleg-nenashev/findbugs-cleanup
Cleanup issues discovered by FindBugs
2015-07-24 15:57:31 +03:00
Oleg Nenashev
79c5b2edd5 FindBugs: Fix over 100 issues and enforce FindBugs 2015-07-20 12:28:41 +03:00
Kohsuke Kawaguchi
2d45ac51ef [maven-release-plugin] prepare for next development iteration 2015-07-17 05:09:28 -07:00
Kohsuke Kawaguchi
505bb8f06d [maven-release-plugin] prepare release github-api-1.69 2015-07-17 05:09:25 -07:00
Kohsuke Kawaguchi
f8408bd29f This method can return null.
I think what's going on is that GitHub takes some non-zero amount of time to compute this value, and our test runs too fast sometimes and try to fetch a PR before its mergeability is computed
2015-07-17 15:06:39 +03:00
Kohsuke Kawaguchi
5f2c84a913 Tests should use test repositories for mutating tests.
Picking up the first random repository you are an owner of and making a change to it is too dangerous.
2015-07-17 14:33:18 +03:00
Kohsuke Kawaguchi
3011c99e3f Merge pull request #208 from oleg-nenashev/master
Fix potential NPE in the code
2015-07-17 14:24:14 +03:00
Oleg Nenashev
ebc97f42ad Fix potential NPE in the code 2015-07-17 14:21:46 +03:00
Kohsuke Kawaguchi
4660c6d363 Merge pull request #192
Changing GHHook to abstract is a binary incompatible change in theory,
but given the way this class is designed it is difficult to imagine
any client code instantiating this class.

So I think it is OK.
2015-07-17 14:06:47 +03:00
Kohsuke Kawaguchi
e239ef50ba Consistent name with other classes 2015-07-17 14:06:35 +03:00
Kohsuke Kawaguchi
8b4312a880 Merge pull request #203 2015-07-17 13:52:35 +03:00
Kohsuke Kawaguchi
90daf8087e Turning this into javadoc so that users can see them in IDE. 2015-07-17 13:52:16 +03:00
Kohsuke Kawaguchi
dd21bcb34c I think this is a better name 2015-07-17 13:51:31 +03:00
Kohsuke Kawaguchi
c4113f1ac7 Merge pull request #182 from henryju/master
Fix invalid URL for pull request comments update/delete
2015-07-17 13:47:43 +03:00
Kohsuke Kawaguchi
efa48acd1d Merge pull request #185 from marc-guenther/master
Fixes #183: added a method listForks() to GHRepository
2015-07-17 13:47:17 +03:00
Kohsuke Kawaguchi
15e4d07a6d Merge pull request #187 from yegorius/master
Recognize previous_file field in GHCommit.File
2015-07-17 13:46:21 +03:00
Kohsuke Kawaguchi
cb2248809c Merge pull request #190 2015-07-17 13:43:01 +03:00
Kohsuke Kawaguchi
eb9551d81b Renamed getMasterBranch to getDefaultBranch
The new set method can be simply renamed without the backward
compatibility version since it's new
2015-07-17 13:42:20 +03:00
Kohsuke Kawaguchi
87d1256a1b Merge pull request #189 from if6was9/fix-post-body-regression
fixed regression that caused POST operations to be sent as GET
2015-07-17 13:39:52 +03:00
Kohsuke Kawaguchi
dd6179cf25 Merge pull request #197 from treeduck/patch-1
added Page Build
2015-07-17 13:35:20 +03:00
Marc Guenther
23c56ff887 remove unused import 2015-07-17 12:30:49 +02:00
Kohsuke Kawaguchi
c4eefa6917 Merge branch 'master' of github.com:kohsuke/github-api 2015-07-17 13:29:40 +03:00
Kohsuke Kawaguchi
202cff58f2 Merge pull request #201 2015-07-17 13:29:22 +03:00
Kohsuke Kawaguchi
025806f0fd Consistent name with other classes 2015-07-17 13:29:07 +03:00
Kohsuke Kawaguchi
b0c54ef0f1 Restored backward compatibility with the former signature 2015-07-17 13:27:20 +03:00
Kohsuke Kawaguchi
4d7681b1a4 Merge pull request #206 from torodev/master
Specified the GET
2015-07-17 13:24:48 +03:00
Kohsuke Kawaguchi
340fb3f624 Merge pull request #207 from oleg-nenashev/findbugs-enable
Enable FindBugs in the repo
2015-07-17 13:13:23 +03:00
Marc Guenther
a83aad22ca renamed Sort enum, some cleanup, better javadoc 2015-07-17 09:33:48 +02:00
Oleg Nenashev
5a418dcce6 Enable FindBugs 2015-07-16 16:56:09 +03:00
torodev
ec5392708f Specified the GET
Previously doesn't specify the HTTP method to perform
2015-07-14 09:47:04 +08:00
Oleg Nenashev
901db92b11 Merge pull request #205 from stephenc/fix-npe
Fix NPE found when resolving issues from search api
2015-07-07 00:22:46 +03:00
Stephen Connolly
01b8b10344 Fix NPE found when resolving issues from search api 2015-07-06 11:07:05 +01:00
Oleg Nenashev
698d642ec8 Merge pull request #204 from lanwen/ping_event
add ping event to GH events enum
2015-07-05 19:57:20 +03:00
MerkushevKirill
90d1047fb2 add ping event to GH events enum 2015-07-05 19:37:56 +03:00
Luca Milanesio
b0d1eac477 GitHub API have changed the semantics of /user/repos API
It seems that since a couple of days (or weeks?) the /user/repos is returning
ALL the repositories that the user has access or collaborates to whilst previously
were only the ones that belong to him.

JavaDoc updated in order to avoid getting unwanted results and introduced as well
the possibility to filter a specific type of repository to be returned:
- All (the GitHub's default)
- Owner (the user's repos)
- Public / Private (public or private repos)
- Member (the user collaborates to)
2015-06-26 13:42:43 +01:00
Julien HENRY
cce02aec3d Add delete and update for GHIssueComment 2015-06-16 09:27:55 +02:00
Julien HENRY
492ff58aa8 Fix invalid URL for pull request comments update/delete 2015-06-16 09:16:49 +02:00
Kohsuke Kawaguchi
dd3e73996b Merge pull request #200 from lanwen/lost_body_write
fix for unused json map when method with body, but body is null
2015-06-15 10:38:14 -07:00
MerkushevKirill
931ed7adac don't ignore args when method without body
in case of GET or DELETE request
2015-06-15 18:14:58 +03:00
MerkushevKirill
861fd55d06 fix for unused json map when method with body, but body is null
fixes regression from b976e0ef4e
2015-06-15 17:57:16 +03:00
Kohsuke Kawaguchi
9a4eee4e7d Merge pull request #198 from lanwen/rate-reset
fix for GH Enterprise which does not have rate limit reset field
2015-06-11 10:53:11 -07:00
MerkushevKirill
ed76cdbddf fix for GH Enterprise which does not have rate limit reset field
Fixes regression from a4c1c8de24
2015-06-11 14:52:50 +03:00
Koji Habu
9d91549803 added Page Build 2015-06-10 15:43:57 -07:00
Marc Guenther
a5425a3c71 improved javadoc for listForks() 2015-05-28 22:18:02 +02:00
Chris Hut
f4b105b10f Enable creation and retrieval of org webhooks
made GHHook abstract and created two concrete subclasses for org
and repo hooks. Created utility class GHHooks to manage creation
and retrieval of org/repo hooks with minimal code duplication. These
are invoked by GHOrganization and GHRepository respectively.
2015-05-15 13:29:18 -07:00
Rob Schoening
e4de09c55b allow default branch to be set 2015-05-09 01:05:04 -07:00
Rob Schoening
d77be9d382 fixed regression that caused POST operations to be sent as GET 2015-05-09 01:01:04 -07:00
yegorius
626909addb recognize previous_file field in GHCommit.File 2015-05-01 17:59:01 +03:00
Marc Guenther
9b750bedef Fixes #183: added a method listForks() to GHRepository
listForks() will list all forks of a repository.
An optional sort argument is also supported.
2015-05-01 14:06:20 +02:00
Kohsuke Kawaguchi
b976e0ef4e Issue #180: don't write body if HTTP method is DELETE. 2015-04-26 10:52:43 -07:00
Kohsuke Kawaguchi
fd434292ad [maven-release-plugin] prepare for next development iteration 2015-04-19 17:40:39 -07:00
Kohsuke Kawaguchi
7b4d3a869b [maven-release-plugin] prepare release github-api-1.68 2015-04-19 17:40:35 -07:00
Kohsuke Kawaguchi
eeebb1b59f Added the 'sha' parameter.
Fixes issue #176
2015-04-19 17:25:13 -07:00
Julien HENRY
63136f64b7 Merge pull request #174
The merge was done manually because the original commit contains lots of
whitespace only changes.
2015-04-19 17:22:04 -07:00
Kohsuke Kawaguchi
1d2fbf2d92 Merge pull request #179 from lskillen/master
Fix NullPointerException on RateLimitHandler when handling API errors.
2015-04-19 17:03:50 -07:00
Kohsuke Kawaguchi
1e52dded14 Added a helper method 2015-04-15 08:33:18 -07:00
Lee Skillen
cfc7005275 Fix NullPointerException on RateLimiter when handling API errors. 2015-04-14 14:45:47 +01:00
Kohsuke Kawaguchi
f23afcd5aa [maven-release-plugin] prepare for next development iteration 2015-04-13 18:30:43 -07:00
Kohsuke Kawaguchi
4e88a0c91b [maven-release-plugin] prepare release github-api-1.67 2015-04-13 18:30:40 -07:00
Kohsuke Kawaguchi
d070f9deb0 TAB -> WS 2015-04-13 18:25:44 -07:00
Kohsuke Kawaguchi
b736e20a74 Added more getHtmlUrl() methods 2015-04-13 18:17:37 -07:00
Kohsuke Kawaguchi
aad20d0a03 Merge pull request #169 from KostyaSha/fixAuthLoop
Throw error for bad creds
2015-04-13 16:55:58 -07:00
Kohsuke Kawaguchi
7ff97348d9 Merge pull request #170 from KostyaSha/coverity
Improvements
2015-04-13 16:55:24 -07:00
Kohsuke Kawaguchi
68dda3a46d Merge pull request #175 2015-04-13 16:47:32 -07:00
Kohsuke Kawaguchi
2cd44f8c33 Added the pair method 2015-04-13 16:47:25 -07:00
Kohsuke Kawaguchi
9775954aff Massaging the PR.
- need to retrieve the object in full to have all the fields properly populated
- documentation fix, as this method points to the root of the forking chain, not just an upstream.
2015-04-13 16:45:38 -07:00
Kohsuke Kawaguchi
1a071b0b54 Returning null instead of throwing an exception (as a matter of taste) 2015-04-13 16:39:20 -07:00
Kohsuke Kawaguchi
8dcea59c74 Fixed javadoc errors 2015-04-13 16:36:14 -07:00
Kohsuke Kawaguchi
f482f77871 Merge pull request #177 from infm/feat/notif
Added getters for the objects notifications refer to
2015-04-13 16:38:22 -07:00
infm
b058c39ee1 Added getters for the objects notifications refer to 2015-04-09 01:21:38 +03:00
Jason Nichols
b926b6c67f Added the source attribute to GHRepository 2015-04-02 14:54:13 -04:00
Kohsuke Kawaguchi
3fb8e5f799 [maven-release-plugin] prepare for next development iteration 2015-03-24 10:26:48 -07:00
Kohsuke Kawaguchi
277ccb5188 [maven-release-plugin] prepare release github-api-1.66 2015-03-24 10:26:44 -07:00
Kanstantsin Shautsou
9ebc9c0867 Use FAIL rate-limit handler for tests
Should avoid possible Thread.sleep() for tests execution.
2015-03-23 21:14:42 +03:00
Kanstantsin Shautsou
f1f96713a4 [CID-107552] Unintended regular expression
regex_expected: The . character(s) in the pattern ".md" can match any character, because calls to replaceAll treat the pattern as a regular expression, which might be unexpected.
2015-03-23 02:35:55 +03:00
Kanstantsin Shautsou
fc3b6d2c2e [CID-107535] Missing call to superclass
Similar to other events
2015-03-23 02:23:44 +03:00
Kanstantsin Shautsou
d0d0716b3b Throw error for bad creds 2015-03-23 02:09:23 +03:00
Kohsuke Kawaguchi
73119afeff [maven-release-plugin] prepare for next development iteration 2015-03-22 15:57:32 -07:00
Kohsuke Kawaguchi
8939179be8 [maven-release-plugin] prepare release github-api-1.65 2015-03-22 15:57:29 -07:00
Kohsuke Kawaguchi
adba2e68db Renamed for consistency with other methods 2015-03-22 15:54:53 -07:00
Kohsuke Kawaguchi
0ef8b471a3 Added subscription related methods 2015-03-22 15:54:10 -07:00
Kohsuke Kawaguchi
205950fc5f Method to mark the thread as read 2015-03-22 15:50:32 -07:00
Kohsuke Kawaguchi
8835b2c745 added a method to mark all the notifications as read 2015-03-22 15:45:36 -07:00
Kohsuke Kawaguchi
74fda40764 Implemented initial notification API support.
Fixes issue #119
2015-03-22 15:40:53 -07:00
Kohsuke Kawaguchi
687a36937e Keep HttpURLConnection() in the field.
The primary motivation was to expose response headers, but this also made the code most concise by reducing the # of parameters that are passed around.
2015-03-22 14:52:34 -07:00
Kohsuke Kawaguchi
2c7b8bd6e8 report error stream even for 404 2015-03-22 14:46:38 -07:00
Kohsuke Kawaguchi
e9417f5fa1 Described how to set up persistent disk cache
This is good enough "fix" for issue #168.
2015-03-22 12:13:30 -07:00
Kohsuke Kawaguchi
5e08b34c43 added code search 2015-03-22 12:08:53 -07:00
Kohsuke Kawaguchi
7b436ffb3b support on-demand data population for the use in code search API. 2015-03-22 12:02:08 -07:00
Kohsuke Kawaguchi
1ee2ec3728 Added repository search 2015-03-22 11:48:56 -07:00
Kohsuke Kawaguchi
ed28768146 implemented user search 2015-03-22 11:41:25 -07:00
Kohsuke Kawaguchi
f931835176 refactored to introduce other search builders 2015-03-22 11:32:48 -07:00
Kohsuke Kawaguchi
0cf9bc2814 [maven-release-plugin] prepare for next development iteration 2015-03-22 11:16:03 -07:00
Kohsuke Kawaguchi
8b428f2c93 whitespace only changes for consistent indentation 2015-03-22 11:14:19 -07:00
Kohsuke Kawaguchi
10238dbcd3 Explaining why this code is the way it is. 2015-03-22 11:13:40 -07:00
Kohsuke Kawaguchi
6229e0928d Revert "Set credentials file according to documentation"
This reverts commit 0bf81f4fb9.

The point of this is to allow me to use a separate account to avoid
corrupting my event stream. GitHub.connect() does the standard handling
for those who are not me.
2015-03-22 11:11:03 -07:00
Kohsuke Kawaguchi
5c7b259fe9 Using the latest 2015-03-22 11:02:17 -07:00
Kohsuke Kawaguchi
cc84c867c0 I think our coverage is pretty good now 2015-03-22 11:01:02 -07:00
Kohsuke Kawaguchi
5bf252e12d Added markdown support
Fixes issue #165
2015-03-22 11:00:57 -07:00
Kohsuke Kawaguchi
75512ff66a Turns out the interning of GHUser wasn't working at all!
Fixes issue #166.
2015-03-22 10:38:57 -07:00
Kohsuke Kawaguchi
6f4832476a test case for #162 2015-03-22 10:21:16 -07:00
Kohsuke Kawaguchi
86b0d27299 added a method to read content.
This also fixes #162.
2015-03-22 10:21:09 -07:00
Kohsuke Kawaguchi
5a8845f7f6 added a method to return the raw unprocessed body 2015-03-22 09:17:49 -07:00
Kohsuke Kawaguchi
709e47f32f Added getDownloadUrl() method 2015-03-22 09:10:34 -07:00
Kohsuke Kawaguchi
77590b4eb3 eliminate the need for path manipulation and consolidate them to 'with' 2015-03-21 16:52:49 -07:00
Kohsuke Kawaguchi
72fc313135 improved error handling 2015-03-21 16:43:11 -07:00
Kohsuke Kawaguchi
39b32cee2e Implemented /repositories
Fixed issue #157
2015-03-21 16:35:34 -07:00
Kohsuke Kawaguchi
bdcee7c052 Merge pull request #160 with some modifications
Strategy pattern is better for API rate limit handling as the current
behavior is quite valid for batch applications.

I'm not taking OkHttp version change so as not to introduce any unneeded
version requirement.
2015-03-17 07:44:36 -07:00
Kohsuke Kawaguchi
4093e53b5b Implemented a strategy pattern to let the client determine API rate limit behavior.
The default is set to the backward compatible behaviour.
2015-03-17 07:43:51 -07:00
Kanstantsin Shautsou
a4c1c8de24 Provide reset date info for rate limit 2015-03-17 07:31:05 -07:00
Kohsuke Kawaguchi
7ed234c875 Standardize environment variable names
... that are more like typical environment variables. Reasonably unique and upper case.

Deprecate other methods. The point of a connector method is to make sure all clients of the same library uses the same environments, thereby eliminating the pain of setting credentials per app.

Allowing the app to specify the environment variable names defeat this purpose.
2015-03-15 13:17:57 -07:00
Kohsuke Kawaguchi
0359160ac6 Avoided using JDK6 method 2015-03-15 13:07:21 -07:00
Kohsuke Kawaguchi
2478dad9b5 Simplification 2015-03-15 13:04:50 -07:00
Kohsuke Kawaguchi
690292352b Simplification
But this method is insane!
2015-03-15 13:02:28 -07:00
Kohsuke Kawaguchi
271d18cddc simplification 2015-03-15 13:01:35 -07:00
Kohsuke Kawaguchi
e1465639e7 Merge pull request #156 from ashwanthkumar/endpoint-from-properties
Picking endpoint from the properties file and environment variables
2015-03-15 19:55:32 +00:00
Kohsuke Kawaguchi
ce7ca59339 Merge pull request #155 2015-03-15 12:49:30 -07:00
Kohsuke Kawaguchi
76610b25d7 Promoted GHTreeEntry to the top-level 2015-03-15 12:49:14 -07:00
Kohsuke Kawaguchi
dfce0bda7c prefer list over raw array 2015-03-15 12:48:27 -07:00
Ashwanth Kumar
41c0dd9727 Fixing the indentation for enpointVariableName 2015-03-13 21:26:49 +05:30
Ashwanth Kumar
232c0389d3 Adding fromEnvironment to maintain backword compatibility 2015-03-13 21:26:19 +05:30
Oleg Nenashev
d95c8a4ab0 Merge pull request #161 from khoa-nd/master
Add method to get the list of languages using in repository
2015-03-13 17:58:01 +03:00
khoa-nd
374fdb37e1 Change type of language bytes from Integer to Long 2015-03-06 09:11:03 +07:00
khoa-nd
f78530636e Add method to get the list of languages using in repository 2015-03-05 15:53:02 +07:00
Kanstantsin Shautsou
0bf81f4fb9 Set credentials file according to documentation 2015-03-03 19:23:06 +03:00
Kohsuke Kawaguchi
dcc3b7f36b [maven-release-plugin] prepare for next development iteration 2015-03-02 09:10:52 -08:00
Kohsuke Kawaguchi
d6722266f5 [maven-release-plugin] prepare release github-api-1.63 2015-03-02 09:10:49 -08:00
Kohsuke Kawaguchi
11566891dc Restored backward compatibility
The signature of the method can change for the future, but it still has
to return Label instances for older binaries
2015-03-02 08:33:00 -08:00
Kohsuke Kawaguchi
9aaf69cc9a Added maling list 2015-03-02 08:14:15 -08:00
Ashwanth Kumar
a716a59489 Picking endpoint from the properties file and environment variables
Helps seemless switching between public github and enterprise without any code changes
2015-02-22 09:41:58 +05:30
Daniel
bad0d1bbcf implementing github trees as described https://developer.github.com/v3/git/trees/#get-a-tree-recursively 2015-02-18 14:58:27 +01:00
Kohsuke Kawaguchi
aa43e265b7 [maven-release-plugin] prepare for next development iteration 2015-02-15 09:12:26 -08:00
Kohsuke Kawaguchi
67280951ff [maven-release-plugin] prepare release github-api-1.62 2015-02-15 09:12:23 -08:00
Kohsuke Kawaguchi
c3a9f6f9f5 Fixed NPE.
issue #152
2015-02-15 09:06:04 -08:00
Kohsuke Kawaguchi
e631e46dd1 Exposed this method.
I'm generally against having these inter-object short cut methods
(in this case it's getOwner().getName() but oh well.)

Fixes issue #149
2015-02-15 08:57:36 -08:00
Kohsuke Kawaguchi
15163ffde0 Avoid multiple concurrent population 2015-02-15 08:56:57 -08:00
Kohsuke Kawaguchi
b898284821 Mentions thread-safety and state the goal.
Most of the objects are effectively immutable, so this should be an easy goal

Fixes issue #148.
2015-02-15 08:56:29 -08:00
Kohsuke Kawaguchi
3bb7eb2e03 Added API to list contributors 2015-02-15 08:50:55 -08:00
Kohsuke Kawaguchi
11fcb9d456 Report the repository the push happened to
Fixes issue #144.
2015-02-15 08:42:32 -08:00
Kohsuke Kawaguchi
29f826448a Added a convenience method.
See: issue #134
2015-02-15 08:35:31 -08:00
Kohsuke Kawaguchi
a8cf4a7120 Added watch API support.
Fixes issue #130
2015-02-15 08:31:57 -08:00
Kohsuke Kawaguchi
60dce94a47 renamed to created RepositoryTest 2015-02-15 08:25:49 -08:00
Kohsuke Kawaguchi
c965b9cc24 follow up fix to the GHRepository.getApiTailUrl() change 2015-02-15 08:20:28 -08:00
Kohsuke Kawaguchi
762a32eb6d Added repository watch listing 2015-02-15 07:45:11 -08:00
Kohsuke Kawaguchi
541dac1aee Use getApiTailUrl for consistency 2015-02-15 07:35:02 -08:00
Kohsuke Kawaguchi
e2e2329301 Noting issue #60 that this method can return null 2015-02-15 07:16:18 -08:00
Kohsuke Kawaguchi
9afad71b0f Newly created user object resets root to null.
Fixes issue #111.
Test case from KostyaSha
2015-02-15 07:13:33 -08:00
Kohsuke Kawaguchi
7bbe0f7e8a Allow the client to explicitly control proxy
Fixes issue #109.
2015-02-15 07:02:50 -08:00
Kohsuke Kawaguchi
d90adfa98e Implemented label CRUD operations on GHRepository
Fixes issue #105
2015-02-15 06:55:35 -08:00
Kohsuke Kawaguchi
1dbcc4b776 Fixed the getReadme() method.
It was calling the wrong endpoint.
Fixed issue #99.
2015-02-15 06:31:22 -08:00
Kohsuke Kawaguchi
18696fca2d [maven-release-plugin] prepare for next development iteration 2015-02-14 10:28:55 -08:00
Kohsuke Kawaguchi
c40100b6da [maven-release-plugin] prepare release github-api-1.61 2015-02-14 10:28:51 -08:00
Kohsuke Kawaguchi
6396818740 MRELEASE-812 botched 1.60 2015-02-14 10:27:13 -08:00
Kohsuke Kawaguchi
6df5a0d47b Added a test 2015-02-14 10:13:25 -08:00
Kohsuke Kawaguchi
15c18c5547 Improved the search API 2015-02-14 10:08:46 -08:00
Kohsuke Kawaguchi
4b6981c2e7 Added issue-search capability 2015-02-14 09:53:29 -08:00
Kohsuke Kawaguchi
1b4025300c Merge remote-tracking branch 'origin/master' 2015-02-14 09:32:53 -08:00
Kohsuke Kawaguchi
983c871bff More compilation error fix 2015-02-14 09:30:50 -08:00
Kohsuke Kawaguchi
609f532f8c Merge pull request #143 2015-02-14 08:29:09 -08:00
Kohsuke Kawaguchi
c6fc03c73a In this library domain objects should be immutable. 2015-02-14 08:28:55 -08:00
Kohsuke Kawaguchi
b6e48cc4f9 Use GHObject as much as we can 2015-02-14 08:27:20 -08:00
Kohsuke Kawaguchi
50f43cc178 Inserted backward compatibility methods 2015-02-14 08:26:49 -08:00
Kohsuke Kawaguchi
f421067a0d Looks like Windows line ends have crept in. 2015-02-14 07:01:32 -08:00
Kohsuke Kawaguchi
edd9a2d5b6 Using newly added GHObject in more places. 2015-02-14 06:59:46 -08:00
Kohsuke Kawaguchi
41e0329f55 doc improvement 2015-02-14 06:52:48 -08:00
Kohsuke Kawaguchi
21ea916e0d Pull request #143 introduced wrong file permissions 2015-02-14 06:48:56 -08:00
Kohsuke Kawaguchi
3b6ca3020e Pull request #143 introduced wrong file permissions 2015-02-14 06:47:52 -08:00
Kohsuke Kawaguchi
3737845b78 Merge pull request #143 2015-02-14 06:47:26 -08:00
Kohsuke Kawaguchi
a30c78cd12 restored backward compatibility in the public API 2015-02-14 06:46:27 -08:00
Kohsuke Kawaguchi
f8fba41a30 Merge pull request #141 from alvaro1728/master
Trivial change to enable creating/updating binary content (files).
2015-02-14 09:42:55 -05:00
Kohsuke Kawaguchi
052902fb49 Merge pull request #146 2015-02-14 06:41:06 -08:00
Surya Gaddipati
58143c26bc Use GHCommitState for deployment status state 2015-01-12 10:04:01 -06:00
Surya Gaddipati
5d83894056 Add method for listing deployments 2015-01-02 16:46:56 -06:00
Rob Schoening
e35667525f fix #145 GHTeam.getMembers() does not page properly 2014-12-28 15:47:57 -08:00
Surya Gaddipati
2f318152d8 Complete api implementation for setting/retriving deployment status on a deployment 2014-12-20 17:09:59 -06:00
Surya Gaddipati
bc518a9ae8 Complete implementation of create deployment api 2014-12-20 11:52:49 -06:00
Kohsuke Kawaguchi
425ae2d536 Merge pull request #142 from suryagaddipati/master
Add code for creating deployments for a repo
2014-12-19 11:45:15 -08:00
Kohsuke Kawaguchi
a6cacd4aba Merge pull request #137 from simonecarriero/master
added 'diverged' constant to GHCompare.Status enum
2014-12-19 11:44:10 -08:00
Kohsuke Kawaguchi
5a7083537c Merge pull request #136 from rtyley/page-team-repositories
Add paging support for Team's Repositories
2014-12-19 11:43:56 -08:00
Surya Gaddipati
e15f7a59fd Merge pull request #139 from farmdawgnation/mocking-scope
Put mockito in the test scope.
2014-12-19 12:53:15 -06:00
Surya Gaddipati
a2fa526aa0 Add code for creating deployments for a repo 2014-12-19 12:47:00 -06:00
mendeza
7e959d6a87 Added binary content support - without tabs. 2014-12-18 21:15:29 -08:00
mendeza
5121fe1cbf Added binary content support. 2014-12-18 21:03:28 -08:00
Matt Farmer
3c3d4fc151 Put mockito in the test scope. 2014-11-16 15:31:04 -05:00
Simone Carriero
a7f75c9a6c added 'diverged' constant to GHCompare.Status enum 2014-11-06 12:18:16 +01:00
Roberto Tyley
e7262b8fbe Add paging support for Team's Repositories
The team repositories endpoint does do paging, so gotta support that.
2014-11-06 09:40:37 +00:00
Kohsuke Kawaguchi
af3099c526 [maven-release-plugin] prepare for next development iteration 2014-10-08 12:17:53 -07:00
Kohsuke Kawaguchi
2b9d47cea8 [maven-release-plugin] prepare release github-api-1.59 2014-10-08 12:17:49 -07:00
Kohsuke Kawaguchi
5db90d3fc4 This test is invalid if ~/.github file exists, which is quite common 2014-10-08 12:15:32 -07:00
Kohsuke Kawaguchi
372d5ff758 Fixed a test regression
Presumably due to the behaviour change on GitHub API?
2014-10-08 12:07:09 -07:00
Kohsuke Kawaguchi
ebf39eaea1 [INFRA-142]
Reworked version of https://github.com/kohsuke/github-api/pull/133/files
2014-10-08 11:29:17 -07:00
Michael O'Cleirigh
556786f2e1 Merge pull request #131 from mocleiri/resolve-credentials-from-environment
Modify GitHubBuilder to resolve user credentials from the system environ...
2014-09-30 14:07:35 -04:00
Michael O'Cleirigh
0f64994537 Make Github.connect() fail if no credentials are setup
With the previous change if no credentials were defined Github.connect() would
fall back on an anonymous connection.

This commit changes the behaviour back to what it was before so that if there
are no credentials defined in the ~/.github file and no credentials defined
in the environment an IOException is thrown to alert the method caller.

The caller can call Github.connectAnonymously() if that scenario is allowed.

This should handle most cases unless callers are depending on the
FileNotFoundException being specifically thrown instead of an IOException.
2014-09-30 13:58:06 -04:00
Michael O'Cleirigh
ac64c2022b Merge pull request #132 from mocleiri/add-getFiles-method-to-GHCompare
Add GHCompare.getFiles() method to be able to see the precise files chan...
2014-09-30 12:03:54 -04:00
Michael O'Cleirigh
9802132b6f Add GHCompare.getFiles() method to be able to see the precise files changed.
There is a file field inside of GHCompare but no getter to extract the values
for analysis.

There are contents in that field so I've added a new get method so that they
can be extracted.
2014-09-30 11:51:57 -04:00
Michael O'Cleirigh
4d6c5c14f1 Modify GitHubBuilder to resolve user credentials from the system environment
Using the Jenkins EnvInject or Credentials Binding Plugins its possible to
pass credentials as Environment Variables.

Its useful for Github.connect() to be able to directly read the values of the
'login', 'password' and 'oauth' properties directly from the environment.

This commit modifies the base Github.connect() method to resolve credentials
in two steps:

1. ~/.github credentials file if it exists.
2. login, password or oauth variables from the environment

A further fromEnvironment() method is provided to support
loading from non-standard variable names.

The old Github.connect() method would throw an IOException if the ~/.github file
did not exist.  Now it will fail silently instead dropping back to the anonymous
users access level.

Added new unit tests into GitHubTest.
2014-09-29 13:42:28 -04:00
Kohsuke Kawaguchi
d228a5fb93 Merge pull request #128 from ndeloof/patch-1
Update github scopes according to https://developer.github.com/v3/oauth/#scopes
2014-09-26 18:10:15 -07:00
Michael O'Cleirigh
7b46ef10c8 Merge pull request #129 from mocleiri/fix-pull-request-remote-repo-get-commit
Allow pullRequest.getHead().getRepository().getCommit(headSha1) to work
2014-09-26 15:14:25 -04:00
Michael O'Cleirigh
8eb9fba051 Allow pullRequest.getHead().getRepository().getCommit(headSha1) to work
The wrong .wrap method was used for pull requests initialized by state
(GHRepository.getPullReqests).

The wrong wrap call was introduced in 9fd34aec7f

This commit sets it back to the .wrapUp method which makes sure the pull request
substructure has the repo object set properly.

Without this change a NullPointerException is thrown on the last line of this
code because the repo object inside of the remoteRepository object is null:

GHRepository repo = github.getRepository(targetRepository);

List<GHPullRequest> openPullRequests = repo.getPullRequests(GHIssueState.OPEN);

for (GHPullRequest pullRequest : openPullRequests) {

    GHCommitPointer head = pullRequest.getHead();

	GHRepository remoteRepository = head.getRepository();

	String commitId = head.getSha();

	GHCommit headCommit = remoteRepository.getCommit(commitId);
2014-09-22 10:53:13 -04:00
Nicolas De loof
7b58182683 Update github scopes according to https://developer.github.com/v3/oauth/#scopes 2014-09-12 23:16:43 +02:00
Kohsuke Kawaguchi
95fbf9274b Merge pull request #124 from ohtake/connector
Allow to use custom HttpConnector when only OAuth token is given
2014-09-04 10:32:11 -07:00
Kohsuke Kawaguchi
09557dfa0f Merge pull request #123 from rtyley/use-issues-endpoints-for-pull-requests
Use issues endpoints for pull requests
2014-09-04 10:31:25 -07:00
Kohsuke Kawaguchi
4029fcc1ca Merge pull request #122 from tbruyelle/browserDownloadUrl
Add missing field browser_download_url in GHAsset
2014-09-04 10:29:23 -07:00
OHTAKE Tomohiro
d6627b1e34 Use custom HttpConnector when only OAuth token is given 2014-09-04 13:18:35 +09:00
OHTAKE Tomohiro
86d75fd767 Introduce GitHubBuilder for flexible GitHub instance creation 2014-09-04 13:17:43 +09:00
Roberto Tyley
e2220bb3b3 Fix setting labels and assignee on PullRequests
Setting labels and assignee on Pull requests failed silently, because
the API endpoint being hit contained '/pulls/' rather than '/issues/'.

"Every pull request is an issue, but not every issue is a pull request.
For this reason, “shared” actions for both features, like manipulating
assignees, labels and milestones, are provided within the Issues API."

https://developer.github.com/v3/pulls/#labels-assignees-and-milestones
2014-09-03 23:34:58 +01:00
Roberto Tyley
1a9b8bd1da Separate out clean-up of Pull requests created during test
If the test assertion fails, we want the pull-request to be closed anyway.
You can't have more than one pull-request merging a given branch into
another, so leaving the PR hanging will cause subsequent test runs to fail
in setup.
2014-09-03 23:18:22 +01:00
Thomas Bruyelle
9eda2d3f77 Add missing field browser_download_url in GHAsset 2014-09-03 22:01:43 +02:00
Kohsuke Kawaguchi
e6d59df705 [maven-release-plugin] prepare for next development iteration 2014-08-30 14:15:29 -07:00
Kohsuke Kawaguchi
db845850b2 [maven-release-plugin] prepare release github-api-1.58 2014-08-30 14:15:25 -07:00
Kohsuke Kawaguchi
d516597659 See if this will get me release with Maven 3.1 2014-08-30 14:13:45 -07:00
Kohsuke Kawaguchi
3af5a8145a Merge branch 'pull-117' 2014-08-30 14:03:58 -07:00
Kohsuke Kawaguchi
31bebd4a7a Design pattern in this library demands that these methods be on GHRef 2014-08-30 14:03:34 -07:00
Kohsuke Kawaguchi
ccb87258b0 Merge pull request #116 from DavidTanner/patch-1
Remove getPath()
2014-08-30 13:54:05 -07:00
Kohsuke Kawaguchi
2ab71e88bd Merge pull request #115 from bernd/add-missing-event-types
Add missing GitHub event types.
2014-08-30 13:53:23 -07:00
Kohsuke Kawaguchi
78bd7585bb Merge pull request #114 from ndeloof/master
get repository full name (including owner)
2014-08-30 13:53:02 -07:00
Kohsuke Kawaguchi
92cc81d9b8 Merge pull request #107 from msperisen/general-pagination
General pagination
2014-08-30 13:52:35 -07:00
Matt Farmer
97a1c741de Implement support for deleting a ref using the GitHub API. 2014-08-22 23:33:04 -04:00
Matt Farmer
077d693959 Add support for updating a ref using the API. 2014-08-22 23:30:22 -04:00
David Tanner
94831fc10a Remove getPath()
When getting the path and providing an enterprise url for the apiUrl, the /api/v3 portion gets duplicated.  Since they will be combined on line 231 of GitHub.java there is no point just grabbing the path.  See https://github.com/janinko/ghprb/issues/178, and https://issues.jenkins-ci.org/browse/JENKINS-24145?focusedCommentId=208270#comment-208270
2014-08-19 13:22:25 -06:00
Surya Gaddipati
1f298a88b0 [maven-release-plugin] prepare for next development iteration 2014-08-19 13:29:40 -05:00
Surya Gaddipati
7e49946bed [maven-release-plugin] prepare release github-api-1.57 2014-08-19 13:29:37 -05:00
Surya Gaddipati
1e81ab1017 Merge pull request #112 from lucamilanesio/master
Get all orgs/teams/permissions in a single GitHub API call
2014-08-19 12:57:39 -05:00
Bernd Ahlers
311180d12e Add missing DEPLOYMENT, DEPLOYMENT_STATUS, RELEASE and STATUS events. 2014-08-18 16:54:17 +02:00
Nicolas De Loof
0efb206881 get repository full name (including owner) 2014-08-06 04:48:46 +02:00
Luca Milanesio
0b92fa5615 Get all orgs/teams/permissions in a single GitHub API call
Exposes a new API call at GitHub root level to build the complete
set of organisations and teams that current user belongs to.

This change allows to massively reduce the number of calls to GitHub 
especially for people that belongs to multiple organisations with 
lots of teams and members.

Signed-off-by: Luca Milanesio <luca.milanesio@gmail.com>
2014-07-24 23:42:37 +01:00
t865095
a58a5b56b2 Merge branch 'master' of https://github.com/kohsuke/github-api 2014-07-08 14:14:59 +02:00
t865095
b9764c0a44 introduce pagination for all paged api calls and introduce cache invalidation 2014-07-08 13:52:53 +02:00
Kohsuke Kawaguchi
590f7ba511 Merge pull request #106 from lucamilanesio/master
Implement pagination on list of private+public repos of a user.
2014-07-04 19:13:04 -07:00
Luca Milanesio
449909b0e8 Implement pagination on list of private+public repos of a user.
The paginated version of listRepositories() was 
missing at GHMyself: as side-effect of this bug
when requesting a paginated list of repositories
the ones privately owned by a user were not shown.

This was caused by the missing override of the 
listRepositories(final int pageSize) at GHMyself
that caused the GHPerson implementation to invoked.

The GHPerson version uses the /users/:org/repos?per_page=x
URL which *works fine* for organisations but unfortunately
*does not return* private repositories for users.

IMHO GitHub API are quite inconsistent form this 
point of view, but they are documented in this way
so that work (inconsistently) as designed.
2014-07-03 10:05:17 +01:00
Kohsuke Kawaguchi
40780525f8 Bumping up the version in the hope of fixing site plugin problem 2014-07-02 21:39:13 -07:00
Kohsuke Kawaguchi
0e3707d1c3 [maven-release-plugin] prepare for next development iteration 2014-07-02 21:28:38 -07:00
Kohsuke Kawaguchi
8ddbef093b [maven-release-plugin] prepare release github-api-1.56 2014-07-02 21:28:34 -07:00
Kohsuke Kawaguchi
4ccdfccdf0 Oops forgot to commit this change 2014-07-02 21:27:11 -07:00
Kohsuke Kawaguchi
3c8aa0c630 Convention dictates that the method name be "listXyz"
getCollaborators() only fetching the first page is a bug, so we should fix that too.
2014-07-02 21:24:17 -07:00
Kohsuke Kawaguchi
ba519f996a Extracted non-formatting changes from pull request #98
The original commit has too many whitespace noise changes.

Reference: https://github.com/kohsuke/github-api/pull/98
2014-07-02 21:22:17 -07:00
Kohsuke Kawaguchi
62d9b92e6e Merge pull request #103 from rtyley/okhttp-2.0.0
Update to OkHttp 2.0.0, which has a new OkUrlFactory
2014-07-02 21:13:37 -07:00
Kohsuke Kawaguchi
d2c909584d Merge pull request #102 from jglick/clearer-FNFE
Better FNFE from delete()
2014-07-02 21:13:16 -07:00
Kohsuke Kawaguchi
219916eb14 Merge pull request #101 from farmdawgnation/final-answer
Un-finalize a handful of classes.
2014-07-02 21:12:59 -07:00
Roberto Tyley
0a37ac901f Update to OkHttp 2.0.0, which has a new OkUrlFactory
OkHttp changed API with v2.0.0, and the `client.open(url)` method no
longer exists:

"URLConnection support has moved to the okhttp-urlconnection module.
If you're upgrading from 1.x, this change will impact you. You will
need to add the okhttp-urlconnection module to your project and use
the OkUrlFactory to create new instances of HttpURLConnection"

https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-200-rc1
2014-06-28 11:12:25 +01:00
Jesse Glick
4586baea27 Explain what a FNFE from delete() may just mean your token is lacking delete_repo. 2014-06-24 10:38:13 -04:00
Matt Farmer
d83961e85b Un-finalize a handful of classes. 2014-06-14 19:34:42 -04:00
Kohsuke Kawaguchi
7e35716ff0 [maven-release-plugin] prepare for next development iteration 2014-06-08 10:37:21 -07:00
Kohsuke Kawaguchi
d0cf1ac605 [maven-release-plugin] prepare release github-api-1.55 2014-06-08 10:37:17 -07:00
Kohsuke Kawaguchi
9a19d07ab8 I'm getting "the key is already in use" error.
Creating a new thro-away key
2014-06-08 10:36:05 -07:00
Kohsuke Kawaguchi
922be0b164 make sure the key gets deleted no matter what 2014-06-08 10:31:15 -07:00
Kohsuke Kawaguchi
d0b8e2e37e Merge pull request #97 from suryagaddipati/add_context_to_commit_status
Add support for adding context to commit status.
2014-06-08 10:21:43 -07:00
Surya Gaddipati
e3d6e08b6a Preserve api compatablity with previous version.
Support adding commitstatus without context.
2014-06-07 14:43:09 -05:00
Surya Gaddipati
16a6623095 Add support for adding context to commit status.
This groups statuses from multiple contexts to return single combined
status. More information here:
https://developer.github.com/changes/2014-03-27-combined-status-api/
2014-06-07 14:29:25 -05:00
Kohsuke Kawaguchi
7bf31ca149 [maven-release-plugin] prepare for next development iteration 2014-06-05 10:30:01 -07:00
Kohsuke Kawaguchi
030f2360ca [maven-release-plugin] prepare release github-api-1.54 2014-06-05 10:29:56 -07:00
Kohsuke Kawaguchi
08eafc4214 Merge pull request #94 from suryagaddipati/master
Add support for adding deploykeys to repo
2014-06-05 10:28:19 -07:00
Kohsuke Kawaguchi
134ece9385 Merge pull request #95 from suryagaddipati/ghref
Add support for retriving a single ref
2014-06-05 10:27:42 -07:00
Surya Gaddipati
3e4b06e959 Add support for retriving a single ref
Implements the following api method
https://developer.github.com/v3/git/refs/#get-a-reference
2014-06-04 15:11:27 -05:00
Surya Gaddipati
3e3c6f70ba Add support for adding deploykeys to repo
Implements https://developer.github.com/v3/repos/keys/
2014-06-03 15:26:04 -05:00
Kohsuke Kawaguchi
3097378a10 Merge pull request #93 from vr100/master
Upgrading to 1.12 version for bridge-method-annotation and bridge-method-injector - fix for #91
2014-05-28 20:52:07 -07:00
vr100
53f7a0f78a Upgrading to 1.12 version for bridge-method-annotation and bridge-method-injector - fix for #91 2014-05-28 12:41:19 +05:30
Kohsuke Kawaguchi
45a6841772 added a method to visit sub-directory 2014-05-27 20:57:42 -07:00
Kohsuke Kawaguchi
80b93a6e33 doc improvement 2014-05-27 20:44:44 -07:00
Kohsuke Kawaguchi
6aaab641be Using the latest 2014-05-10 15:57:56 -07:00
Kohsuke Kawaguchi
4999490c06 [maven-release-plugin] prepare for next development iteration 2014-05-10 15:52:17 -07:00
Kohsuke Kawaguchi
c7c1cd8bb3 [maven-release-plugin] prepare release github-api-1.53 2014-05-10 15:52:12 -07:00
Kohsuke Kawaguchi
8a1f116305 Renamed to avoid colliding with LifecycleTest 2014-05-10 15:49:31 -07:00
Kohsuke Kawaguchi
f8fe1dda6d Presence check needs to run on the same repo 2014-05-10 15:46:14 -07:00
Kohsuke Kawaguchi
bf44232d5c Updated test case 2014-05-10 15:43:15 -07:00
Kohsuke Kawaguchi
8c8ba47ef9 Fork into an org to simplify access control 2014-05-10 15:38:13 -07:00
Kohsuke Kawaguchi
b3580002d0 doc improvement 2014-05-10 15:37:21 -07:00
Kohsuke Kawaguchi
1249199b22 push fails with HTTPS 2014-05-10 15:34:57 -07:00
Kohsuke Kawaguchi
f39a47f354 This test seems to fail randomly 2014-05-10 15:32:58 -07:00
Kohsuke Kawaguchi
f58f15925f Fake a big rate limit
This fixes issue #78
2014-05-10 15:30:33 -07:00
Kohsuke Kawaguchi
a071f8bb86 Exposed more endpoints.
This fixes issue #64.
2014-05-10 15:21:59 -07:00
Kohsuke Kawaguchi
d33609ee57 Make sure getRepositories() for the user himself returns private repositories
This fixes issue #88
2014-05-10 15:16:12 -07:00
Kohsuke Kawaguchi
f2c08bc1e8 Added ability to create a pull request.
This fixes issue #79.
2014-05-10 15:05:48 -07:00
Kohsuke Kawaguchi
688d8ed7bc Added databinding for files 2014-05-10 14:11:41 -07:00
Kohsuke Kawaguchi
2ddb4018b8 added data binding for a file in gist 2014-05-10 14:07:53 -07:00
Kohsuke Kawaguchi
3ec25683f7 doc improvement 2014-05-10 14:03:49 -07:00
Kohsuke Kawaguchi
25d426f483 Bug fix based on tests 2014-05-10 14:03:12 -07:00
Kohsuke Kawaguchi
9d91ebc47a Not sure why tests weren't in the right package 2014-05-10 13:53:13 -07:00
Kohsuke Kawaguchi
c784ab6632 Added Gist support 2014-05-10 13:52:36 -07:00
Kohsuke Kawaguchi
ed5e3f13a1 exposed via getter.
This fixes issue #52.
2014-05-10 13:25:33 -07:00
Kohsuke Kawaguchi
3dcd82745e Resolved issue #54 2014-05-10 12:52:00 -07:00
Kohsuke Kawaguchi
c564dc5f29 All tests should use the secondary account 2014-05-10 12:47:28 -07:00
Kohsuke Kawaguchi
d64453b661 Fixing tests 2014-05-10 12:44:52 -07:00
Kohsuke Kawaguchi
834ed7db0e Merge branch 'pull-84' 2014-05-10 12:42:34 -07:00
Kohsuke Kawaguchi
db1dde533f Updated tests to use a separate account 2014-05-10 12:42:19 -07:00
Kohsuke Kawaguchi
9c66d9465e Added removal of release 2014-05-10 12:27:18 -07:00
Kohsuke Kawaguchi
8c193d004e Updated test cases to reflect my changes 2014-05-10 12:11:20 -07:00
Kohsuke Kawaguchi
7cbd7f999a Pointless to define a builder that doesn't take parameters 2014-05-10 12:08:17 -07:00
Kohsuke Kawaguchi
4340c8cb00 Support pagination in releases just like tags 2014-05-10 12:00:44 -07:00
Kohsuke Kawaguchi
6f6583772d Should support pagination 2014-05-10 11:59:46 -07:00
Kohsuke Kawaguchi
c62bc8d5da subsumed by GHRepository.queryCommits() 2014-05-10 11:58:22 -07:00
Kohsuke Kawaguchi
f68bfcb3e2 [maven-release-plugin] prepare for next development iteration 2014-05-09 18:39:33 -07:00
Kohsuke Kawaguchi
a37ade13cd [maven-release-plugin] prepare release github-api-1.52 2014-05-09 18:39:29 -07:00
Kohsuke Kawaguchi
1e0129f2d8 A few more properties while we are at it 2014-05-09 18:36:46 -07:00
Kohsuke Kawaguchi
2e1d4381b0 looks like this property was renamed 2014-05-09 18:34:51 -07:00
Kohsuke Kawaguchi
a409b4f49c Merge branch 'pull-86'
Conflicts:
	src/main/java/org/kohsuke/github/GHOrganization.java
	src/main/java/org/kohsuke/github/Requester.java
	src/test/java/org/kohsuke/AppTest.java
2014-05-09 18:30:59 -07:00
Kohsuke Kawaguchi
926776204b Implemented the builder pattern to my liking 2014-05-09 18:28:34 -07:00
Kohsuke Kawaguchi
bba490127d Merge branch 'pull-87' 2014-05-09 17:59:30 -07:00
Kohsuke Kawaguchi
80672c43c0 Restored backward compatibility 2014-05-09 17:59:22 -07:00
Kohsuke Kawaguchi
926e0ea0e5 added more tests.
Looks like org APIs only work for owners of the org
2014-05-09 17:55:53 -07:00
Kohsuke Kawaguchi
6da169cd56 a convenience method 2014-05-09 17:54:24 -07:00
Kohsuke Kawaguchi
aaf10aa118 added a test 2014-05-09 17:53:08 -07:00
Kohsuke Kawaguchi
145bdacf13 Added a method to list up teams 2014-05-09 17:50:19 -07:00
Kohsuke Kawaguchi
51309efd46 Graceful error handling 2014-05-09 17:43:27 -07:00
Kohsuke Kawaguchi
60fe143b07 detect the common problem
If the caller tries to parse a pull event into a pull_request event, we'd choke with NPE. This change avoids that.
2014-04-30 13:27:37 -07:00
Kelly Campbell
3f921b69f6 Fix bug in GHMyself.getEmails due to API change 2014-04-25 22:55:45 -04:00
vr100
d2ac81d7ba Using builder pattern to list commits in a repo 2014-04-23 09:45:11 +05:30
Francois Berthault
2e5a9479a8 create a Release & Branch 2014-04-21 10:45:10 +02:00
Kohsuke Kawaguchi
ec664ab6a2 Merge pull request #83 from antonkrasov/master
add tarball_url and zipball_url to GHRelease
2014-04-19 11:50:39 -07:00
Anton Krasov
8818bf8cf0 add tarball_url and zipball_url to GHRelease 2014-04-18 17:28:51 +03:00
Kohsuke Kawaguchi
cc53e0c8ff [maven-release-plugin] prepare for next development iteration 2014-04-13 08:58:53 -07:00
Kohsuke Kawaguchi
8353499d18 [maven-release-plugin] prepare release github-api-1.51 2014-04-13 08:58:49 -07:00
Kohsuke Kawaguchi
d2c5994616 I always get this confused 2014-04-13 08:57:48 -07:00
Kohsuke Kawaguchi
500b9097f7 doc improvement 2014-04-13 08:53:00 -07:00
Kohsuke Kawaguchi
7993266e6e This is also useful for setting timeout 2014-04-13 08:51:58 -07:00
Kohsuke Kawaguchi
74090103a9 doc improvement 2014-04-13 08:48:16 -07:00
Kohsuke Kawaguchi
a18cde2340 Abstracted away HTTP connector and added OkHttp implementation for convenience 2014-04-13 08:46:21 -07:00
Kohsuke Kawaguchi
ee98e97876 Merge pull request #80 from rtyley/remove-member-of-org
Add support for removing a user from an Organisation
2014-04-13 08:22:23 -07:00
Kohsuke Kawaguchi
ff63bafd72 Merge pull request #82 from prazanna/master
Cast url.openConnection() to HttpURLConnection instead of HttpsURLConnec...
2014-04-13 08:22:00 -07:00
Prasanna Rajaperumal
3f8c8be77a Cast url.openConnection() to HttpURLConnection instead of HttpsURLConnection. Useful for enterprise githubs which does not have https set up. 2014-04-09 18:13:10 -07:00
Roberto Tyley
769cdc73e7 Add support for removing a user from an Organisation 2014-04-02 18:47:50 +01:00
Kohsuke Kawaguchi
cef8f74c00 Added LICENSE 2014-04-02 09:31:02 -07:00
Kohsuke Kawaguchi
9f5ab709de [maven-release-plugin] prepare for next development iteration 2014-03-28 10:59:51 -07:00
Kohsuke Kawaguchi
c6fdae3b3c [maven-release-plugin] prepare release github-api-1.50 2014-03-28 10:59:47 -07:00
Kohsuke Kawaguchi
320cf0fea2 Seeing a failure to create 2014-03-28 10:58:41 -07:00
Kohsuke Kawaguchi
0261f1262f fixed a test case 2014-03-28 10:58:41 -07:00
Kohsuke Kawaguchi
5278ae3662 Merge pull request #75 from rtyley/check-team-membership
Support the check-user-team-membership API call
2014-03-28 10:24:18 -07:00
Kohsuke Kawaguchi
2941c44de2 Merge pull request #73 from rtyley/fix-issue-labels-setter
Fix GHIssue.setLabels()
2014-03-28 10:23:15 -07:00
Kohsuke Kawaguchi
627222602e Merge pull request #72 from farmdawgnation/patch-1
Un-finalize GHContent.
2014-03-28 10:23:03 -07:00
Kohsuke Kawaguchi
e13b1ffc48 looks like the 'tire' repository is gone 2014-03-28 10:11:15 -07:00
Kohsuke Kawaguchi
10bafce217 fixed a test 2014-03-28 10:08:08 -07:00
Kohsuke Kawaguchi
4817969495 fixed a broken test 2014-03-28 10:06:50 -07:00
Kohsuke Kawaguchi
2feda55eb7 looks like we need to pick another user here 2014-03-28 10:01:59 -07:00
Kohsuke Kawaguchi
a74cfd453a Added support for getting issues by milestone and state.
rework AppTest to work better for people other than kohsuke

This patch was originally from @evanchooly. Reworked to avoid whitespace
changes.
2014-03-28 09:57:04 -07:00
Kohsuke Kawaguchi
a360f65133 merging a portion of pull request #70 2014-03-28 09:49:38 -07:00
Kohsuke Kawaguchi
6a903d65a7 Fixed a bug in the databinding of the 'private' field.
Luca pointed out this bug in
ae7a616e92
2014-03-28 09:47:27 -07:00
Kohsuke Kawaguchi
d4b3166036 Merge branch 'pull-69' 2014-03-28 09:42:00 -07:00
Kohsuke Kawaguchi
21a54e2333 The parent commit appears to be totally untested.
The placement of the method makes no sense, and the API route is wrong.
The parameter is missing, and the expected response type is wrong.
2014-03-28 09:40:55 -07:00
Kohsuke Kawaguchi
37c58bffba indentation fix 2014-03-28 09:37:11 -07:00
Kohsuke Kawaguchi
4a42b7277c Merge branch 'pull-76' 2014-03-28 09:35:43 -07:00
Kohsuke Kawaguchi
071aea397b Keep the original signature intact for backward compatibility 2014-03-28 09:35:37 -07:00
vr100
9c02f918c1 In order to handle http based github enterprise vm url, changing https to http 2014-03-26 09:23:26 +05:30
vr100
15c5c9615e Added pagesize parameter to 'Get commits by author and branch' api 2014-03-20 15:00:34 +05:30
vr100
0b74692d62 change in comment 2014-03-19 11:38:03 +05:30
vr100
8f24f55eb7 Added apis to list commits by author and list the repos of an organization (including the private ones) 2014-03-19 11:06:11 +05:30
Kohsuke Kawaguchi
cd5ab1ae9b need to populate enum 2014-03-18 11:52:00 -07:00
Roberto Tyley
d29ea97948 Fix org.getMembers() to 'wrap' returned users for post-populating
This fixes an issue introduced with PR #66 in commit fee02a3d16 - the
`getMembers()` method switched to using paging, but lost the code that
populated the users with a full set of values.

This commit just applies 'wrapping' to all users returned, so that methods
like `user.getCreatedAt()` can be called on returned users without throwing
a NullPointerException - the reference to 'root' allows the user objects to
populate themselves.
2014-03-14 09:22:15 +00:00
Roberto Tyley
9930e7bb93 Add org public-members call, to complement the full members list
http://developer.github.com/v3/orgs/members/#public-members-list
2014-03-13 22:04:45 +00:00
Roberto Tyley
b1d37e4848 Support the check-user-team-membership API call
http://developer.github.com/v3/orgs/teams/#get-team-member
2014-03-12 21:46:14 +00:00
Roberto Tyley
893152cdf3 Fix GHIssue.setLabels() - *don't* set 'assignee' instead! 2014-03-08 16:05:33 +00:00
Matt Farmer
efbf98751d Un-finalize GHContent.
GHContent was declared as a final class, which makes it impossible to mock with libraries like Mockito.
2014-03-07 22:14:21 -05:00
Luca Milanesio
caac294e79 BugFix when listing repositories of a GitHub Organisation
Repositories of a GitHub Organisation are under 
/orgs/:org/repos as documented at:
http://developer.github.com/v3/repos/#list-organization-repositories

We need then to override the GHPerson implementation
which would have just returned the user's repositories.
2014-02-28 17:45:36 +00:00
vanjikumaran
d145ad8f47 Created new method to automate the merge 2014-02-24 17:00:11 +05:30
lindseydew
628034ae8c add a filter param to the get members method 2014-02-11 18:07:01 +00:00
Ryan Kennedy
fee02a3d16 Support paging when fetching organization members
Organization members are a paged list in the V3 GitHub API. Previously the code would fetch only the first page of ~30 members and return that. This change switches the return to a PagedIterable<GHUser> so clients can fetch the entire organization's member list.
2014-01-22 09:56:06 -08:00
Kohsuke Kawaguchi
ce5ae13bf6 [maven-release-plugin] prepare for next development iteration 2014-01-06 08:56:38 -08:00
Kohsuke Kawaguchi
26b6a94e32 [maven-release-plugin] prepare release github-api-1.49 2014-01-06 08:56:34 -08:00
Kohsuke Kawaguchi
be6ef475ba [maven-release-plugin] prepare for next development iteration 2014-01-06 08:52:00 -08:00
Kohsuke Kawaguchi
55e218ac37 [maven-release-plugin] prepare release github-api-1.48 2014-01-06 08:51:56 -08:00
Kohsuke Kawaguchi
7d1f636cdd Recover from earlier test failures 2014-01-01 21:12:17 -08:00
Kohsuke Kawaguchi
a4b8b9b09b Merge pull request #61 from lucamilanesio/master
Fetching of user's verified keys through standard OAuth scope.
2014-01-01 15:26:58 -08:00
Kohsuke Kawaguchi
4e8e28d27c Merge pull request #59 from farmdawgnation/contents-api
Contents API
2014-01-01 15:26:23 -08:00
Luca Milanesio
4b52414435 Fetching of user's verified keys through standard OAuth scope.
Allow the fetching of a user's verified key list without
requiring to have an OAuth user scope (which implies
user's profile READ/WRITE permissions).
This would relax the requirements of GitHub OAuth scope
when fetching public information such as their SSH
public keys.
2013-12-11 00:30:27 +00:00
Matt Farmer
811b96bcbe Implement the ability to retrieve content from a particular ref. 2013-11-28 10:02:37 -05:00
Matt Farmer
f3207855ca Implement a CRUD integration test for the content api. 2013-11-28 09:45:54 -05:00
Matt Farmer
9f3c5b93e3 Store encoded content in class level variable on update. 2013-11-28 09:45:21 -05:00
Matt Farmer
a56357f0c1 Implement the ability to retrieve conent if not populated.
The create and update API calls don't send back the content you just
sent, so that field is null. If this GHContent was instantiated from one
of those calls, we want to make sure we can retrieve the content (and
updated sha, etc) on the fly.
2013-11-28 09:44:27 -05:00
Matt Farmer
f8d14d2e56 Implement the ability to delete content. 2013-11-28 00:37:40 -05:00
Matt Farmer
b0c30759c8 Properly wrap content on directory listing retrieval. 2013-11-28 00:33:07 -05:00
Matt Farmer
54037e6e10 Add the ability to specify a branch name with GHContent updates. 2013-11-28 00:29:49 -05:00
Matt Farmer
fc260d4a37 Implement the ability to create content via content api. 2013-11-28 00:21:25 -05:00
Matt Farmer
387d4e5bc9 Return the new GHContentUpdateResponse from content changes. 2013-11-28 00:12:30 -05:00
Matt Farmer
4ffd46b391 Implement the ability to update existing content. 2013-11-28 00:03:43 -05:00
Matt Farmer
3b49370c06 Add the ability to retrieve the sha of the content. 2013-11-27 23:28:40 -05:00
Alexandre COLLIGNON
925d26e54c Add GitHub Contents API read methods 2013-11-27 22:35:41 -05:00
Kohsuke Kawaguchi
1283006b53 [maven-release-plugin] prepare for next development iteration 2013-11-27 11:57:40 -08:00
Kohsuke Kawaguchi
83a718c9db [maven-release-plugin] prepare release github-api-1.47 2013-11-27 11:57:35 -08:00
Kohsuke Kawaguchi
2abf03ccb7 Minor doc improvement 2013-11-27 11:52:47 -08:00
Kohsuke Kawaguchi
a59810a487 Merge pull request #56 from endeavor85/master
Use `PagedIterator<GHIssue>` to retrieve repository issues
2013-11-27 11:49:44 -08:00
Kohsuke Kawaguchi
9cc9e06ad1 Merge pull request #58 from rtholmes/master
Add support for PULL_REQUEST_REVIEW_COMMENT event types.
2013-11-27 11:49:17 -08:00
reid holmes
0108a0c146 Add support for PULL_REQUEST_REVIEW_COMMENT event types. 2013-11-26 15:13:36 -05:00
endeavor85
4188758d84 Use PagedIterator<GHIssue> to retrieve repository issues. Overcomes
default 30 item page size limit.
2013-11-24 02:54:18 -06:00
Kohsuke Kawaguchi
2144100f81 [maven-release-plugin] prepare for next development iteration 2013-11-13 13:05:29 -08:00
Kohsuke Kawaguchi
8a61e04be6 [maven-release-plugin] prepare release github-api-1.46 2013-11-13 13:05:24 -08:00
Kohsuke Kawaguchi
eaeb083891 Perhaps this will help resolve? 2013-11-12 13:13:18 -08:00
Kohsuke Kawaguchi
25e117b412 oops 2013-11-12 12:47:37 -08:00
Kohsuke Kawaguchi
6b7ceed1a5 Short cut 2013-11-12 12:45:39 -08:00
Kohsuke Kawaguchi
0533fc98a2 bumped up to a newer version 2013-11-12 12:21:17 -08:00
Kohsuke Kawaguchi
edde3ab2fb added one more field based on observations 2013-11-12 12:17:57 -08:00
Kohsuke Kawaguchi
ec20e518be adding a new payload implementation for PushEvent 2013-11-12 12:14:34 -08:00
Kohsuke Kawaguchi
930a582afa Unified various different instances of the "author" class 2013-11-12 12:10:33 -08:00
Kohsuke Kawaguchi
7536eeea54 V2 code no longer needed 2013-11-12 12:01:49 -08:00
Kohsuke Kawaguchi
d940d43907 added more event support 2013-11-12 11:52:40 -08:00
Kohsuke Kawaguchi
3ad3dd9493 [maven-release-plugin] prepare for next development iteration 2013-11-09 15:19:27 -08:00
Kohsuke Kawaguchi
553df7ac85 [maven-release-plugin] prepare release github-api-1.45 2013-11-09 15:19:23 -08:00
Kohsuke Kawaguchi
9648602252 Merge branch 'pull-51' 2013-11-09 15:17:21 -08:00
Kohsuke Kawaguchi
63d0d13330 Better and more secure to use OAuth. 2013-11-09 15:17:01 -08:00
Kohsuke Kawaguchi
ff9b538a49 doc touch up 2013-11-09 15:11:02 -08:00
Kohsuke Kawaguchi
6632da34c0 this dependency is for testing 2013-11-09 15:08:07 -08:00
evanchooly
178c9ff4d0 add support (most of) the release-related endpoints 2013-11-04 20:08:24 -05:00
Kohsuke Kawaguchi
bfefeae5c1 Merged pull request #45 with some changes 2013-11-02 18:15:31 -07:00
Kohsuke Kawaguchi
ebf953cbc4 Massaging the pull request.
- GHPerson really should be an abstract class
- static listPullRequests method does not fit the design of this
  library, although I'm very sympathetic as to why Luca wanted to do it.
  Nonetheless I'm removing this in favor of the lazy loading of the
  state to avoid unnecessary calls in the future.
2013-11-02 18:13:40 -07:00
Luca Milanesio
19ec3321ae Gets commit details of a pull request.
Retrieves the list of commits included in the pull request.
Commit object returned is not a full GHCommit and includes
just a small subset of information.
2013-10-09 16:59:18 +01:00
Kohsuke Kawaguchi
d82af9f1a0 Merge pull request #50 from pescuma/jackson
Updates Jackson to 2.2.3
2013-10-02 08:31:42 -07:00
Ricardo Pescuma Domenecci
4712d2c8ac Using version 2 of jackson 2013-09-28 14:25:23 -03:00
Ricardo Pescuma Domenecci
a2df4217fd Updated issue label with ifts fields 2013-09-28 12:43:01 -03:00
Luca Milanesio
096c96550b Allows fetching pull requests by knowing repo-name and owner. 2013-09-27 09:18:22 +01:00
Luca Milanesio
2fb3f31930 GHRepository owner is NOT a GHUser but more generically a GHPerson.
When GitHub repositories are associated to organisations,
the owner is NOT the user but the org itself.
2013-09-27 09:12:54 +01:00
Luca Milanesio
f52b4a2e11 Allows to define page size for repository lists.
Extension of the listRepositories() with the desired
pageSize. This allows to reduce the number of calls
to GitHub API for fetching the entire set of repositories
browsing all the pages.

Additionally allows to match the UX paging with the
underlying GitHub API paging, increasing performance
and reducing hourly API allowance.
2013-09-16 00:41:10 +01:00
Kohsuke Kawaguchi
bbc78ffec6 [maven-release-plugin] prepare for next development iteration 2013-09-07 13:32:24 +01:00
Kohsuke Kawaguchi
3606f412b3 [maven-release-plugin] prepare release github-api-1.44 2013-09-07 13:32:15 +01:00
Kohsuke Kawaguchi
6e0e94094b Massaging the changes 2013-09-07 13:29:23 +01:00
Kohsuke Kawaguchi
976960f495 Merge pull request #42 from paulbutenko/master
Commit's short info model
2013-09-07 05:25:58 -07:00
Kohsuke Kawaguchi
d2f2f3b2d3 Merge pull request #44 from stephenc/is-anonymous
Provide a way to determine if the connection is anonymous
2013-09-07 05:18:29 -07:00
Kohsuke Kawaguchi
2da7c45840 Merge pull request #43 from stephenc/master
GHMyself should allow accessing the private repos and orgs too
2013-09-07 05:18:00 -07:00
Stephen Connolly
fb078de627 Provide a way to determine if the connection is anonymous 2013-08-29 14:33:04 +01:00
Stephen Connolly
da46b7fddb GHMyself should allow accessing the private repos and orgs too 2013-08-29 14:29:58 +01:00
Paul Butenko
c4e0729b7d GHCOmpare reverted, getCommit changed to getCommitShortInfo 2013-08-17 01:09:55 +03:00
Paul Butenko
eee9f0ace5 Original formating restored 2013-08-17 00:48:42 +03:00
Paul Butenko
d0692458a3 New model for short info of the commit was added 2013-08-17 00:41:45 +03:00
Kohsuke Kawaguchi
c96e6c7c92 [maven-release-plugin] prepare for next development iteration 2013-07-06 22:26:45 -07:00
Kohsuke Kawaguchi
4956278f17 [maven-release-plugin] prepare release github-api-1.43 2013-07-06 22:26:39 -07:00
Kohsuke Kawaguchi
5858a86624 using the latest 2013-07-06 22:24:21 -07:00
Kohsuke Kawaguchi
c87d178a6a added a method that matches the convention elsewhere. 2013-07-06 17:49:56 -07:00
Kohsuke Kawaguchi
6fc872b1fd this is no longer efficient 2013-07-06 17:49:46 -07:00
Kohsuke Kawaguchi
589c5783a0 "myself" only makes sense when there's a credential 2013-05-24 12:01:56 -07:00
Kohsuke Kawaguchi
40165628d6 [maven-release-plugin] prepare for next development iteration 2013-05-07 11:09:20 -07:00
Kohsuke Kawaguchi
435be77249 [maven-release-plugin] prepare release github-api-1.42 2013-05-07 11:09:13 -07:00
Kohsuke Kawaguchi
b932ba856d fixed NPE 2013-05-07 11:07:12 -07:00
Kohsuke Kawaguchi
094514f617 Merge pull request #36 from spiffxp/require-credentials-fix
Allow oauthToken to be used without login
2013-05-06 14:34:06 -07:00
Kohsuke Kawaguchi
fab96879d0 Merge pull request #37 from spiffxp/pr-comments-fix
Force issues-based API route for PR comments
2013-05-06 14:33:29 -07:00
Kohsuke Kawaguchi
367a5f0c57 Merge pull request #38 from janinko/fixPullRequestPayload
add repository to Pull Request payload and wrap the PR with the repository
2013-05-06 14:32:11 -07:00
Honza Brázdil
0d2ecfbc67 add repository to Pull Request payload and wrap the PR with the repository 2013-05-02 18:11:40 +02:00
Aaron Crickenberger
5410ba3b1d Force issues-based API route for PR comments
pulls/:number/comments is used for review_comments
2013-05-01 13:59:45 -07:00
Aaron Crickenberger
716bfd4611 requireCredential should allow for oauthToken with no login 2013-04-30 15:41:08 -07:00
Kohsuke Kawaguchi
3830a58493 [maven-release-plugin] prepare for next development iteration 2013-04-23 10:30:54 -07:00
Kohsuke Kawaguchi
31d5cf6129 [maven-release-plugin] prepare release github-api-1.41 2013-04-23 10:30:48 -07:00
Kohsuke Kawaguchi
8c78d20e6e doc improvement 2013-04-23 10:25:57 -07:00
Kohsuke Kawaguchi
abe78cf0bb Formatting only changes 2013-04-23 10:20:07 -07:00
Kohsuke Kawaguchi
eeebfd5f04 added a little helper code that generates an OAuth token for ~/.github 2013-04-23 10:19:50 -07:00
Kohsuke Kawaguchi
5e3d3dd023 In fact there's no point in looking up the 'token' property since API token is no longer supported by GitHub 2013-04-23 10:05:45 -07:00
Kohsuke Kawaguchi
60175ebfad if the user name is available, pass that in and save a lookup 2013-04-23 10:05:06 -07:00
Kohsuke Kawaguchi
c6fafe453f Cleaned up the authentication part of the code 2013-04-23 10:04:20 -07:00
Kohsuke Kawaguchi
838ecd0dd8 Merge branch 'pull-33' 2013-04-23 09:40:37 -07:00
Kohsuke Kawaguchi
beec605e2c [FIXED issue #34] API route for pull requests uses 'pulls' 2013-04-23 09:28:00 -07:00
watsonian
da1405a060 Remove apiToken completely. 2013-04-20 11:58:52 -07:00
watsonian
e38eeae533 Update constructor to use OAuth tokens rather than API tokens. 2013-04-20 11:43:54 -07:00
watsonian
8442e7e326 Declare the exception type. 2013-04-19 17:10:29 -07:00
watsonian
e6c82e2003 Stop using deprecated API tokens for Enterprise.
Authentication by API token is deprecated and doesn't work anymore.
Instead, authentication should be done via OAuth token now.
2013-04-19 16:27:09 -07:00
Kohsuke Kawaguchi
c4de972c53 [maven-release-plugin] prepare for next development iteration 2013-04-16 12:30:34 -07:00
Kohsuke Kawaguchi
d2adbaec89 [maven-release-plugin] prepare release github-api-1.40 2013-04-16 12:30:28 -07:00
Kohsuke Kawaguchi
72736588c9 release botched because of the Nexus staging deployer. rolling back to the parent POM 4 2013-04-16 12:28:38 -07:00
Kohsuke Kawaguchi
46e726363a [maven-release-plugin] prepare for next development iteration 2013-04-16 12:22:26 -07:00
Kohsuke Kawaguchi
f7e5292b8c [maven-release-plugin] prepare release github-api-1.39 2013-04-16 12:22:20 -07:00
Kohsuke Kawaguchi
f67954fa3e Merge branch 'pull-32' 2013-04-16 12:19:33 -07:00
Kohsuke Kawaguchi
ba6c6a17ae doc improvement 2013-04-16 12:18:50 -07:00
Kohsuke Kawaguchi
c21d61a70d TAB -> WS 2013-04-16 12:17:30 -07:00
Kohsuke Kawaguchi
df857d3a84 doc improvement 2013-04-16 12:14:06 -07:00
Honza Brázdil
e9564f101b implement retrieving of access token 2013-04-14 05:50:11 +02:00
Honza Brázdil
e8a2a69649 Implement GHEventPayload.IssueComment 2013-04-13 17:09:03 +02:00
Kohsuke Kawaguchi
ba416b1294 [maven-release-plugin] prepare for next development iteration 2013-04-06 19:06:44 -07:00
Kohsuke Kawaguchi
3024b598ad [maven-release-plugin] prepare release github-api-1.38 2013-04-06 19:06:37 -07:00
Kohsuke Kawaguchi
5ac7a34a13 using a newer POM 2013-04-06 19:03:47 -07:00
Kohsuke Kawaguchi
b63181d9b5 need to finish the initialization 2013-04-06 13:56:04 -07:00
Kohsuke Kawaguchi
a3119e2cc7 [maven-release-plugin] prepare for next development iteration 2013-03-14 19:06:11 -07:00
Kohsuke Kawaguchi
e8b8971b72 [maven-release-plugin] prepare release github-api-1.37 2013-03-14 19:06:05 -07:00
Kohsuke Kawaguchi
d5f5fa0e0a doc improvement 2013-03-14 19:02:05 -07:00
Kohsuke Kawaguchi
c284f90a1a adding some more type-safe overloads 2013-03-14 18:56:37 -07:00
Michael Clarke
349df60ce8 Adding in support for the refs command and filters in the API 2013-02-15 23:55:04 +00:00
Michael Clarke
5ccc3f4ccd Adding in support for the compare command in the API 2013-02-15 09:43:27 +00:00
johnou
8ba61bb3a6 Revert 2ef5dec466 and add source encoding to deter build warnings. 2013-01-24 17:31:43 +01:00
Johno Crawford
cb3d413e5e [maven-release-plugin] prepare for next development iteration 2013-01-24 17:23:07 +01:00
Johno Crawford
1837699d8c [maven-release-plugin] prepare release github-api-1.36 2013-01-24 17:22:58 +01:00
johnou
2ef5dec466 Temporary change for release. 2013-01-24 17:20:16 +01:00
Johno Crawford
a46c7acbd2 Merge branch 'master' of github.com:kohsuke/github-api 2013-01-24 16:58:42 +01:00
johnou
769d645237 Normalize api url for oauth constructor. 2013-01-24 16:57:51 +01:00
Kohsuke Kawaguchi
389330df2e [maven-release-plugin] prepare for next development iteration 2013-01-06 16:47:29 -08:00
Kohsuke Kawaguchi
9d75913005 [maven-release-plugin] prepare release github-api-1.35 2013-01-06 16:47:24 -08:00
Kohsuke Kawaguchi
887ca772e0 switching to Markdown 2013-01-06 16:45:17 -08:00
Kohsuke Kawaguchi
45286598aa adding OAuth support in ~/.github 2013-01-06 16:43:43 -08:00
Kohsuke Kawaguchi
2e074b5bc4 follow up fix to the pull request #28 2013-01-06 16:25:02 -08:00
Johno Crawford
560e3c257a Refactored test. 2013-01-06 16:25:02 -08:00
Johno Crawford
6e0202fa0b Added membership checks. 2013-01-06 16:25:01 -08:00
Kohsuke Kawaguchi
ef241b1a07 Merge pull request #27 from johnou/deprecated-password
Password is no longer required for api usage and fix for broken base64 encoding.
2013-01-06 16:14:15 -08:00
Johno Crawford
f80cb541d5 Fix base64 encoding. 2013-01-06 21:11:19 +01:00
Johno Crawford
1fe61f72e2 Password is no longer required for api usage. 2013-01-06 13:08:41 +01:00
Jerome Lacoste
bf1b0edfd2 Merge pull request #26 from johnou/remove-webclient
Removed web client and proprietary api usage.
2013-01-06 00:34:15 -08:00
johnou
f0ab946b88 Removed proprietary api usage. 2013-01-06 04:27:18 +01:00
Johno Crawford
975ef1a43d Removed last traces of web client. 2013-01-06 04:06:55 +01:00
Kohsuke Kawaguchi
7064865157 [maven-release-plugin] prepare for next development iteration 2013-01-05 17:18:17 -08:00
Kohsuke Kawaguchi
3dd738b0db [maven-release-plugin] prepare release github-api-1.34 2013-01-05 17:18:11 -08:00
Kohsuke Kawaguchi
6480dde247 oops test failures 2013-01-05 17:15:46 -08:00
Kohsuke Kawaguchi
555dab7403 Merge branch 'pull-22' 2013-01-05 17:11:58 -08:00
Kohsuke Kawaguchi
13158a28e1 turns out we never exposed the ability to specify the custom URL.
So no backward compatibility provision is needed.
Also in this change, I stopped exposin the password. See the code comment for more details
2013-01-05 17:10:24 -08:00
Kohsuke Kawaguchi
cbaca87bbc massaging this a bit to accept the full URL 2013-01-05 16:08:42 -08:00
Kohsuke Kawaguchi
5166202f67 follow-up fix and documenting the expected value 2013-01-05 15:59:02 -08:00
johnou
35d45ca47d JENKINS-13726: Github plugin should work with Guthub enterprise by allowing for overriding the github URL. 2013-01-06 00:47:44 +01:00
Honza Brázdil
b66ede98c7 Retrieve repository directly. 2012-10-20 23:24:56 +02:00
Kohsuke Kawaguchi
1ba8f2ccbf Update pom.xml
Added <repository> definition
2012-10-17 07:45:15 -07:00
Kohsuke Kawaguchi
82133c117a [maven-release-plugin] prepare for next development iteration 2012-09-13 16:31:58 -07:00
Kohsuke Kawaguchi
f71afca828 [maven-release-plugin] prepare release github-api-1.33 2012-09-13 16:31:52 -07:00
Kohsuke Kawaguchi
87f5231c9a updated a test 2012-09-13 16:28:50 -07:00
Kohsuke Kawaguchi
b17f506c20 clean up 2012-09-13 16:23:57 -07:00
Kohsuke Kawaguchi
7f15f12668 completed code to create a new issue 2012-09-13 16:23:06 -07:00
Kohsuke Kawaguchi
e53e62bfa0 added code to create a new issue 2012-09-13 15:56:05 -07:00
Kohsuke Kawaguchi
2e74517a4a fixed issue #20
PagedIterator is updated to cope with the base iterator returning array of length 0
2012-09-13 15:46:25 -07:00
Kohsuke Kawaguchi
aed888051e added a method to retrieve a single issue 2012-09-13 15:36:32 -07:00
Kohsuke Kawaguchi
bd584124bb Merge pull request #19 from janinko/Issues-19-PagedIterable_dosnt_use_authentication
PagedIterable dosn't use authentication
2012-09-13 15:32:56 -07:00
Honza Brázdil
e658a7fa6b send authentication header on all requests 2012-09-12 18:04:59 +02:00
Kohsuke Kawaguchi
52108707bb Merge pull request #18 from janinko/patch-1
When using lazy population, this is not deprecated
2012-09-07 09:52:12 -07:00
Honza Brázdil
0e226a8f78 When using lazy population, this is not deprecated 2012-09-06 14:23:51 +03:00
Kohsuke Kawaguchi
1bf3e025b8 [maven-release-plugin] prepare for next development iteration 2012-09-05 19:30:18 -07:00
Kohsuke Kawaguchi
a0fdcca129 [maven-release-plugin] prepare release github-api-1.32 2012-09-05 19:30:04 -07:00
Kohsuke Kawaguchi
3e75e96718 adding an assertion 2012-09-05 19:26:25 -07:00
Kohsuke Kawaguchi
1dd875adac adding lazy population to GHUser and got rid of GHSmallUser 2012-09-05 19:25:56 -07:00
Kohsuke Kawaguchi
2341f789ab Merge branch 'master' into pull-17 2012-09-05 19:13:32 -07:00
Kohsuke Kawaguchi
8a95847b0a Renaming to better represent what it does. 2012-09-05 19:13:10 -07:00
Kohsuke Kawaguchi
ea9f3eacbc bug fix 2012-09-05 19:12:18 -07:00
Kohsuke Kawaguchi
435363a246 moved the pagenation API over to Poster 2012-09-05 19:08:29 -07:00
Kohsuke Kawaguchi
b6520cb6f9 got rid of all retrieveXYZ methods in favor of Poster 2012-09-05 18:55:44 -07:00
Kohsuke Kawaguchi
d6d73f5165 A step toward using Poster in place of the retrieve* methods.
I was trying to add  the flavor of the retrieve method that reads into an existing instance, when I realized that there are just too many orthogonal axes here to rely on overloaded methods.

That calls for a builder pattern, which we already have --- it's called Poster, but it can actually already handle GET and other HTTP requests.

So I'm retiring the retrieveXYZ methods and moving the code into Poster. This is the first step.
2012-09-05 18:53:06 -07:00
Kohsuke Kawaguchi
f58dbceec7 Massaging the pull request.
In various places of the GitHub API, there's often a full object and
then there's a shallow object. I think the client API would be a lot
easier to use if a single class represents both and retrieve additional
fields on the fly as needed.
2012-09-05 18:15:29 -07:00
Kohsuke Kawaguchi
3f1bb1a214 completed the commit status API 2012-09-05 18:00:50 -07:00
Kohsuke Kawaguchi
892d2acaa2 Added the commit status API, first cut. 2012-09-04 10:40:32 -07:00
Honza Brázdil
4e27d1b5a0 method names should by camelCase 2012-08-31 15:31:41 +02:00
Honza Brázdil
fff3272e42 make url methods return URL and add getApiUrl 2012-08-31 15:27:06 +02:00
Honza Brázdil
803198620d Nested GHIssue.PullRequest must be static 2012-08-31 15:24:14 +02:00
Honza Brázdil
9017fe70d5 We need to preserve api 2012-08-31 14:50:08 +02:00
Honza Brázdil
ce47762fbf Added milestone attribute to GHIssue 2012-08-31 14:37:02 +02:00
Honza Brázdil
b40677a3ca changed return value of GHRepository.getPullRequest()
I'm not sure whether this influence something or not, but I think it should be OK.
2012-08-31 14:30:00 +02:00
Honza Brázdil
c283c4e595 added method retrieving detailed pull request 2012-08-31 14:23:48 +02:00
Honza Brázdil
6aabaea96c Clean up GHIssue and GHPullRequest and make them relevant to api v3.
Added SmallUser representing reference to user.
Added DetailedPullRequest - when retrieving pull request by id, it has more attributes then pull requests obtained by GHRepository.getPullRequests()
2012-08-31 12:37:00 +02:00
Kohsuke Kawaguchi
65adb2f2b4 [maven-release-plugin] prepare for next development iteration 2012-08-28 11:03:11 -07:00
Kohsuke Kawaguchi
dcaf926a95 [maven-release-plugin] prepare release github-api-1.31 2012-08-28 11:02:59 -07:00
Honza Brázdil
587278f282 we need to maintain the binary compatibility, so I reverted getComments and added listComments that exposes PagedIterable.
inspired by 8f95c4f179
2012-08-28 19:09:18 +02:00
Honza Brázdil
cc3793cbcd Comments are paged 2012-08-28 18:59:09 +02:00
Honza Brázdil
c268a5dd07 removed unused throws statement 2012-08-28 18:59:09 +02:00
Honza Brázdil
58d10df5e3 Fix GHIssue.getState() No enum constant 2012-08-28 18:59:09 +02:00
Honza Brázdil
ae2d01a878 fix GHPullRequest.getLabels() NPE 2012-08-28 18:59:09 +02:00
Honza Brázdil
dbc5b0b742 user is not just username; added url 2012-08-28 18:59:09 +02:00
Kohsuke Kawaguchi
6af12c2335 [maven-release-plugin] prepare for next development iteration 2012-08-28 09:43:22 -07:00
Kohsuke Kawaguchi
dafb50d6a9 [maven-release-plugin] prepare release github-api-1.30 2012-08-28 09:43:14 -07:00
Kohsuke Kawaguchi
13c59b6618 Merge branch 'pull-15' 2012-08-28 09:41:59 -07:00
Kohsuke Kawaguchi
8f95c4f179 Massaging the pull request 15.
- we need to maintain the binary compatibility, so I reverted
  getPullRequests and added listPullRequests that exposes PagedIterable.

- Made PagedIterator expose asList.
2012-08-28 09:39:49 -07:00
Aurélien Thieriot
9fd34aec7f Paging GHPullRequests getter and allow to transform iterator to a list 2012-08-12 13:01:42 +02:00
Kohsuke Kawaguchi
17c7a3e7c5 [maven-release-plugin] prepare for next development iteration 2012-06-18 12:51:29 -07:00
Kohsuke Kawaguchi
40a8c110bf [maven-release-plugin] prepare release github-api-1.29 2012-06-18 12:51:25 -07:00
Kohsuke Kawaguchi
c9cd0a4d1f added a simple CRUD test 2012-06-18 12:50:47 -07:00
Kohsuke Kawaguchi
45eae77f8f added missing repository delete operation 2012-06-18 12:50:40 -07:00
Kohsuke Kawaguchi
926202900c fixed a bug in editing the repository definition 2012-06-18 12:37:27 -07:00
Kohsuke Kawaguchi
21aa669503 redundant test case 2012-06-18 12:24:30 -07:00
Kohsuke Kawaguchi
dee28e7a7a Doc says this is asynchronous 2012-06-18 12:23:48 -07:00
Kohsuke Kawaguchi
c8f46a3666 needs to wrap up 2012-06-18 12:23:34 -07:00
Kohsuke Kawaguchi
ba7fe10a08 bug fix 2012-06-18 12:23:20 -07:00
Kohsuke Kawaguchi
9e9db72878 [maven-release-plugin] prepare for next development iteration 2012-06-13 08:27:58 -07:00
Kohsuke Kawaguchi
69a87e2ab7 [maven-release-plugin] prepare release github-api-1.28 2012-06-13 08:27:53 -07:00
Kohsuke Kawaguchi
8ec2686e72 getName() is null with shallow retrieval 2012-06-13 08:12:18 -07:00
Kohsuke Kawaguchi
d034ca4d1f removed unused V3 API 2012-06-13 08:10:01 -07:00
Kohsuke Kawaguchi
61cf71fd67 [maven-release-plugin] prepare for next development iteration 2012-06-12 14:26:30 -07:00
Kohsuke Kawaguchi
63dd1330e9 [maven-release-plugin] prepare release github-api-1.27 2012-06-12 14:26:25 -07:00
Kohsuke Kawaguchi
4411650c5a additional tweaks 2012-06-12 14:25:08 -07:00
Kohsuke Kawaguchi
1c15751949 Removing pointless '3' suffix in the method names. 2012-06-12 14:21:43 -07:00
Kohsuke Kawaguchi
82acf4f107 Now that everything is V3 API, there's no need for such enum. 2012-06-12 14:20:52 -07:00
Kohsuke Kawaguchi
5525ae8921 Removed unused JSON databinding classes 2012-06-12 14:16:59 -07:00
Kohsuke Kawaguchi
b5f7208b0d Removed v2 API usage and switched to v3.
https://github.com/kohsuke/github-api/issues/8
2012-06-12 14:07:27 -07:00
Kohsuke Kawaguchi
3b5bc98053 [maven-release-plugin] prepare for next development iteration 2012-06-04 10:09:15 -07:00
Kohsuke Kawaguchi
3a9ade667a [maven-release-plugin] prepare release github-api-1.26 2012-06-04 10:09:10 -07:00
Kohsuke Kawaguchi
057c32d410 added API to retrieve rate limit. 2012-06-04 10:08:31 -07:00
Kohsuke Kawaguchi
33657c9c92 made the authentication header optional.
This was needed now that GHPerson.getRepository() always try with authentication on, and it'll break if logged in anonymously
2012-06-04 10:05:03 -07:00
Kohsuke Kawaguchi
4c199256a5 [maven-release-plugin] prepare for next development iteration 2012-05-21 22:42:24 -07:00
Kohsuke Kawaguchi
9e62776905 [maven-release-plugin] prepare release github-api-1.25 2012-05-21 22:42:19 -07:00
Kohsuke Kawaguchi
9ba74b945d added permission check methods 2012-05-21 22:40:43 -07:00
Kohsuke Kawaguchi
66656ce612 when authenticated, repository returns additional information, so always send in a credential when one is available 2012-05-21 22:37:48 -07:00
Kohsuke Kawaguchi
73a20ad829 [maven-release-plugin] prepare for next development iteration 2012-05-21 22:16:52 -07:00
Kohsuke Kawaguchi
6fc9a546cb [maven-release-plugin] prepare release github-api-1.24 2012-05-21 22:16:47 -07:00
Kohsuke Kawaguchi
3f6c225948 updated URL 2012-05-21 22:16:09 -07:00
Kohsuke Kawaguchi
c7e9650a39 added code to list up public keys 2012-05-21 22:15:34 -07:00
Kohsuke Kawaguchi
fd28a36b74 [maven-release-plugin] prepare for next development iteration 2012-04-24 17:22:19 -07:00
Kohsuke Kawaguchi
86543c84db [maven-release-plugin] prepare release github-api-1.23 2012-04-24 17:22:14 -07:00
Kohsuke Kawaguchi
706cdac4cc bug fix 2012-04-24 17:21:33 -07:00
Kohsuke Kawaguchi
0b69743792 added comment deletion 2012-04-24 17:17:35 -07:00
Kohsuke Kawaguchi
dd54a00172 added update 2012-04-24 17:13:48 -07:00
Kohsuke Kawaguchi
b5514b891a added a method to create a new commit comment 2012-04-24 17:06:23 -07:00
Kohsuke Kawaguchi
31a6eca97f added commit comment support 2012-04-24 16:54:05 -07:00
Kohsuke Kawaguchi
8557676561 making names consistent with GHBranch 2012-04-24 16:36:18 -07:00
Kohsuke Kawaguchi
39631461ae added list commits 2012-04-24 16:30:01 -07:00
Kohsuke Kawaguchi
a124d7f714 added some tests 2012-04-24 16:16:13 -07:00
Kohsuke Kawaguchi
fff07bf70b fixed a bug in error handling 2012-04-24 16:14:13 -07:00
Kohsuke Kawaguchi
53d09bb5d8 added object representation for GitHub commit 2012-04-24 16:11:55 -07:00
Kohsuke Kawaguchi
a8ecf0bef0 [maven-release-plugin] prepare for next development iteration 2012-04-12 11:36:57 -07:00
Kohsuke Kawaguchi
74b3902d5f [maven-release-plugin] prepare release github-api-1.22 2012-04-12 11:36:49 -07:00
Kohsuke Kawaguchi
7433ed968e monkey test code 2012-04-12 11:05:18 -07:00
Kohsuke Kawaguchi
ddf2d69a68 this method can return null 2012-04-12 11:05:04 -07:00
Kohsuke Kawaguchi
f5b34861bd avoid NPE 2012-04-12 11:01:43 -07:00
Kohsuke Kawaguchi
f0ff31a1af [maven-release-plugin] prepare for next development iteration 2012-04-11 18:16:16 -07:00
Kohsuke Kawaguchi
8ce76fba62 [maven-release-plugin] prepare release github-api-1.21 2012-04-11 18:16:10 -07:00
Kohsuke Kawaguchi
a947672320 doc improvement 2012-04-11 16:34:37 -07:00
Kohsuke Kawaguchi
5496e2b553 added pagenation support 2012-04-11 16:30:31 -07:00
Kohsuke Kawaguchi
2f9edc65dd support gzip for better performance 2012-04-11 15:45:08 -07:00
Kohsuke Kawaguchi
6372337456 Use gzip to improve transfer performance 2012-04-11 15:44:04 -07:00
Kohsuke Kawaguchi
b843606ebe [maven-release-plugin] prepare for next development iteration 2012-04-11 09:32:51 -07:00
Kohsuke Kawaguchi
7cda083b31 [maven-release-plugin] prepare release github-api-1.20 2012-04-11 09:32:46 -07:00
Kohsuke Kawaguchi
095604d4ca updated the parent version 2012-04-11 09:32:22 -07:00
Kohsuke Kawaguchi
7e799d02e3 Added test-ish 2012-04-11 09:29:28 -07:00
Kohsuke Kawaguchi
7f4612f872 exposed the size 2012-04-11 09:27:47 -07:00
Kohsuke Kawaguchi
6f6ff56338 exposed master_branch 2012-04-11 09:26:26 -07:00
Kohsuke Kawaguchi
27701a75d9 Migrating to the V3 API 2012-04-10 13:03:55 -07:00
Kohsuke Kawaguchi
3717d2ed32 emulate the value for V2 API 2012-04-10 12:57:25 -07:00
Kohsuke Kawaguchi
3a9b6665ee exposed avatar_url 2012-04-10 12:43:59 -07:00
Kohsuke Kawaguchi
bbc42f8898 [maven-release-plugin] prepare for next development iteration 2012-04-06 08:25:49 -07:00
Kohsuke Kawaguchi
f6aea47c2c [maven-release-plugin] prepare release github-api-1.19 2012-04-06 08:25:43 -07:00
Kohsuke Kawaguchi
23069ac2fc Using map to enable lookup by name. 2012-04-06 08:24:41 -07:00
Kohsuke Kawaguchi
0b2fdc598b cleaning up 2012-04-06 08:22:44 -07:00
Frederik Fix
aac30b923c implement listing of branches 2012-04-05 16:21:24 +02:00
Kohsuke Kawaguchi
318caf6123 [maven-release-plugin] prepare for next development iteration 2012-03-08 12:51:59 -08:00
Kohsuke Kawaguchi
6898893ffb [maven-release-plugin] prepare release github-api-1.18 2012-03-08 12:51:54 -08:00
Kohsuke Kawaguchi
cb34f4e91f Merge branch 'pull-6' 2012-03-08 12:50:09 -08:00
Kohsuke Kawaguchi
0da4b320f1 As per Sun coding convention, using upper case letters for enum constants 2012-03-08 12:49:36 -08:00
Kohsuke Kawaguchi
facb5bd13e Added API to handle emails. 2012-03-08 12:47:11 -08:00
Kohsuke Kawaguchi
22bc768868 [maven-release-plugin] prepare for next development iteration 2012-02-12 09:30:37 -08:00
Kohsuke Kawaguchi
a9b6f7bc9c [maven-release-plugin] prepare release github-api-1.17 2012-02-12 09:30:06 -08:00
Kohsuke Kawaguchi
830fb7192d added additional convenience method 2012-02-12 08:20:10 -08:00
Kohsuke Kawaguchi
e8ff7a4ae8 updated to use V3 API 2012-02-12 08:11:15 -08:00
Kohsuke Kawaguchi
dac2a56671 fully populate the root field upon deserialization 2012-02-12 07:43:06 -08:00
Kohsuke Kawaguchi
2718cf5ccb support both v2 and v3 2012-02-12 07:27:39 -08:00
Michael O'Cleirigh
202a5d435c Add original GitHub.connectUsingOAuth(token) back
This adds the original API back which defaults to the 'github.com' server.
2012-02-01 21:24:19 -05:00
Michael O'Cleirigh
58af8d0e90 Add support for github enterprise different base url
This changes how the ApiVersion enumeration works so that each of the V2 and V3  Url schemes is actually a template.

Then the serverName/hostname to use is passed in and used to generate the full url.

This will allow the github-api project to be used against users running the enterprise version of github.

This is needed to support github enterprise based authentication with the github-oauth-plugin.
2012-01-31 22:01:46 -05:00
Kohsuke Kawaguchi
b950be9626 bug fix in the event API. Turns out GHRepository isn't usable for this, because the name field is different.
/repos/:user/:repo returns just ":repo" portion in the name field, whereas in the event it has both ":user/:repo"
2012-01-14 11:53:53 -08:00
Kohsuke Kawaguchi
222277ae0a doc improvement 2012-01-14 11:42:09 -08:00
y.kokubo
fbcf3a17b4 implmented milestone api via v3 2012-01-13 14:36:00 +09:00
Kohsuke Kawaguchi
748cbdd03b doc improvement 2012-01-08 18:30:20 -08:00
Kohsuke Kawaguchi
57b26b6a21 doc improvement 2012-01-08 18:30:19 -08:00
Kohsuke Kawaguchi
a4026d46ce after an experiment, revisiting the design 2012-01-08 18:30:19 -08:00
Kohsuke Kawaguchi
696daf7387 adding the payload handling 2012-01-08 18:30:19 -08:00
Kohsuke Kawaguchi
4a507a5625 adding event support 2012-01-08 18:30:19 -08:00
Kohsuke Kawaguchi
ac1dd9a0ee 'Z' isn't parsed but it means GMT 2012-01-08 18:30:19 -08:00
Kohsuke Kawaguchi
44f1038516 [maven-release-plugin] prepare for next development iteration 2012-01-03 11:16:15 -08:00
Kohsuke Kawaguchi
3e2c9f86da [maven-release-plugin] prepare release github-api-1.16 2012-01-03 11:16:10 -08:00
Kohsuke Kawaguchi
44cc3c8556 added OAuth support to V3 API calls 2012-01-03 11:14:33 -08:00
Kohsuke Kawaguchi
bf65a746b0 inheriting javadoc and designating as overridden 2012-01-03 11:12:18 -08:00
Joshua Krall
4a4a469ca4 Fix for finding private repos on organizations,
requires authenticated API call
2012-01-02 19:45:58 -06:00
Kohsuke Kawaguchi
46b2e5dd32 bug fix 2012-01-02 10:46:54 -08:00
Kohsuke Kawaguchi
8a7adf876f added support for a hook 2012-01-02 10:39:16 -08:00
Kohsuke Kawaguchi
c16ebe4fec bug fix 2012-01-01 18:38:03 -08:00
Kohsuke Kawaguchi
4c61f79e5c bug fix 2012-01-01 18:07:27 -08:00
Kohsuke Kawaguchi
646dc17e5d typo 2012-01-01 18:07:07 -08:00
Kohsuke Kawaguchi
7977471458 Pulled up more properties to the base type 2012-01-01 17:43:44 -08:00
Kohsuke Kawaguchi
9ac2ad957b needs to send auth header 2012-01-01 13:11:24 -08:00
Kohsuke Kawaguchi
7fead8171d improving the usability by introducing a set with lookup-by-ID 2012-01-01 11:13:09 -08:00
Kohsuke Kawaguchi
70bc5c59e2 added a method to return organizations of the user 2012-01-01 09:01:33 -08:00
Kohsuke Kawaguchi
06ef6e841d [maven-release-plugin] prepare for next development iteration 2011-12-31 21:20:06 -08:00
Kohsuke Kawaguchi
2bee34da59 [maven-release-plugin] prepare release github-api-1.15 2011-12-31 21:20:00 -08:00
Kohsuke Kawaguchi
74415b14be bug fix in the error handling 2011-12-19 17:47:08 -08:00
Kohsuke Kawaguchi
1e9a68a16b fixed the behaviour in case the repository doesn't exist. 2011-12-19 17:07:56 -08:00
Kohsuke Kawaguchi
7a3127ed65 added a method to list all members 2011-12-19 17:07:56 -08:00
Kohsuke Kawaguchi
11b0ac19fd PUT apparently requires some payload. 2011-12-19 17:07:56 -08:00
Michael O'Cleirigh
c8eab1f53e OAuth related changes to getMyself() and getUser (username)
Changed how getMyself() works so that in the OAuth case it will use the username less url.

Changed how getUser (username) works in the OAuth case so that you can lookup the specific username using the OAuth token.

Previously getUser (username) would always return the 'myself' user.
2011-11-19 01:08:01 -05:00
Kohsuke Kawaguchi
1c613c5f07 added a method to publicize/conceal 2011-11-15 15:26:47 -08:00
Kohsuke Kawaguchi
b8a63541e8 v3 API changed the meaning of the 'url' field. 2011-11-10 14:30:27 -08:00
Kohsuke Kawaguchi
f25083fde1 more test 2011-11-10 14:25:59 -08:00
Kohsuke Kawaguchi
c86c974400 GHOrganization.createRepository broke, so I fixed that by using V3 API.
That didn't quite work because v3 API has owner as an object, whereas v2 API has owner as string.

So then I fixed all the other retrieval points for GHRepository to use v3.
2011-11-10 14:23:36 -08:00
Kohsuke Kawaguchi
0ad419b026 [maven-release-plugin] prepare for next development iteration 2011-10-26 17:39:15 -07:00
165 changed files with 17954 additions and 1239 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
target
.idea/
*.iml
*.ipr
*.iws

22
LICENSE.txt Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2011- Kohsuke Kawaguchi and other contributors
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

2
README
View File

@@ -1,3 +1,3 @@
Java API for GitHub
See http://kohsuke.org/github-api/ for more details
See http://github-api.kohsuke.org/ for more details

162
pom.xml
View File

@@ -3,11 +3,11 @@
<parent>
<groupId>org.kohsuke</groupId>
<artifactId>pom</artifactId>
<version>1</version>
<version>17</version>
</parent>
<artifactId>github-api</artifactId>
<version>1.14</version>
<version>1.83</version>
<name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>
@@ -16,6 +16,7 @@
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
<url>http://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.83</tag>
</scm>
<distributionManagement>
@@ -25,36 +26,149 @@
</site>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<findbugs-maven-plugin.version>3.0.2</findbugs-maven-plugin.version>
<findbugs-maven-plugin.failOnError>true</findbugs-maven-plugin.failOnError>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.15</version>
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java15</artifactId>
<version>1.0</version>
</signature>
</configuration>
<executions>
<execution>
<id>ensure-java-1.5-class-library</id>
<phase>test</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-injector</artifactId>
<version>1.14</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>${findbugs-maven-plugin.version}</version>
<configuration>
<xmlOutput>true</xmlOutput>
<failOnError>${findbugs-maven-plugin.failOnError}</failOnError>
</configuration>
<executions>
<execution>
<id>run-findbugs</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jvnet.hudson</groupId>
<artifactId>htmlunit</artifactId>
<version>2.6-hudson-2</version>
<exclusions>
<exclusion>
<!-- hides JDK DOM classes in Eclipse -->
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
</exclusions>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.5.0</version>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-annotation</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>org.kohsuke.stapler</groupId>
<artifactId>stapler-jetty</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>3.1.0.201310021548-r</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp-urlconnection</artifactId>
<version>2.7.5</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>wordnet-random-name</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>
<reporting>
<plugins>
@@ -64,4 +178,20 @@
</plugin>
</plugins>
</reporting>
<licenses>
<license>
<name>The MIT license</name>
<url>http://www.opensource.org/licenses/mit-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>
<mailingLists>
<mailingList>
<name>User List</name>
<post>github-api@googlegroups.com</post>
<archive>https://groups.google.com/forum/#!forum/github-api</archive>
</mailingList>
</mailingLists>
</project>

View File

@@ -0,0 +1,63 @@
package org.kohsuke.github;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.HttpURLConnection;
/**
* Pluggable strategy to determine what to do when the API abuse limit is hit.
*
* @author Kohsuke Kawaguchi
* @see GitHubBuilder#withAbuseLimitHandler(AbuseLimitHandler)
* @see <a href="https://developer.github.com/v3/#abuse-rate-limits">documentation</a>
* @see RateLimitHandler
*/
public abstract class AbuseLimitHandler {
/**
* Called when the library encounters HTTP error indicating that the API abuse limit is reached.
*
* <p>
* Any exception thrown from this method will cause the request to fail, and the caller of github-api
* will receive an exception. If this method returns normally, another request will be attempted.
* For that to make sense, the implementation needs to wait for some time.
*
* @see <a href="https://developer.github.com/v3/#abuse-rate-limits">API documentation from GitHub</a>
* @param e
* Exception from Java I/O layer. If you decide to fail the processing, you can throw
* this exception (or wrap this exception into another exception and throw it.)
* @param uc
* Connection that resulted in an error. Useful for accessing other response headers.
*/
public abstract void onError(IOException e, HttpURLConnection uc) throws IOException;
/**
* Wait until the API abuse "wait time" is passed.
*/
public static final AbuseLimitHandler WAIT = new AbuseLimitHandler() {
@Override
public void onError(IOException e, HttpURLConnection uc) throws IOException {
try {
Thread.sleep(parseWaitTime(uc));
} catch (InterruptedException _) {
throw (InterruptedIOException)new InterruptedIOException().initCause(e);
}
}
private long parseWaitTime(HttpURLConnection uc) {
String v = uc.getHeaderField("Retry-After");
if (v==null) return 60 * 1000; // can't tell, return 1 min
return Math.max(1000, Long.parseLong(v)*1000);
}
};
/**
* Fail immediately.
*/
public static final AbuseLimitHandler FAIL = new AbuseLimitHandler() {
@Override
public void onError(IOException e, HttpURLConnection uc) throws IOException {
throw (IOException)new IOException("Abust limit reached").initCause(e);
}
};
}

View File

@@ -1,17 +0,0 @@
package org.kohsuke.github;
/**
* Different API versions.
*
* @author Kohsuke Kawaguchi
*/
enum ApiVersion {
V2("https://github.com/api/v2/json"),
V3("https://api.github.com");
final String url;
ApiVersion(String url) {
this.url = url;
}
}

View File

@@ -0,0 +1,21 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
* @see GHBranch#disableProtection()
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
class BranchProtection {
boolean enabled;
RequiredStatusChecks requiredStatusChecks;
static class RequiredStatusChecks {
EnforcementLevel enforcement_level;
List<String> contexts = new ArrayList<String>();
}
}

View File

@@ -23,9 +23,13 @@
*/
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* @author Kohsuke Kawaguchi
*/
@SuppressFBWarnings(value = "UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD",
justification = "Being constructed by JSON deserialization")
class DeleteToken {
public String delete_token;
}

View File

@@ -0,0 +1,14 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* @author Kohsuke Kawaguchi
*/
public enum EnforcementLevel {
OFF, NON_ADMINS, EVERYONE;
public String toString() {
return name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,101 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
/**
* Asset in a release.
*
* @see GHRelease#getAssets()
*/
public class GHAsset extends GHObject {
GitHub root;
GHRepository owner;
private String name;
private String label;
private String state;
private String content_type;
private long size;
private long download_count;
private String browser_download_url;
public String getContentType() {
return content_type;
}
public void setContentType(String contentType) throws IOException {
edit("content_type", contentType);
this.content_type = contentType;
}
public long getDownloadCount() {
return download_count;
}
public String getLabel() {
return label;
}
public void setLabel(String label) throws IOException {
edit("label", label);
this.label = label;
}
public String getName() {
return name;
}
public GHRepository getOwner() {
return owner;
}
public GitHub getRoot() {
return root;
}
public long getSize() {
return size;
}
public String getState() {
return state;
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
public String getBrowserDownloadUrl() {
return browser_download_url;
}
private void edit(String key, Object value) throws IOException {
new Requester(root)._with(key, value).method("PATCH").to(getApiRoute());
}
public void delete() throws IOException {
new Requester(root).method("DELETE").to(getApiRoute());
}
private String getApiRoute() {
return "/repos/" + owner.getOwnerName() + "/" + owner.getName() + "/releases/assets/" + id;
}
GHAsset wrap(GHRelease release) {
this.owner = release.getOwner();
this.root = owner.root;
return this;
}
public static GHAsset[] wrap(GHAsset[] assets, GHRelease release) {
for (GHAsset aTo : assets) {
aTo.wrap(release);
}
return assets;
}
}

View File

@@ -0,0 +1,114 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URL;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
* Generated OAuth token
*
* @author janinko
* @see GitHub#createToken(Collection, String, String)
* @see <a href="http://developer.github.com/v3/oauth/#create-a-new-authorization">API documentation</a>
*/
public class GHAuthorization extends GHObject {
public static final String USER = "user";
public static final String USER_EMAIL = "user:email";
public static final String USER_FOLLOW = "user:follow";
public static final String PUBLIC_REPO = "public_repo";
public static final String REPO = "repo";
public static final String REPO_STATUS = "repo:status";
public static final String DELETE_REPO = "delete_repo";
public static final String NOTIFICATIONS = "notifications";
public static final String GIST = "gist";
public static final String READ_HOOK = "read:repo_hook";
public static final String WRITE_HOOK = "write:repo_hook";
public static final String AMIN_HOOK = "admin:repo_hook";
public static final String READ_ORG = "read:org";
public static final String WRITE_ORG = "write:org";
public static final String ADMIN_ORG = "admin:org";
public static final String READ_KEY = "read:public_key";
public static final String WRITE_KEY = "write:public_key";
public static final String ADMIN_KEY = "admin:public_key";
private GitHub root;
private List<String> scopes;
private String token;
private String token_last_eight;
private String hashed_token;
private App app;
private String note;
private String note_url;
private String fingerprint;
//TODO add some user class for https://developer.github.com/v3/oauth_authorizations/#check-an-authorization ?
//private GHUser user;
public GitHub getRoot() {
return root;
}
public List<String> getScopes() {
return scopes;
}
public String getToken() {
return token;
}
public String getTokenLastEight() {
return token_last_eight;
}
public String getHashedToken() {
return hashed_token;
}
public URL getAppUrl() {
return GitHub.parseURL(app.url);
}
public String getAppName() {
return app.name;
}
@SuppressFBWarnings(value = "NM_CONFUSING",
justification = "It's a part of the library API, cannot be changed")
public URL getApiURL() {
return GitHub.parseURL(url);
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
public String getNote() {
return note;
}
public URL getNoteUrl() {
return GitHub.parseURL(note_url);
}
public String getFingerprint() {
return fingerprint;
}
/*package*/ GHAuthorization wrap(GitHub root) {
this.root = root;
return this;
}
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD"},
justification = "JSON API")
private static class App {
private String url;
private String name;
// private String client_id; not yet used
}
}

View File

@@ -0,0 +1,64 @@
package org.kohsuke.github;
import org.apache.commons.codec.binary.Base64InputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
/**
* @author Kanstantsin Shautsou
* @author Kohsuke Kawaguchi
* @see GHTreeEntry#asBlob()
* @see GHRepository#getBlob(String)
* @see <a href="https://developer.github.com/v3/git/blobs/#get-a-blob">Get a blob</a>
*/
public class GHBlob {
private String content, encoding, url, sha;
private long size;
/**
* API URL of this blob.
*/
public URL getUrl() {
return GitHub.parseURL(url);
}
public String getSha() {
return sha;
}
/**
* Number of bytes in this blob.
*/
public long getSize() {
return size;
}
public String getEncoding() {
return encoding;
}
/**
* Encoded content. You probably want {@link #read()}
*/
public String getContent() {
return content;
}
/**
* Retrieves the actual bytes of the blob.
*/
public InputStream read() {
if (encoding.equals("base64")) {
try {
return new Base64InputStream(new ByteArrayInputStream(content.getBytes("US-ASCII")), false);
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e); // US-ASCII is mandatory
}
}
throw new UnsupportedOperationException("Unrecognized encoding: "+encoding);
}
}

View File

@@ -0,0 +1,129 @@
package org.kohsuke.github;
import static org.kohsuke.github.Previews.LOKI;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import org.kohsuke.github.BranchProtection.RequiredStatusChecks;
import com.fasterxml.jackson.annotation.JsonProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* A branch in a repository.
*
* @author Yusuke Kokubo
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
public class GHBranch {
private GitHub root;
private GHRepository owner;
private String name;
private Commit commit;
@JsonProperty("protected")
private boolean protection;
private String protection_url;
public static class Commit {
String sha;
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
String url;
}
public GitHub getRoot() {
return root;
}
/**
* Repository that this branch is in.
*/
public GHRepository getOwner() {
return owner;
}
public String getName() {
return name;
}
/**
* Returns true if the push to this branch is restricted via branch protection.
*/
@Preview @Deprecated
public boolean isProtected() {
return protection;
}
/**
* Returns API URL that deals with the protection of this branch.
*/
@Preview @Deprecated
public URL getProtectionUrl() {
return GitHub.parseURL(protection_url);
}
/**
* The commit that this branch currently points to.
*/
public String getSHA1() {
return commit.sha;
}
/**
* Disables branch protection and allows anyone with push access to push changes.
*/
@Preview @Deprecated
public void disableProtection() throws IOException {
BranchProtection bp = new BranchProtection();
bp.enabled = false;
setProtection(bp);
}
/**
* Enables branch protection to control what commit statuses are required to push.
*
* @see GHCommitStatus#getContext()
*/
@Preview @Deprecated
public void enableProtection(EnforcementLevel level, Collection<String> contexts) throws IOException {
BranchProtection bp = new BranchProtection();
bp.enabled = true;
bp.requiredStatusChecks = new RequiredStatusChecks();
bp.requiredStatusChecks.enforcement_level = level;
bp.requiredStatusChecks.contexts.addAll(contexts);
setProtection(bp);
}
@Preview @Deprecated
public void enableProtection(EnforcementLevel level, String... contexts) throws IOException {
enableProtection(level, Arrays.asList(contexts));
}
private void setProtection(BranchProtection bp) throws IOException {
new Requester(root).method("PATCH").withPreview(LOKI)._with("protection",bp).to(getApiRoute());
}
String getApiRoute() {
return owner.getApiTailUrl("/branches/"+name);
}
@Override
public String toString() {
final String url = owner != null ? owner.getUrl().toString() : "unknown";
return "Branch:" + name + " in " + url;
}
/*package*/ GHBranch wrap(GHRepository repo) {
this.owner = repo;
this.root = repo.root;
return this;
}
}

View File

@@ -0,0 +1,387 @@
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
* A commit in a repository.
*
* @author Kohsuke Kawaguchi
* @see GHRepository#getCommit(String)
* @see GHCommitComment#getCommit()
*/
@SuppressFBWarnings(value = {"NP_UNWRITTEN_FIELD", "UWF_UNWRITTEN_FIELD"},
justification = "JSON API")
public class GHCommit {
private GHRepository owner;
private ShortInfo commit;
/**
* Short summary of this commit.
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD", "UWF_UNWRITTEN_FIELD"}, justification = "JSON API")
public static class ShortInfo {
private GHAuthor author;
private GHAuthor committer;
private String message;
private int comment_count;
static class Tree {
String sha;
}
private Tree tree;
@WithBridgeMethods(value = GHAuthor.class, castRequired = true)
public GitUser getAuthor() {
return author;
}
public Date getAuthoredDate() {
return GitHub.parseDate(author.date);
}
@WithBridgeMethods(value = GHAuthor.class, castRequired = true)
public GitUser getCommitter() {
return committer;
}
public Date getCommitDate() {
return GitHub.parseDate(committer.date);
}
/**
* Commit message.
*/
public String getMessage() {
return message;
}
public int getCommentCount() {
return comment_count;
}
}
/**
* @deprecated Use {@link GitUser} instead.
*/
public static class GHAuthor extends GitUser {
private String date;
}
public static class Stats {
int total,additions,deletions;
}
/**
* A file that was modified.
*/
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD",
justification = "It's being initilized by JSON deserialization")
public static class File {
String status;
int changes,additions,deletions;
String raw_url, blob_url, sha, patch;
String filename, previous_filename;
/**
* Number of lines added + removed.
*/
public int getLinesChanged() {
return changes;
}
/**
* Number of lines added.
*/
public int getLinesAdded() {
return additions;
}
/**
* Number of lines removed.
*/
public int getLinesDeleted() {
return deletions;
}
/**
* "modified", "added", or "removed"
*/
public String getStatus() {
return status;
}
/**
* Full path in the repository.
*/
@SuppressFBWarnings(value = "NM_CONFUSING",
justification = "It's a part of the library's API and cannot be renamed")
public String getFileName() {
return filename;
}
/**
* Previous path, in case file has moved.
*/
public String getPreviousFilename() {
return previous_filename;
}
/**
* The actual change.
*/
public String getPatch() {
return patch;
}
/**
* URL like 'https://raw.github.com/jenkinsci/jenkins/4eb17c197dfdcf8ef7ff87eb160f24f6a20b7f0e/core/pom.xml'
* that resolves to the actual content of the file.
*/
public URL getRawUrl() {
return GitHub.parseURL(raw_url);
}
/**
* URL like 'https://github.com/jenkinsci/jenkins/blob/1182e2ebb1734d0653142bd422ad33c21437f7cf/core/pom.xml'
* that resolves to the HTML page that describes this file.
*/
public URL getBlobUrl() {
return GitHub.parseURL(blob_url);
}
/**
* [0-9a-f]{40} SHA1 checksum.
*/
public String getSha() {
return sha;
}
}
public static class Parent {
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
String url;
String sha;
}
static class User {
// TODO: what if someone who doesn't have an account on GitHub makes a commit?
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
String url,avatar_url,gravatar_id;
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
int id;
String login;
}
String url,html_url,sha;
List<File> files;
Stats stats;
List<Parent> parents;
User author,committer;
public ShortInfo getCommitShortInfo() throws IOException {
if (commit==null)
populate();
return commit;
}
/**
* The repository that contains the commit.
*/
public GHRepository getOwner() {
return owner;
}
/**
* Number of lines added + removed.
*/
public int getLinesChanged() throws IOException {
populate();
return stats.total;
}
/**
* Number of lines added.
*/
public int getLinesAdded() throws IOException {
populate();
return stats.additions;
}
/**
* Number of lines removed.
*/
public int getLinesDeleted() throws IOException {
populate();
return stats.deletions;
}
/**
* Use this method to walk the tree
*/
public GHTree getTree() throws IOException {
return owner.getTree(getCommitShortInfo().tree.sha);
}
/**
* URL of this commit like "https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000"
*/
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
/**
* [0-9a-f]{40} SHA1 checksum.
*/
public String getSHA1() {
return sha;
}
/**
* List of files changed/added/removed in this commit.
*
* @return
* Can be empty but never null.
*/
public List<File> getFiles() throws IOException {
populate();
return files!=null ? Collections.unmodifiableList(files) : Collections.<File>emptyList();
}
/**
* Returns the SHA1 of parent commit objects.
*/
public List<String> getParentSHA1s() {
if (parents==null) return Collections.emptyList();
return new AbstractList<String>() {
@Override
public String get(int index) {
return parents.get(index).sha;
}
@Override
public int size() {
return parents.size();
}
};
}
/**
* Resolves the parent commit objects and return them.
*/
public List<GHCommit> getParents() throws IOException {
List<GHCommit> r = new ArrayList<GHCommit>();
for (String sha1 : getParentSHA1s())
r.add(owner.getCommit(sha1));
return r;
}
public GHUser getAuthor() throws IOException {
return resolveUser(author);
}
/**
* Gets the date the change was authored on.
* @return the date the change was authored on.
* @throws IOException if the information was not already fetched and an attempt at fetching the information failed.
*/
public Date getAuthoredDate() throws IOException {
return getCommitShortInfo().getAuthoredDate();
}
public GHUser getCommitter() throws IOException {
return resolveUser(committer);
}
/**
* Gets the date the change was committed on.
*
* @return the date the change was committed on.
* @throws IOException if the information was not already fetched and an attempt at fetching the information failed.
*/
public Date getCommitDate() throws IOException {
return getCommitShortInfo().getCommitDate();
}
private GHUser resolveUser(User author) throws IOException {
if (author==null || author.login==null) return null;
return owner.root.getUser(author.login);
}
/**
* Lists up all the commit comments in this repository.
*/
public PagedIterable<GHCommitComment> listComments() {
return new PagedIterable<GHCommitComment>() {
public PagedIterator<GHCommitComment> _iterator(int pageSize) {
return new PagedIterator<GHCommitComment>(owner.root.retrieve().asIterator(String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha), GHCommitComment[].class, pageSize)) {
@Override
protected void wrapUp(GHCommitComment[] page) {
for (GHCommitComment c : page)
c.wrap(owner);
}
};
}
};
}
/**
* Creates a commit comment.
*
* I'm not sure how path/line/position parameters interact with each other.
*/
public GHCommitComment createComment(String body, String path, Integer line, Integer position) throws IOException {
GHCommitComment r = new Requester(owner.root)
.with("body",body)
.with("path",path)
.with("line",line)
.with("position",position)
.to(String.format("/repos/%s/%s/commits/%s/comments",owner.getOwnerName(),owner.getName(),sha),GHCommitComment.class);
return r.wrap(owner);
}
public GHCommitComment createComment(String body) throws IOException {
return createComment(body, null, null, null);
}
/**
* Gets the status of this commit, newer ones first.
*/
public PagedIterable<GHCommitStatus> listStatuses() throws IOException {
return owner.listCommitStatuses(sha);
}
/**
* Gets the last status of this commit, which is what gets shown in the UI.
*/
public GHCommitStatus getLastStatus() throws IOException {
return owner.getLastCommitStatus(sha);
}
/**
* Some of the fields are not always filled in when this object is retrieved as a part of another API call.
*/
void populate() throws IOException {
if (files==null && stats==null)
owner.root.retrieve().to(owner.getApiTailUrl("commits/" + sha), this);
}
GHCommit wrapUp(GHRepository owner) {
this.owner = owner;
return this;
}
}

View File

@@ -0,0 +1,133 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import static org.kohsuke.github.Previews.SQUIRREL_GIRL;
/**
* A comment attached to a commit (or a specific line in a specific file of a commit.)
*
* @author Kohsuke Kawaguchi
* @see GHRepository#listCommitComments()
* @see GHCommit#listComments()
* @see GHCommit#createComment(String, String, Integer, Integer)
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHCommitComment extends GHObject implements Reactable {
private GHRepository owner;
String body, html_url, commit_id;
Integer line;
String path;
GHUser user; // not fully populated. beware.
public GHRepository getOwner() {
return owner;
}
/**
* URL like 'https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000#commitcomment-1252827' to
* show this commit comment in a browser.
*/
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
public String getSHA1() {
return commit_id;
}
/**
* Commit comment in the GitHub flavored markdown format.
*/
public String getBody() {
return body;
}
/**
* A commit comment can be on a specific line of a specific file, if so, this field points to a file.
* Otherwise null.
*/
public String getPath() {
return path;
}
/**
* A commit comment can be on a specific line of a specific file, if so, this field points to the line number in the file.
* Otherwise -1.
*/
public int getLine() {
return line!=null ? line : -1;
}
/**
* Gets the user who put this comment.
*/
public GHUser getUser() throws IOException {
return owner == null || owner.root.isOffline() ? user : owner.root.getUser(user.login);
}
/**
* Gets the commit to which this comment is associated with.
*/
public GHCommit getCommit() throws IOException {
return getOwner().getCommit(getSHA1());
}
/**
* Updates the body of the commit message.
*/
public void update(String body) throws IOException {
new Requester(owner.root)
.with("body", body)
.method("PATCH").to(getApiTail(), GHCommitComment.class);
this.body = body;
}
@Preview @Deprecated
public GHReaction createReaction(ReactionContent content) throws IOException {
return new Requester(owner.root)
.withPreview(SQUIRREL_GIRL)
.with("content", content.getContent())
.to(getApiTail()+"/reactions", GHReaction.class).wrap(owner.root);
}
@Preview @Deprecated
public PagedIterable<GHReaction> listReactions() {
return new PagedIterable<GHReaction>() {
public PagedIterator<GHReaction> _iterator(int pageSize) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiTail()+"/reactions", GHReaction[].class, pageSize)) {
@Override
protected void wrapUp(GHReaction[] page) {
for (GHReaction c : page)
c.wrap(owner.root);
}
};
}
};
}
/**
* Deletes this comment.
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(getApiTail());
}
private String getApiTail() {
return String.format("/repos/%s/%s/comments/%s",owner.getOwnerName(),owner.getName(),id);
}
GHCommitComment wrap(GHRepository owner) {
this.owner = owner;
if (owner.root.isOffline()) {
user.wrapUp(owner.root);
}
return this;
}
}

View File

@@ -23,6 +23,8 @@
*/
package org.kohsuke.github;
import java.io.IOException;
/**
* Identifies a commit in {@link GHPullRequest}.
*
@@ -31,11 +33,11 @@ package org.kohsuke.github;
public class GHCommitPointer {
private String ref, sha, label;
private GHUser user;
private GHRepository repository;
private GHRepository repo;
/**
* This points to the user who owns
* the {@link #repository}.
* the {@link #getRepository()}.
*/
public GHUser getUser() {
return user;
@@ -45,11 +47,11 @@ public class GHCommitPointer {
* The repository that contains the commit.
*/
public GHRepository getRepository() {
return repository;
return repo;
}
/**
* Named ref to the commit.
* Named ref to the commit. This appears to be a "short ref" that doesn't include "refs/heads/" portion.
*/
public String getRef() {
return ref;
@@ -68,4 +70,16 @@ public class GHCommitPointer {
public String getLabel() {
return label;
}
/**
* Obtains the commit that this pointer is referring to.
*/
public GHCommit getCommit() throws IOException {
return getRepository().getCommit(getSha());
}
void wrapUp(GitHub root) {
if (user!=null) user.root = root;
if (repo!=null) repo.wrap(root);
}
}

View File

@@ -0,0 +1,105 @@
package org.kohsuke.github;
import java.util.Date;
/**
* Builds up query for listing commits.
*
* <p>
* Call various methods that set the filter criteria, then {@link #list()} method to actually list up the commit.
*
* <pre>
* GHRepository r = ...;
* for (GHCommit c : r.queryCommits().since(x).until(y).author("kohsuke")) {
* ...
* }
* </pre>
*
* @author Kohsuke Kawaguchi
* @see GHRepository#queryCommits()
*/
public class GHCommitQueryBuilder {
private final Requester req;
private final GHRepository repo;
/*package*/ GHCommitQueryBuilder(GHRepository repo) {
this.repo = repo;
this.req = repo.root.retrieve(); // requester to build up
}
/**
* GItHub login or email address by which to filter by commit author.
*/
public GHCommitQueryBuilder author(String author) {
req.with("author",author);
return this;
}
/**
* Only commits containing this file path will be returned.
*/
public GHCommitQueryBuilder path(String path) {
req.with("path",path);
return this;
}
/**
* Specifies the SHA1 commit / tag / branch / etc to start listing commits from.
*
*/
public GHCommitQueryBuilder from(String ref) {
req.with("sha",ref);
return this;
}
public GHCommitQueryBuilder pageSize(int pageSize) {
req.with("per_page",pageSize);
return this;
}
/**
* Only commits after this date will be returned
*/
public GHCommitQueryBuilder since(Date dt) {
req.with("since",GitHub.printDate(dt));
return this;
}
/**
* Only commits after this date will be returned
*/
public GHCommitQueryBuilder since(long timestamp) {
return since(new Date(timestamp));
}
/**
* Only commits before this date will be returned
*/
public GHCommitQueryBuilder until(Date dt) {
req.with("until",GitHub.printDate(dt));
return this;
}
/**
* Only commits before this date will be returned
*/
public GHCommitQueryBuilder until(long timestamp) {
return until(new Date(timestamp));
}
/**
* Lists up the commits with the criteria built so far.
*/
public PagedIterable<GHCommit> list() {
return new PagedIterable<GHCommit>() {
public PagedIterator<GHCommit> _iterator(int pageSize) {
return new PagedIterator<GHCommit>(req.asIterator(repo.getApiTailUrl("commits"), GHCommit[].class, pageSize)) {
protected void wrapUp(GHCommit[] page) {
for (GHCommit c : page)
c.wrapUp(repo);
}
};
}
};
}
}

View File

@@ -0,0 +1,11 @@
package org.kohsuke.github;
/**
* Represents the state of commit
*
* @author Kohsuke Kawaguchi
* @see GHCommitStatus
*/
public enum GHCommitState {
PENDING, SUCCESS, ERROR, FAILURE
}

View File

@@ -0,0 +1,63 @@
package org.kohsuke.github;
import java.net.URL;
/**
* Represents a status of a commit.
*
* @author Kohsuke Kawaguchi
* @see GHRepository#getLastCommitStatus(String)
* @see GHCommit#getLastStatus()
* @see GHRepository#createCommitStatus(String, GHCommitState, String, String)
*/
public class GHCommitStatus extends GHObject {
String state;
String target_url,description;
String context;
GHUser creator;
private GitHub root;
/*package*/ GHCommitStatus wrapUp(GitHub root) {
if (creator!=null) creator.wrapUp(root);
this.root = root;
return this;
}
public GHCommitState getState() {
for (GHCommitState s : GHCommitState.values()) {
if (s.name().equalsIgnoreCase(state))
return s;
}
throw new IllegalStateException("Unexpected state: "+state);
}
/**
* The URL that this status is linked to.
*
* This is the URL specified when creating a commit status.
*/
public String getTargetUrl() {
return target_url;
}
public String getDescription() {
return description;
}
public GHUser getCreator() {
return creator;
}
public String getContext() {
return context;
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
}

View File

@@ -0,0 +1,167 @@
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URL;
/**
* The model user for comparing 2 commits in the GitHub API.
*
* @author Michael Clarke
*/
public class GHCompare {
private String url, html_url, permalink_url, diff_url, patch_url;
public Status status;
private int ahead_by, behind_by, total_commits;
private Commit base_commit, merge_base_commit;
private Commit[] commits;
private GHCommit.File[] files;
private GHRepository owner;
public URL getUrl() {
return GitHub.parseURL(url);
}
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
public URL getPermalinkUrl() {
return GitHub.parseURL(permalink_url);
}
public URL getDiffUrl() {
return GitHub.parseURL(diff_url);
}
public URL getPatchUrl() {
return GitHub.parseURL(patch_url);
}
public Status getStatus() {
return status;
}
public int getAheadBy() {
return ahead_by;
}
public int getBehindBy() {
return behind_by;
}
public int getTotalCommits() {
return total_commits;
}
public Commit getBaseCommit() {
return base_commit;
}
public Commit getMergeBaseCommit() {
return merge_base_commit;
}
/**
* Gets an array of commits.
* @return A copy of the array being stored in the class.
*/
public Commit[] getCommits() {
Commit[] newValue = new Commit[commits.length];
System.arraycopy(commits, 0, newValue, 0, commits.length);
return newValue;
}
/**
* Gets an array of commits.
* @return A copy of the array being stored in the class.
*/
public GHCommit.File[] getFiles() {
GHCommit.File[] newValue = new GHCommit.File[files.length];
System.arraycopy(files, 0, newValue, 0, files.length);
return newValue;
}
public GHCompare wrap(GHRepository owner) {
this.owner = owner;
for (Commit commit : commits) {
commit.wrapUp(owner);
}
merge_base_commit.wrapUp(owner);
base_commit.wrapUp(owner);
return this;
}
/**
* Compare commits had a child commit element with additional details we want to capture.
* This extenstion of GHCommit provides that.
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD"},
justification = "JSON API")
public static class Commit extends GHCommit {
private InnerCommit commit;
public InnerCommit getCommit() {
return commit;
}
}
public static class InnerCommit {
private String url, sha, message;
private User author, committer;
private Tree tree;
public String getUrl() {
return url;
}
public String getSha() {
return sha;
}
public String getMessage() {
return message;
}
@WithBridgeMethods(value=User.class,castRequired=true)
public GitUser getAuthor() {
return author;
}
@WithBridgeMethods(value=User.class,castRequired=true)
public GitUser getCommitter() {
return committer;
}
public Tree getTree() {
return tree;
}
}
public static class Tree {
private String url, sha;
public String getUrl() {
return url;
}
public String getSha() {
return sha;
}
}
/**
* @deprecated use {@link GitUser} instead.
*/
public static class User extends GitUser {
}
public static enum Status {
behind, ahead, identical, diverged
}
}

View File

@@ -0,0 +1,248 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.bind.DatatypeConverter;
/**
* A Content of a repository.
*
* @author Alexandre COLLIGNON
* @see GHRepository#getFileContent(String)
*/
@SuppressWarnings({"UnusedDeclaration"})
public class GHContent {
/*
In normal use of this class, repository field is set via wrap(),
but in the code search API, there's a nested 'repository' field that gets populated from JSON.
*/
private GHRepository repository;
private GitHub root;
private String type;
private String encoding;
private long size;
private String sha;
private String name;
private String path;
private String content;
private String url; // this is the API url
private String git_url; // this is the Blob url
private String html_url; // this is the UI
private String download_url;
public GHRepository getOwner() {
return repository;
}
public String getType() {
return type;
}
public String getEncoding() {
return encoding;
}
public long getSize() {
return size;
}
public String getSha() {
return sha;
}
public String getName() {
return name;
}
public String getPath() {
return path;
}
/**
* Retrieve the decoded content that is stored at this location.
*
* <p>
* Due to the nature of GitHub's API, you're not guaranteed that
* the content will already be populated, so this may trigger
* network activity, and can throw an IOException.
*
* @deprecated
* Use {@link #read()}
*/
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
public String getContent() throws IOException {
return new String(Base64.decodeBase64(getEncodedContent()));
}
/**
* Retrieve the base64-encoded content that is stored at this location.
*
* <p>
* Due to the nature of GitHub's API, you're not guaranteed that
* the content will already be populated, so this may trigger
* network activity, and can throw an IOException.
*
* @deprecated
* Use {@link #read()}
*/
public String getEncodedContent() throws IOException {
if (content!=null)
return content;
else
return Base64.encodeBase64String(IOUtils.toByteArray(read()));
}
public String getUrl() {
return url;
}
public String getGitUrl() {
return git_url;
}
public String getHtmlUrl() {
return html_url;
}
/**
* Retrieves the actual content stored here.
*/
public InputStream read() throws IOException {
// if the download link is encoded with a token on the query string, the default behavior of POST will fail
return new Requester(root).method("GET").asStream(getDownloadUrl());
}
/**
* URL to retrieve the raw content of the file. Null if this is a directory.
*/
public String getDownloadUrl() throws IOException {
populate();
return download_url;
}
public boolean isFile() {
return "file".equals(type);
}
public boolean isDirectory() {
return "dir".equals(type);
}
/**
* Fully populate the data by retrieving missing data.
*
* Depending on the original API call where this object is created, it may not contain everything.
*/
protected synchronized void populate() throws IOException {
if (download_url!=null) return; // already populated
root.retrieve().to(url, this);
}
/**
* List immediate children of this directory.
*/
public PagedIterable<GHContent> listDirectoryContent() throws IOException {
if (!isDirectory())
throw new IllegalStateException(path+" is not a directory");
return new PagedIterable<GHContent>() {
public PagedIterator<GHContent> _iterator(int pageSize) {
return new PagedIterator<GHContent>(root.retrieve().asIterator(url, GHContent[].class, pageSize)) {
@Override
protected void wrapUp(GHContent[] page) {
GHContent.wrap(page, repository);
}
};
}
};
}
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
public GHContentUpdateResponse update(String newContent, String commitMessage) throws IOException {
return update(newContent.getBytes(), commitMessage, null);
}
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
public GHContentUpdateResponse update(String newContent, String commitMessage, String branch) throws IOException {
return update(newContent.getBytes(), commitMessage, branch);
}
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage) throws IOException {
return update(newContentBytes, commitMessage, null);
}
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage, String branch) throws IOException {
String encodedContent = Base64.encodeBase64String(newContentBytes);
Requester requester = new Requester(root)
.with("path", path)
.with("message", commitMessage)
.with("sha", sha)
.with("content", encodedContent)
.method("PUT");
if (branch != null) {
requester.with("branch", branch);
}
GHContentUpdateResponse response = requester.to(getApiRoute(), GHContentUpdateResponse.class);
response.getContent().wrap(repository);
response.getCommit().wrapUp(repository);
this.content = encodedContent;
return response;
}
public GHContentUpdateResponse delete(String message) throws IOException {
return delete(message, null);
}
public GHContentUpdateResponse delete(String commitMessage, String branch) throws IOException {
Requester requester = new Requester(root)
.with("path", path)
.with("message", commitMessage)
.with("sha", sha)
.method("DELETE");
if (branch != null) {
requester.with("branch", branch);
}
GHContentUpdateResponse response = requester.to(getApiRoute(), GHContentUpdateResponse.class);
response.getCommit().wrapUp(repository);
return response;
}
private String getApiRoute() {
return "/repos/" + repository.getOwnerName() + "/" + repository.getName() + "/contents/" + path;
}
GHContent wrap(GHRepository owner) {
this.repository = owner;
this.root = owner.root;
return this;
}
GHContent wrap(GitHub root) {
this.root = root;
if (repository!=null)
repository.wrap(root);
return this;
}
public static GHContent[] wrap(GHContent[] contents, GHRepository repository) {
for (GHContent unwrappedContent : contents) {
unwrappedContent.wrap(repository);
}
return contents;
}
}

View File

@@ -0,0 +1,74 @@
package org.kohsuke.github;
/**
* Search code for {@link GHContent}.
*
* @author Kohsuke Kawaguchi
* @see GitHub#searchContent()
*/
public class GHContentSearchBuilder extends GHSearchBuilder<GHContent> {
/*package*/ GHContentSearchBuilder(GitHub root) {
super(root,ContentSearchResult.class);
}
/**
* Search terms.
*/
public GHContentSearchBuilder q(String term) {
super.q(term);
return this;
}
public GHContentSearchBuilder in(String v) {
return q("in:"+v);
}
public GHContentSearchBuilder language(String v) {
return q("language:"+v);
}
public GHContentSearchBuilder fork(String v) {
return q("fork:"+v);
}
public GHContentSearchBuilder size(String v) {
return q("size:"+v);
}
public GHContentSearchBuilder path(String v) {
return q("path:"+v);
}
public GHContentSearchBuilder filename(String v) {
return q("filename:"+v);
}
public GHContentSearchBuilder extension(String v) {
return q("extension:"+v);
}
public GHContentSearchBuilder user(String v) {
return q("user:"+v);
}
public GHContentSearchBuilder repo(String v) {
return q("repo:"+v);
}
private static class ContentSearchResult extends SearchResult<GHContent> {
private GHContent[] items;
@Override
/*package*/ GHContent[] getItems(GitHub root) {
for (GHContent item : items)
item.wrap(root);
return items;
}
}
@Override
protected String getApiUrl() {
return "/search/code";
}
}

View File

@@ -0,0 +1,18 @@
package org.kohsuke.github;
/**
* The response that is returned when updating
* repository content.
**/
public class GHContentUpdateResponse {
private GHContent content;
private GHCommit commit;
public GHContent getContent() {
return content;
}
public GHCommit getCommit() {
return commit;
}
}

View File

@@ -0,0 +1,21 @@
package org.kohsuke.github;
/**
* {@link GHContent} with license information.
*
* @author Kohsuke Kawaguchi
* @see <a href="https://developer.github.com/v3/licenses/#get-a-repositorys-license">documentation</a>
* @see GHRepository#getLicense()
*/
@Preview @Deprecated
class GHContentWithLicense extends GHContent {
GHLicense license;
@Override
GHContentWithLicense wrap(GHRepository owner) {
super.wrap(owner);
if (license!=null)
license.wrap(owner.root);
return this;
}
}

View File

@@ -0,0 +1,114 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
/**
* Creates a repository
*
* @author Kohsuke Kawaguchi
*/
public class GHCreateRepositoryBuilder {
private final GitHub root;
protected final Requester builder;
private final String apiUrlTail;
/*package*/ GHCreateRepositoryBuilder(GitHub root, String apiUrlTail, String name) {
this.root = root;
this.apiUrlTail = apiUrlTail;
this.builder = new Requester(root);
this.builder.with("name",name);
}
public GHCreateRepositoryBuilder description(String description) {
this.builder.with("description",description);
return this;
}
public GHCreateRepositoryBuilder homepage(URL homepage) {
return homepage(homepage.toExternalForm());
}
public GHCreateRepositoryBuilder homepage(String homepage) {
this.builder.with("homepage",homepage);
return this;
}
/**
* Creates a private repository
*/
public GHCreateRepositoryBuilder private_(boolean b) {
this.builder.with("private",b);
return this;
}
/**
* Enables issue tracker
*/
public GHCreateRepositoryBuilder issues(boolean b) {
this.builder.with("has_issues",b);
return this;
}
/**
* Enables wiki
*/
public GHCreateRepositoryBuilder wiki(boolean b) {
this.builder.with("has_wiki",b);
return this;
}
/**
* Enables downloads
*/
public GHCreateRepositoryBuilder downloads(boolean b) {
this.builder.with("has_downloads",b);
return this;
}
/**
* If true, create an initial commit with empty README.
*/
public GHCreateRepositoryBuilder autoInit(boolean b) {
this.builder.with("auto_init",b);
return this;
}
/**
* Creates a default .gitignore
*
* See https://developer.github.com/v3/repos/#create
*/
public GHCreateRepositoryBuilder gitignoreTemplate(String language) {
this.builder.with("gitignore_template",language);
return this;
}
/**
* Desired license template to apply
*
* See https://developer.github.com/v3/repos/#create
*/
public GHCreateRepositoryBuilder licenseTemplate(String license) {
this.builder.with("license_template",license);
return this;
}
/**
* The team that gets granted access to this repository. Only valid for creating a repository in
* an organization.
*/
public GHCreateRepositoryBuilder team(GHTeam team) {
if (team!=null)
this.builder.with("team_id",team.getId());
return this;
}
/**
* Creates a repository with all the parameters.
*/
public GHRepository create() throws IOException {
return builder.method("POST").to(apiUrlTail, GHRepository.class).wrap(root);
}
}

View File

@@ -0,0 +1,46 @@
package org.kohsuke.github;
import java.io.IOException;
import org.apache.commons.lang.builder.ToStringBuilder;
public class GHDeployKey {
protected String url, key, title;
protected boolean verified;
protected int id;
private GHRepository owner;
public int getId() {
return id;
}
public String getKey() {
return key;
}
public String getTitle() {
return title;
}
public String getUrl() {
return url;
}
public boolean isVerified() {
return verified;
}
public GHDeployKey wrap(GHRepository repo) {
this.owner = repo;
return this;
}
public String toString() {
return new ToStringBuilder(this).append("title",title).append("id",id).append("key",key).toString();
}
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(String.format("/repos/%s/%s/keys/%d", owner.getOwnerName(), owner.getName(), id));
}
}

View File

@@ -0,0 +1,61 @@
package org.kohsuke.github;
import java.net.URL;
public class GHDeployment extends GHObject {
private GHRepository owner;
private GitHub root;
protected String sha;
protected String ref;
protected String task;
protected Object payload;
protected String environment;
protected String description;
protected String statuses_url;
protected String repository_url;
protected GHUser creator;
GHDeployment wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if(creator != null) creator.wrapUp(root);
return this;
}
public URL getStatusesUrl() {
return GitHub.parseURL(statuses_url);
}
public URL getRepositoryUrl() {
return GitHub.parseURL(repository_url);
}
public String getTask() {
return task;
}
public String getPayload() {
return (String) payload;
}
public String getEnvironment() {
return environment;
}
public GHUser getCreator() {
return creator;
}
public String getRef() {
return ref;
}
public String getSha(){
return sha;
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
}

View File

@@ -0,0 +1,55 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.List;
//Based on https://developer.github.com/v3/repos/deployments/#create-a-deployment
public class GHDeploymentBuilder {
private final GHRepository repo;
private final Requester builder;
public GHDeploymentBuilder(GHRepository repo) {
this.repo = repo;
this.builder = new Requester(repo.root);
}
public GHDeploymentBuilder(GHRepository repo, String ref) {
this(repo);
ref(ref);
}
public GHDeploymentBuilder ref(String branch) {
builder.with("ref",branch);
return this;
}
public GHDeploymentBuilder task(String task) {
builder.with("task",task);
return this;
}
public GHDeploymentBuilder autoMerge(boolean autoMerge) {
builder.with("auto_merge",autoMerge);
return this;
}
public GHDeploymentBuilder requiredContexts(List<String> requiredContexts) {
builder.with("required_contexts",requiredContexts);
return this;
}
public GHDeploymentBuilder payload(String payload) {
builder.with("payload",payload);
return this;
}
public GHDeploymentBuilder environment(String environment) {
builder.with("environment",environment);
return this;
}
public GHDeploymentBuilder description(String description) {
builder.with("description",description);
return this;
}
public GHDeployment create() throws IOException {
return builder.to(repo.getApiTailUrl("deployments"),GHDeployment.class).wrap(repo);
}
}

View File

@@ -0,0 +1,8 @@
package org.kohsuke.github;
/**
* Represents the state of deployment
*/
public enum GHDeploymentState {
PENDING, SUCCESS, ERROR, FAILURE
}

View File

@@ -0,0 +1,44 @@
package org.kohsuke.github;
import java.net.URL;
import java.util.Locale;
public class GHDeploymentStatus extends GHObject {
private GHRepository owner;
private GitHub root;
protected GHUser creator;
protected String state;
protected String description;
protected String target_url;
protected String deployment_url;
protected String repository_url;
public GHDeploymentStatus wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if(creator != null) creator.wrapUp(root);
return this;
}
public URL getTargetUrl() {
return GitHub.parseURL(target_url);
}
public URL getDeploymentUrl() {
return GitHub.parseURL(deployment_url);
}
public URL getRepositoryUrl() {
return GitHub.parseURL(repository_url);
}
public GHDeploymentState getState() {
return GHDeploymentState.valueOf(state.toUpperCase(Locale.ENGLISH));
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
}

View File

@@ -0,0 +1,31 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Locale;
public class GHDeploymentStatusBuilder {
private final Requester builder;
private GHRepository repo;
private int deploymentId;
public GHDeploymentStatusBuilder(GHRepository repo, int deploymentId, GHDeploymentState state) {
this.repo = repo;
this.deploymentId = deploymentId;
this.builder = new Requester(repo.root);
this.builder.with("state",state);
}
public GHDeploymentStatusBuilder description(String description) {
this.builder.with("description",description);
return this;
}
public GHDeploymentStatusBuilder targetUrl(String targetUrl) {
this.builder.with("target_url",targetUrl);
return this;
}
public GHDeploymentStatus create() throws IOException {
return builder.to(repo.getApiTailUrl("deployments")+"/"+deploymentId+"/statuses",GHDeploymentStatus.class).wrap(repo);
}
}

View File

@@ -1,8 +1,10 @@
package org.kohsuke.github;
/**
* Sort direction
*
* @author Kohsuke Kawaguchi
*/
class JsonOrganization {
public GHOrganization organization;
public enum GHDirection {
ASC, DESC
}

View File

@@ -23,19 +23,51 @@
*/
package org.kohsuke.github;
import java.util.List;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* @author Kohsuke Kawaguchi
* Represents an email of GitHub.
*
* @author Kelly Campbell
*/
class JsonPullRequests {
public List<GHPullRequest> pulls;
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD", "NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD"}, justification = "JSON API")
public class GHEmail {
public List<GHPullRequest> wrap(GHRepository owner) {
for (GHPullRequest pull : pulls) {
pull.owner = owner;
pull.root = owner.root;
protected String email;
protected boolean primary;
protected boolean verified;
public String getEmail() {
return email;
}
public boolean isPrimary() {
return primary;
}
public boolean isVerified() {
return verified;
}
@Override
public String toString() {
return "Email:"+email;
}
@Override
public int hashCode() {
return email.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof GHEmail) {
GHEmail that = (GHEmail) obj;
return this.email.equals(that.email);
}
return pulls;
return false;
}
}

View File

@@ -0,0 +1,51 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* Hook event type.
*
* @author Kohsuke Kawaguchi
* @see GHEventInfo
* @see <a href="https://developer.github.com/v3/activity/events/types/">Event type reference</a>
*/
public enum GHEvent {
COMMIT_COMMENT,
CREATE,
DELETE,
DEPLOYMENT,
DEPLOYMENT_STATUS,
DOWNLOAD,
FOLLOW,
FORK,
FORK_APPLY,
GIST,
GOLLUM,
ISSUE_COMMENT,
ISSUES,
MEMBER,
PAGE_BUILD,
PUBLIC,
PULL_REQUEST,
PULL_REQUEST_REVIEW_COMMENT,
PUSH,
RELEASE,
REPOSITORY, // only valid for org hooks
STATUS,
TEAM_ADD,
WATCH,
PING,
/**
* Special event type that means "every possible event"
*/
ALL;
/**
* Returns GitHub's internal representation of this event.
*/
String symbol() {
if (this==ALL) return "*";
return name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,106 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Date;
import com.fasterxml.jackson.databind.node.ObjectNode;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Represents an event.
*
* @author Kohsuke Kawaguchi
*/
@SuppressFBWarnings(value = "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", justification = "JSON API")
public class GHEventInfo {
private GitHub root;
// we don't want to expose Jackson dependency to the user. This needs databinding
private ObjectNode payload;
private long id;
private String created_at;
private String type;
// these are all shallow objects
private GHEventRepository repo;
private GHUser actor;
private GHOrganization org;
/**
* Inside the event JSON model, GitHub uses a slightly different format.
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" }, justification = "JSON API")
public static class GHEventRepository {
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
private int id;
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
private String url; // repository API URL
private String name; // owner/repo
}
public GHEvent getType() {
String t = type;
if (t.endsWith("Event")) t=t.substring(0,t.length()-5);
for (GHEvent e : GHEvent.values()) {
if (e.name().replace("_","").equalsIgnoreCase(t))
return e;
}
return null; // unknown event type
}
/*package*/ GHEventInfo wrapUp(GitHub root) {
this.root = root;
return this;
}
public long getId() {
return id;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
/**
* Repository where the change was made.
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" },
justification = "The field comes from JSON deserialization")
public GHRepository getRepository() throws IOException {
return root.getRepository(repo.name);
}
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" },
justification = "The field comes from JSON deserialization")
public GHUser getActor() throws IOException {
return root.getUser(actor.getLogin());
}
/**
* Quick way to just get the actor of the login.
*/
public String getActorLogin() throws IOException {
return actor.getLogin();
}
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" },
justification = "The field comes from JSON deserialization")
public GHOrganization getOrganization() throws IOException {
return (org==null || org.getLogin()==null) ? null : root.getOrganization(org.getLogin());
}
/**
* Retrieves the payload.
*
* @param type
* Specify one of the {@link GHEventPayload} subtype that defines a type-safe access to the payload.
* This must match the {@linkplain #getType() event type}.
*/
public <T extends GHEventPayload> T getPayload(Class<T> type) throws IOException {
T v = GitHub.MAPPER.readValue(payload.traverse(), type);
v.wrapUp(root);
return v;
}
}

View File

@@ -0,0 +1,671 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.Reader;
import java.util.List;
/**
* Base type for types used in databinding of the event payload.
*
* @see GitHub#parseEventPayload(Reader, Class)
* @see GHEventInfo#getPayload(Class)
*/
@SuppressWarnings("UnusedDeclaration")
public abstract class GHEventPayload {
protected GitHub root;
private GHUser sender;
/*package*/ GHEventPayload() {
}
/**
* Gets the sender or {@code null} if accessed via the events API.
* @return the sender or {@code null} if accessed via the events API.
*/
public GHUser getSender() {
return sender;
}
public void setSender(GHUser sender) {
this.sender = sender;
}
/*package*/ void wrapUp(GitHub root) {
this.root = root;
if (sender != null) {
sender.wrapUp(root);
}
}
/**
* A pull request status has changed.
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#pullrequestevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public static class PullRequest extends GHEventPayload {
private String action;
private int number;
private GHPullRequest pull_request;
private GHRepository repository;
public String getAction() {
return action;
}
public int getNumber() {
return number;
}
public GHPullRequest getPullRequest() {
pull_request.root = root;
return pull_request;
}
public GHRepository getRepository() {
return repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (pull_request==null)
throw new IllegalStateException("Expected pull_request payload, but got something else. Maybe we've got another type of event?");
if (repository!=null) {
repository.wrap(root);
pull_request.wrap(repository);
} else {
pull_request.wrapUp(root);
}
}
}
/**
* A comment was added to an issue
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#issuecommentevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD" },
justification = "Constructed by JSON deserialization")
public static class IssueComment extends GHEventPayload {
private String action;
private GHIssueComment comment;
private GHIssue issue;
private GHRepository repository;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization")
public String getAction() {
return action;
}
public GHIssueComment getComment() {
return comment;
}
public void setComment(GHIssueComment comment) {
this.comment = comment;
}
public GHIssue getIssue() {
return issue;
}
public void setIssue(GHIssue issue) {
this.issue = issue;
}
public GHRepository getRepository() {
return repository;
}
public void setRepository(GHRepository repository) {
this.repository = repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository != null) {
repository.wrap(root);
issue.wrap(repository);
} else {
issue.wrap(root);
}
comment.wrapUp(issue);
}
}
/**
* A comment was added to a commit
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#commitcommentevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD" },
justification = "Constructed by JSON deserialization")
public static class CommitComment extends GHEventPayload {
private String action;
private GHCommitComment comment;
private GHRepository repository;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization")
public String getAction() {
return action;
}
public GHCommitComment getComment() {
return comment;
}
public void setComment(GHCommitComment comment) {
this.comment = comment;
}
public GHRepository getRepository() {
return repository;
}
public void setRepository(GHRepository repository) {
this.repository = repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository != null) {
repository.wrap(root);
comment.wrap(repository);
}
}
}
/**
* A repository, branch, or tag was created
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#createevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD" },
justification = "Constructed by JSON deserialization")
public static class Create extends GHEventPayload {
private String ref;
@JsonProperty("ref_type")
private String refType;
@JsonProperty("master_branch")
private String masterBranch;
private String description;
private GHRepository repository;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization")
public String getRef() {
return ref;
}
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization")
public String getRefType() {
return refType;
}
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization")
public String getMasterBranch() {
return masterBranch;
}
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization")
public String getDescription() {
return description;
}
public GHRepository getRepository() {
return repository;
}
public void setRepository(GHRepository repository) {
this.repository = repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository != null) {
repository.wrap(root);
}
}
}
/**
* A branch, or tag was deleted
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#deleteevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD" },
justification = "Constructed by JSON deserialization")
public static class Delete extends GHEventPayload {
private String ref;
@JsonProperty("ref_type")
private String refType;
private GHRepository repository;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization")
public String getRef() {
return ref;
}
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization")
public String getRefType() {
return refType;
}
public GHRepository getRepository() {
return repository;
}
public void setRepository(GHRepository repository) {
this.repository = repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository != null) {
repository.wrap(root);
}
}
}
/**
* A deployment
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#deploymentevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD" },
justification = "Constructed by JSON deserialization")
public static class Deployment extends GHEventPayload {
private GHDeployment deployment;
private GHRepository repository;
public GHDeployment getDeployment() {
return deployment;
}
public void setDeployment(GHDeployment deployment) {
this.deployment = deployment;
}
public GHRepository getRepository() {
return repository;
}
public void setRepository(GHRepository repository) {
this.repository = repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository != null) {
repository.wrap(root);
deployment.wrap(repository);
}
}
}
/**
* A deployment
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#deploymentstatusevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD" },
justification = "Constructed by JSON deserialization")
public static class DeploymentStatus extends GHEventPayload {
@JsonProperty("deployment_status")
private GHDeploymentStatus deploymentStatus;
private GHDeployment deployment;
private GHRepository repository;
public GHDeploymentStatus getDeploymentStatus() {
return deploymentStatus;
}
public void setDeploymentStatus(GHDeploymentStatus deploymentStatus) {
this.deploymentStatus = deploymentStatus;
}
public GHDeployment getDeployment() {
return deployment;
}
public void setDeployment(GHDeployment deployment) {
this.deployment = deployment;
}
public GHRepository getRepository() {
return repository;
}
public void setRepository(GHRepository repository) {
this.repository = repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository != null) {
repository.wrap(root);
deployment.wrap(repository);
deploymentStatus.wrap(repository);
}
}
}
/**
* A user forked a repository
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#forkevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD" },
justification = "Constructed by JSON deserialization")
public static class Fork extends GHEventPayload {
private GHRepository forkee;
private GHRepository repository;
public GHRepository getForkee() {
return forkee;
}
public void setForkee(GHRepository forkee) {
this.forkee = forkee;
}
public GHRepository getRepository() {
return repository;
}
public void setRepository(GHRepository repository) {
this.repository = repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
forkee.wrap(root);
if (repository != null) {
repository.wrap(root);
}
}
}
/**
* A ping.
*/
public static class Ping extends GHEventPayload {
private GHRepository repository;
private GHOrganization organization;
public void setRepository(GHRepository repository) {
this.repository = repository;
}
public GHRepository getRepository() {
return repository;
}
public GHOrganization getOrganization() {
return organization;
}
public void setOrganization(GHOrganization organization) {
this.organization = organization;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository!=null)
repository.wrap(root);
if (organization != null) {
organization.wrapUp(root);
}
}
}
/**
* A repository was made public.
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#publicevent">authoritative source</a>
*/
public static class Public extends GHEventPayload {
private GHRepository repository;
public void setRepository(GHRepository repository) {
this.repository = repository;
}
public GHRepository getRepository() {
return repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository!=null)
repository.wrap(root);
}
}
/**
* A commit was pushed.
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#pushevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD", "UUF_UNUSED_FIELD"},
justification = "Constructed by JSON deserialization")
public static class Push extends GHEventPayload {
private String head, before;
private boolean created, deleted, forced;
private String ref;
private int size;
private List<PushCommit> commits;
private GHRepository repository;
private Pusher pusher;
/**
* The SHA of the HEAD commit on the repository
*/
public String getHead() {
return head;
}
/**
* This is undocumented, but it looks like this captures the commit that the ref was pointing to
* before the push.
*/
public String getBefore() {
return before;
}
@JsonSetter // alias
private void setAfter(String after) {
head = after;
}
/**
* The full Git ref that was pushed. Example: “refs/heads/master”
*/
public String getRef() {
return ref;
}
/**
* The number of commits in the push.
* Is this always the same as {@code getCommits().size()}?
*/
public int getSize() {
return size;
}
public boolean isCreated() {
return created;
}
public boolean isDeleted() {
return deleted;
}
public boolean isForced() {
return forced;
}
/**
* The list of pushed commits.
*/
public List<PushCommit> getCommits() {
return commits;
}
public GHRepository getRepository() {
return repository;
}
public Pusher getPusher() {
return pusher;
}
public void setPusher(Pusher pusher) {
this.pusher = pusher;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository!=null)
repository.wrap(root);
}
public static class Pusher {
private String name, email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
/**
* Commit in a push
*/
public static class PushCommit {
private GitUser author;
private GitUser committer;
private String url, sha, message;
private boolean distinct;
private List<String> added, removed, modified;
public GitUser getAuthor() {
return author;
}
public GitUser getCommitter() {
return committer;
}
/**
* Points to the commit API resource.
*/
public String getUrl() {
return url;
}
public String getSha() {
return sha;
}
@JsonSetter
private void setId(String id) {
sha = id;
}
public String getMessage() {
return message;
}
/**
* Whether this commit is distinct from any that have been pushed before.
*/
public boolean isDistinct() {
return distinct;
}
public List<String> getAdded() {
return added;
}
public List<String> getRemoved() {
return removed;
}
public List<String> getModified() {
return modified;
}
}
}
/**
* A repository was created, deleted, made public, or made private.
*
* @see <a href="http://developer.github.com/v3/activity/events/types/#repositoryevent">authoritative source</a>
*/
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD", "UWF_UNWRITTEN_FIELD"},
justification = "Constructed by JSON deserialization")
public static class Repository extends GHEventPayload {
private String action;
private GHRepository repository;
private GHOrganization organization;
public String getAction() {
return action;
}
public void setRepository(GHRepository repository) {
this.repository = repository;
}
public GHRepository getRepository() {
return repository;
}
public GHOrganization getOrganization() {
return organization;
}
public void setOrganization(GHOrganization organization) {
this.organization = organization;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
repository.wrap(root);
if (organization != null) {
organization.wrapUp(root);
}
}
}
}

View File

@@ -0,0 +1,179 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* Gist
*
* @author Kohsuke Kawaguchi
* @see GHUser#listGists()
* @see GitHub#getGist(String)
* @see GitHub#createGist()
* @see <a href="https://developer.github.com/v3/gists/">documentation</a>
*/
public class GHGist extends GHObject {
/*package almost final*/ GHUser owner;
/*package almost final*/ GitHub root;
private String forks_url, commits_url, id, git_pull_url, git_push_url, html_url;
@JsonProperty("public")
private boolean _public;
private String description;
private int comments;
private String comments_url;
private Map<String,GHGistFile> files = new HashMap<String, GHGistFile>();
/**
* User that owns this Gist.
*/
public GHUser getOwner() {
return owner;
}
public String getForksUrl() {
return forks_url;
}
public String getCommitsUrl() {
return commits_url;
}
/**
* URL like https://gist.github.com/gists/12345.git
*/
public String getGitPullUrl() {
return git_pull_url;
}
public String getGitPushUrl() {
return git_push_url;
}
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
public boolean isPublic() {
return _public;
}
public String getDescription() {
return description;
}
public int getCommentCount() {
return comments;
}
/**
* API URL of listing comments.
*/
public String getCommentsUrl() {
return comments_url;
}
public GHGistFile getFile(String name) {
return files.get(name);
}
public Map<String,GHGistFile> getFiles() {
return Collections.unmodifiableMap(files);
}
/*package*/ GHGist wrapUp(GHUser owner) {
this.owner = owner;
this.root = owner.root;
wrapUp();
return this;
}
/**
* Used when caller obtains {@link GHGist} without knowing its owner.
* A partially constructed owner object is interned.
*/
/*package*/ GHGist wrapUp(GitHub root) throws IOException {
this.owner = root.getUser(owner);
this.root = root;
wrapUp();
return this;
}
private void wrapUp() {
for (Entry<String, GHGistFile> e : files.entrySet()) {
e.getValue().fileName = e.getKey();
}
}
String getApiTailUrl(String tail) {
return "/gists/" + id + '/' + tail;
}
public void star() throws IOException {
new Requester(root).method("PUT").to(getApiTailUrl("star"));
}
public void unstar() throws IOException {
new Requester(root).method("DELETE").to(getApiTailUrl("star"));
}
public boolean isStarred() throws IOException {
return root.retrieve().asHttpStatusCode(getApiTailUrl("star"))/100==2;
}
/**
* Forks this gist into your own.
*/
public GHGist fork() throws IOException {
return new Requester(root).to(getApiTailUrl("forks"),GHGist.class).wrapUp(root);
}
public PagedIterable<GHGist> listForks() {
return new PagedIterable<GHGist>() {
public PagedIterator<GHGist> _iterator(int pageSize) {
return new PagedIterator<GHGist>(root.retrieve().asIterator(getApiTailUrl("forks"), GHGist[].class, pageSize)) {
@Override
protected void wrapUp(GHGist[] page) {
try {
for (GHGist c : page)
c.wrapUp(root);
} catch (IOException e) {
throw new Error(e);
}
}
};
}
};
}
/**
* Deletes this gist.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to("/gists/" + id);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GHGist ghGist = (GHGist) o;
return id.equals(ghGist.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View File

@@ -0,0 +1,48 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
/**
* Builder pattern for creating a new Gist.
*
* @author Kohsuke Kawaguchi
* @see GitHub#createGist()
*/
public class GHGistBuilder {
private final GitHub root;
private final Requester req;
private final LinkedHashMap<String,Object> files = new LinkedHashMap<String, Object>();
public GHGistBuilder(GitHub root) {
this.root = root;
req = new Requester(root);
}
public GHGistBuilder description(String desc) {
req.with("description",desc);
return this;
}
public GHGistBuilder public_(boolean v) {
req.with("public",v);
return this;
}
/**
* Adds a new file.
*/
public GHGistBuilder file(String fileName, String content) {
files.put(fileName, Collections.singletonMap("content", content));
return this;
}
/**
* Creates a Gist based on the parameters specified thus far.
*/
public GHGist create() throws IOException {
req._with("files",files);
return req.to("/gists",GHGist.class).wrapUp(root);
}
}

View File

@@ -0,0 +1,60 @@
package org.kohsuke.github;
/**
* A file inside {@link GHGist}
*
* @author Kohsuke Kawaguchi
* @see GHGist#getFile(String)
* @see GHGist#getFiles()
*/
public class GHGistFile {
/*package almost final*/ String fileName;
private int size;
private String raw_url, type, language, content;
private boolean truncated;
public String getFileName() {
return fileName;
}
/**
* File size in bytes.
*/
public int getSize() {
return size;
}
/**
* URL that serves this file as-is.
*/
public String getRawUrl() {
return raw_url;
}
/**
* Content type of this Gist, such as "text/plain"
*/
public String getType() {
return type;
}
public String getLanguage() {
return language;
}
/**
* Content of this file.
*/
public String getContent() {
return content;
}
/**
* (?) indicates if {@link #getContent()} contains a truncated content.
*/
public boolean isTruncated() {
return truncated;
}
}

View File

@@ -0,0 +1,62 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* @author Kohsuke Kawaguchi
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public abstract class GHHook extends GHObject {
String name;
List<String> events;
boolean active;
Map<String,String> config;
public String getName() {
return name;
}
public EnumSet<GHEvent> getEvents() {
EnumSet<GHEvent> s = EnumSet.noneOf(GHEvent.class);
for (String e : events) {
if (e.equals("*")) s.add(GHEvent.ALL);
else s.add(Enum.valueOf(GHEvent.class, e.toUpperCase(Locale.ENGLISH)));
}
return s;
}
public boolean isActive() {
return active;
}
public Map<String, String> getConfig() {
return Collections.unmodifiableMap(config);
}
/**
* Deletes this hook.
*/
public void delete() throws IOException {
new Requester(getRoot()).method("DELETE").to(getApiRoute());
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
abstract GitHub getRoot();
abstract String getApiRoute();
}

View File

@@ -0,0 +1,131 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* Utility class for creating and retrieving webhooks; removes duplication between GHOrganization and GHRepository
* functionality
*/
class GHHooks {
static abstract class Context {
private final GitHub root;
private Context(GitHub root) {
this.root = root;
}
public List<GHHook> getHooks() throws IOException {
GHHook [] hookArray = root.retrieve().to(collection(),collectionClass()); // jdk/eclipse bug requires this to be on separate line
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(hookArray));
for (GHHook h : list)
wrap(h);
return list;
}
public GHHook getHook(int id) throws IOException {
GHHook hook = root.retrieve().to(collection() + "/" + id, clazz());
return wrap(hook);
}
public GHHook createHook(String name, Map<String, String> config, Collection<GHEvent> events, boolean active) throws IOException {
List<String> ea = null;
if (events!=null) {
ea = new ArrayList<String>();
for (GHEvent e : events)
ea.add(e.symbol());
}
GHHook hook = new Requester(root)
.with("name", name)
.with("active", active)
._with("config", config)
._with("events", ea)
.to(collection(), clazz());
return wrap(hook);
}
abstract String collection();
abstract Class<? extends GHHook[]> collectionClass();
abstract Class<? extends GHHook> clazz();
abstract GHHook wrap(GHHook hook);
}
private static class RepoContext extends Context {
private final GHRepository repository;
private final GHUser owner;
private RepoContext(GHRepository repository, GHUser owner) {
super(repository.root);
this.repository = repository;
this.owner = owner;
}
@Override
String collection() {
return String.format("/repos/%s/%s/hooks", owner.getLogin(), repository.getName());
}
@Override
Class<? extends GHHook[]> collectionClass() {
return GHRepoHook[].class;
}
@Override
Class<? extends GHHook> clazz() {
return GHRepoHook.class;
}
@Override
GHHook wrap(GHHook hook) {
return ((GHRepoHook)hook).wrap(repository);
}
}
private static class OrgContext extends Context {
private final GHOrganization organization;
private OrgContext(GHOrganization organization) {
super(organization.root);
this.organization = organization;
}
@Override
String collection() {
return String.format("/orgs/%s/hooks", organization.getLogin());
}
@Override
Class<? extends GHHook[]> collectionClass() {
return GHOrgHook[].class;
}
@Override
Class<? extends GHHook> clazz() {
return GHOrgHook.class;
}
@Override
GHHook wrap(GHHook hook) {
return ((GHOrgHook)hook).wrap(organization);
}
}
static Context repoContext(GHRepository repository, GHUser owner) {
return new RepoContext(repository, owner);
}
static Context orgContext(GHOrganization organization) {
return new OrgContext(organization);
}
}

View File

@@ -24,27 +24,77 @@
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import static org.kohsuke.github.Previews.*;
/**
* Represents an issue on GitHub.
*
* @author Eric Maupin
* @author Kohsuke Kawaguchi
* @see GHRepository#getIssue(int)
* @see GitHub#searchIssues()
* @see GHIssueSearchBuilder
*/
public class GHIssue {
public class GHIssue extends GHObject implements Reactable{
GitHub root;
GHRepository owner;
// API v3
protected GHUser assignee; // not sure what this field is now that 'assignees' exist
protected GHUser[] assignees;
protected String state;
protected int number;
protected String closed_at;
protected int comments;
@SkipFromToString
protected String body;
// for backward compatibility with < 1.63, this collection needs to hold instances of Label, not GHLabel
protected List<Label> labels;
protected GHUser user;
protected String title, html_url;
protected GHIssue.PullRequest pull_request;
protected GHMilestone milestone;
protected GHUser closed_by;
private String gravatar_id,body,title,state,created_at,updated_at,html_url;
private List<String> labels;
private int number,votes,comments;
private int position;
/**
* @deprecated use {@link GHLabel}
*/
public static class Label extends GHLabel {
}
/*package*/ GHIssue wrap(GHRepository owner) {
this.owner = owner;
if(milestone != null) milestone.wrap(owner);
return wrap(owner.root);
}
/*package*/ GHIssue wrap(GitHub root) {
this.root = root;
if(assignee != null) assignee.wrapUp(root);
if(assignees!=null) GHUser.wrap(assignees,root);
if(user != null) user.wrapUp(root);
if(closed_by != null) closed_by.wrapUp(root);
return this;
}
/*package*/ static GHIssue[] wrap(GHIssue[] issues, GHRepository owner) {
for (GHIssue i : issues)
i.wrap(owner);
return issues;
}
/**
* Repository to which the issue belongs.
@@ -71,7 +121,7 @@ public class GHIssue {
* The HTML page of this issue,
* like https://github.com/jenkinsci/jenkins/issues/100
*/
public URL getUrl() {
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
@@ -80,50 +130,229 @@ public class GHIssue {
}
public GHIssueState getState() {
return Enum.valueOf(GHIssueState.class, state);
return Enum.valueOf(GHIssueState.class, state.toUpperCase(Locale.ENGLISH));
}
public Collection<String> getLabels() {
return Collections.unmodifiableList(labels);
public Collection<GHLabel> getLabels() throws IOException {
if(labels == null){
return Collections.emptyList();
}
return Collections.<GHLabel>unmodifiableList(labels);
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
public Date getClosedAt() {
return GitHub.parseDate(closed_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
public URL getApiURL(){
return GitHub.parseURL(url);
}
/**
* Updates the issue by adding a comment.
*
* @return
* Newly posted comment.
*/
public void comment(String message) throws IOException {
new Poster(root).withCredential().with("comment",message).to(getApiRoute("comment"));
@WithBridgeMethods(void.class)
public GHIssueComment comment(String message) throws IOException {
GHIssueComment r = new Requester(root).with("body",message).to(getIssuesApiRoute() + "/comments", GHIssueComment.class);
return r.wrapUp(this);
}
private void edit(String key, Object value) throws IOException {
new Requester(root)._with(key, value).method("PATCH").to(getApiRoute());
}
private void editIssue(String key, Object value) throws IOException {
new Requester(root)._with(key, value).method("PATCH").to(getIssuesApiRoute());
}
/**
* Closes this issue.
*/
public void close() throws IOException {
new Poster(root).withCredential().to(getApiRoute("close"));
edit("state", "closed");
}
/**
* Reopens this issue.
*/
public void reopen() throws IOException {
new Poster(root).withCredential().to(getApiRoute("reopen"));
edit("state", "open");
}
public void setTitle(String title) throws IOException {
edit("title",title);
}
public void setBody(String body) throws IOException {
edit("body",body);
}
public void assignTo(GHUser user) throws IOException {
setAssignees(user);
}
public void setLabels(String... labels) throws IOException {
editIssue("labels",labels);
}
/**
* Obtains all the comments associated with this issue.
*
* @see #listComments()
*/
public List<GHIssueComment> getComments() throws IOException {
return root.retrieve(getApiRoute("comments"), JsonIssueComments.class).wrap(this);
return listComments().asList();
}
/**
* Obtains all the comments associated with this issue.
*/
public PagedIterable<GHIssueComment> listComments() throws IOException {
return new PagedIterable<GHIssueComment>() {
public PagedIterator<GHIssueComment> _iterator(int pageSize) {
return new PagedIterator<GHIssueComment>(root.retrieve().asIterator(getIssuesApiRoute() + "/comments", GHIssueComment[].class, pageSize)) {
protected void wrapUp(GHIssueComment[] page) {
for (GHIssueComment c : page)
c.wrapUp(GHIssue.this);
}
};
}
};
}
private String getApiRoute(String verb) {
return "/issues/"+verb+"/"+owner.getOwnerName()+"/"+owner.getName()+"/"+number;
@Preview @Deprecated
public GHReaction createReaction(ReactionContent content) throws IOException {
return new Requester(owner.root)
.withPreview(SQUIRREL_GIRL)
.with("content", content.getContent())
.to(getApiRoute()+"/reactions", GHReaction.class).wrap(root);
}
}
@Preview @Deprecated
public PagedIterable<GHReaction> listReactions() {
return new PagedIterable<GHReaction>() {
public PagedIterator<GHReaction> _iterator(int pageSize) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) {
@Override
protected void wrapUp(GHReaction[] page) {
for (GHReaction c : page)
c.wrap(owner.root);
}
};
}
};
}
public void addAssignees(GHUser... assignees) throws IOException {
addAssignees(Arrays.asList(assignees));
}
public void addAssignees(Collection<GHUser> assignees) throws IOException {
List<String> names = toLogins(assignees);
root.retrieve().method("POST").with("assignees",names).to(getIssuesApiRoute()+"/assignees",this);
}
public void setAssignees(GHUser... assignees) throws IOException {
setAssignees(Arrays.asList(assignees));
}
public void setAssignees(Collection<GHUser> assignees) throws IOException {
editIssue("assignees",toLogins(assignees));
}
public void removeAssignees(GHUser... assignees) throws IOException {
removeAssignees(Arrays.asList(assignees));
}
public void removeAssignees(Collection<GHUser> assignees) throws IOException {
List<String> names = toLogins(assignees);
root.retrieve().method("DELETE").with("assignees",names).inBody().to(getIssuesApiRoute()+"/assignees",this);
}
private List<String> toLogins(Collection<GHUser> assignees) {
List<String> names = new ArrayList<String>(assignees.size());
for (GHUser a : assignees) {
names.add(a.getLogin());
}
return names;
}
protected String getApiRoute() {
return getIssuesApiRoute();
}
protected String getIssuesApiRoute() {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
}
public GHUser getAssignee() {
return assignee;
}
public List<GHUser> getAssignees() {
return Collections.unmodifiableList(Arrays.asList(assignees));
}
/**
* User who submitted the issue.
*/
public GHUser getUser() {
return user;
}
/**
* Reports who has closed the issue.
*
* <p>
* Note that GitHub doesn't always seem to report this information
* even for an issue that's already closed. See
* https://github.com/kohsuke/github-api/issues/60.
*/
public GHUser getClosedBy() {
if(!"closed".equals(state)) return null;
if(closed_by != null) return closed_by;
//TODO closed_by = owner.getIssue(number).getClosed_by();
return closed_by;
}
public int getCommentsCount(){
return comments;
}
/**
* Returns non-null if this issue is a shadow of a pull request.
*/
public PullRequest getPullRequest() {
return pull_request;
}
public boolean isPullRequest() {
return pull_request!=null;
}
public GHMilestone getMilestone() {
return milestone;
}
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD"},
justification = "JSON API")
public static class PullRequest{
private String diff_url, patch_url, html_url;
public URL getDiffUrl() {
return GitHub.parseURL(diff_url);
}
public URL getPatchUrl() {
return GitHub.parseURL(patch_url);
}
public URL getUrl() {
return GitHub.parseURL(html_url);
}
}
}

View File

@@ -0,0 +1,60 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
public class GHIssueBuilder {
private final GHRepository repo;
private final Requester builder;
private List<String> labels = new ArrayList<String>();
private List<String> assignees = new ArrayList<String>();
GHIssueBuilder(GHRepository repo, String title) {
this.repo = repo;
this.builder = new Requester(repo.root);
builder.with("title",title);
}
/**
* Sets the main text of an issue, which is arbitrary multi-line text.
*/
public GHIssueBuilder body(String str) {
builder.with("body",str);
return this;
}
public GHIssueBuilder assignee(GHUser user) {
if (user!=null)
assignees.add(user.getLogin());
return this;
}
public GHIssueBuilder assignee(String user) {
if (user!=null)
assignees.add(user);
return this;
}
public GHIssueBuilder milestone(GHMilestone milestone) {
if (milestone!=null)
builder.with("milestone",milestone.getNumber());
return this;
}
public GHIssueBuilder label(String label) {
if (label!=null)
labels.add(label);
return this;
}
/**
* Creates a new issue.
*/
public GHIssue create() throws IOException {
return builder.with("labels",labels).with("assignees",assignees).to(repo.getApiTailUrl("issues"),GHIssue.class).wrap(repo);
}
}

View File

@@ -24,18 +24,25 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Date;
import java.net.URL;
import static org.kohsuke.github.Previews.SQUIRREL_GIRL;
/**
* Comment to the issue
*
* @author Kohsuke Kawaguchi
*/
public class GHIssueComment {
public class GHIssueComment extends GHObject implements Reactable {
GHIssue owner;
private String body, gravatar_id, user, created_at, updated_at;
private int id;
private String body, gravatar_id;
private GHUser user; // not fully populated. beware.
/*package*/ GHIssueComment wrapUp(GHIssue owner) {
this.owner = owner;
return this;
}
/**
* Gets the issue to which this comment is associated.
@@ -51,29 +58,68 @@ public class GHIssueComment {
return body;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
public int getId() {
return id;
}
/**
* Gets the ID of the user who posted this comment.
*/
@Deprecated
public String getUserName() {
return user;
return user.getLogin();
}
/**
* Gets the user who posted this comment.
*/
public GHUser getUser() throws IOException {
return owner.root.getUser(user);
return owner == null || owner.root.isOffline() ? user : owner.root.getUser(user.getLogin());
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
/**
* Updates the body of the issue comment.
*/
public void update(String body) throws IOException {
new Requester(owner.root).with("body", body).method("PATCH").to(getApiRoute(), GHIssueComment.class);
this.body = body;
}
/**
* Deletes this issue comment.
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(getApiRoute());
}
@Preview @Deprecated
public GHReaction createReaction(ReactionContent content) throws IOException {
return new Requester(owner.root)
.withPreview(SQUIRREL_GIRL)
.with("content", content.getContent())
.to(getApiRoute()+"/reactions", GHReaction.class).wrap(owner.root);
}
@Preview @Deprecated
public PagedIterable<GHReaction> listReactions() {
return new PagedIterable<GHReaction>() {
public PagedIterator<GHReaction> _iterator(int pageSize) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) {
@Override
protected void wrapUp(GHReaction[] page) {
for (GHReaction c : page)
c.wrap(owner.root);
}
};
}
};
}
private String getApiRoute() {
return "/repos/"+owner.getRepository().getOwnerName()+"/"+owner.getRepository().getName()+"/issues/comments/" + id;
}
}

View File

@@ -0,0 +1,71 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* Search issues.
*
* @author Kohsuke Kawaguchi
* @see GitHub#searchIssues()
*/
public class GHIssueSearchBuilder extends GHSearchBuilder<GHIssue> {
/*package*/ GHIssueSearchBuilder(GitHub root) {
super(root,IssueSearchResult.class);
}
/**
* Search terms.
*/
public GHIssueSearchBuilder q(String term) {
super.q(term);
return this;
}
public GHIssueSearchBuilder mentions(GHUser u) {
return mentions(u.getLogin());
}
public GHIssueSearchBuilder mentions(String login) {
return q("mentions:"+login);
}
public GHIssueSearchBuilder isOpen() {
return q("is:open");
}
public GHIssueSearchBuilder isClosed() {
return q("is:closed");
}
public GHIssueSearchBuilder isMerged() {
return q("is:merged");
}
public GHIssueSearchBuilder order(GHDirection v) {
req.with("order",v);
return this;
}
public GHIssueSearchBuilder sort(Sort sort) {
req.with("sort",sort);
return this;
}
public enum Sort { COMMENTS, CREATED, UPDATED }
private static class IssueSearchResult extends SearchResult<GHIssue> {
private GHIssue[] items;
@Override
/*package*/ GHIssue[] getItems(GitHub root) {
for (GHIssue i : items)
i.wrap(root);
return items;
}
}
@Override
protected String getApiUrl() {
return "/search/issues";
}
}

View File

@@ -24,7 +24,11 @@
package org.kohsuke.github;
/**
* @see GHPullRequestQueryBuilder#state(GHIssueState)
*/
public enum GHIssueState {
OPEN,
CLOSED
CLOSED,
ALL
}

View File

@@ -0,0 +1,54 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* SSH public key.
*
* @author Kohsuke Kawaguchi
*/
@SuppressFBWarnings(value = "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", justification = "JSON API")
public class GHKey {
/*package almost final*/ GitHub root;
protected String url, key, title;
protected boolean verified;
protected int id;
public int getId() {
return id;
}
public String getKey() {
return key;
}
public String getTitle() {
return title;
}
/**
* Something like "https://api.github.com/user/keys/73593"
*/
public String getUrl() {
return url;
}
public GitHub getRoot() {
return root;
}
public boolean isVerified() {
return verified;
}
/*package*/ GHKey wrap(GitHub root) {
this.root = root;
return this;
}
public String toString() {
return new ToStringBuilder(this).append("title",title).append("id",id).append("key",key).toString();
}
}

View File

@@ -0,0 +1,37 @@
package org.kohsuke.github;
import java.io.IOException;
/**
* @author Kohsuke Kawaguchi
* @see GHIssue#getLabels()
* @see GHRepository#listLabels()
*/
public class GHLabel {
private String url, name, color;
private GHRepository repo;
public String getUrl() {
return url;
}
public String getName() {
return name;
}
/**
* Color code without leading '#', such as 'f29513'
*/
public String getColor() {
return color;
}
/*package*/ GHLabel wrapUp(GHRepository repo) {
this.repo = repo;
return this;
}
public void delete() throws IOException {
repo.root.retrieve().method("DELETE").to(url);
}
}

View File

@@ -0,0 +1,168 @@
/*
* The MIT License
*
* Copyright (c) 2016, Duncan Dickinson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import static org.kohsuke.github.Previews.DRAX;
/**
* The GitHub Preview API's license information
* <p>
* WARNING: This uses a PREVIEW API - subject to change.
*
* @author Duncan Dickinson
* @see GitHub#getLicense(String)
* @see GHRepository#getLicense()
* @see <a href="https://developer.github.com/v3/licenses/">https://developer.github.com/v3/licenses/</a>
*/
@Preview @Deprecated
@SuppressWarnings({"UnusedDeclaration"})
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHLicense extends GHObject {
@SuppressFBWarnings("IS2_INCONSISTENT_SYNC") // root is set before the object is returned to the app
/*package almost final*/ GitHub root;
// these fields are always present, even in the short form
protected String key, name;
// the rest is only after populated
protected Boolean featured;
protected String html_url, description, category, implementation, body;
protected List<String> required = new ArrayList<String>();
protected List<String> permitted = new ArrayList<String>();
protected List<String> forbidden = new ArrayList<String>();
/**
* @return a mnemonic for the license
*/
public String getKey() {
return key;
}
/**
* @return the license name
*/
public String getName() {
return name;
}
/**
* @return API URL of this object.
*/
@WithBridgeMethods(value = String.class, adapterMethod = "urlToString")
public URL getUrl() {
return GitHub.parseURL(url);
}
/**
* Featured licenses are bold in the new repository drop-down
*
* @return True if the license is featured, false otherwise
*/
public Boolean isFeatured() throws IOException {
populate();
return featured;
}
public URL getHtmlUrl() throws IOException {
populate();
return GitHub.parseURL(html_url);
}
public String getDescription() throws IOException {
populate();
return description;
}
public String getCategory() throws IOException {
populate();
return category;
}
public String getImplementation() throws IOException {
populate();
return implementation;
}
public List<String> getRequired() throws IOException {
populate();
return required;
}
public List<String> getPermitted() throws IOException {
populate();
return permitted;
}
public List<String> getForbidden() throws IOException {
populate();
return forbidden;
}
public String getBody() throws IOException {
populate();
return body;
}
/**
* Fully populate the data by retrieving missing data.
*
* Depending on the original API call where this object is created, it may not contain everything.
*/
protected synchronized void populate() throws IOException {
if (description!=null) return; // already populated
root.retrieve().withPreview(DRAX).to(url, this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof GHLicense)) return false;
GHLicense that = (GHLicense) o;
return this.url.equals(that.url);
}
@Override
public int hashCode() {
return url.hashCode();
}
/*package*/ GHLicense wrap(GitHub root) {
this.root = root;
return this;
}
}

View File

@@ -0,0 +1,84 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import java.util.Locale;
/**
* Represents a membership of a user in an organization.
*
* @author Kohsuke Kawaguchi
* @see GHMyself#listOrgMemberships()
*/
public class GHMembership /* extends GHObject --- but it doesn't have id, created_at, etc. */ {
GitHub root;
String url;
String state;
String role;
GHUser user;
GHOrganization organization;
public URL getUrl() {
return GitHub.parseURL(url);
}
public State getState() {
return Enum.valueOf(State.class, state.toUpperCase(Locale.ENGLISH));
}
public Role getRole() {
return Enum.valueOf(Role.class, role.toUpperCase(Locale.ENGLISH));
}
public GHUser getUser() {
return user;
}
public GHOrganization getOrganization() {
return organization;
}
/**
* Accepts a pending invitation to an organization.
*
* @see GHMyself#getMembership(GHOrganization)
*/
public void activate() throws IOException {
root.retrieve().method("PATCH").with("state",State.ACTIVE).to(url,this);
}
/*package*/ GHMembership wrap(GitHub root) {
this.root = root;
if (user!=null) user = root.getUser(user.wrapUp(root));
if (organization!=null) organization.wrapUp(root);
return this;
}
/*package*/ static void wrap(GHMembership[] page, GitHub root) {
for (GHMembership m : page)
m.wrap(root);
}
/**
* Role of a user in an organization.
*/
public enum Role {
/**
* Organization owner.
*/
ADMIN,
/**
* Non-owner organization member.
*/
MEMBER;
}
/**
* Whether a role is currently active or waiting for acceptance (pending)
*/
public enum State {
ACTIVE,
PENDING;
}
}

View File

@@ -0,0 +1,101 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.Locale;
/**
*
* @author Yusuke Kokubo
*
*/
public class GHMilestone extends GHObject {
GitHub root;
GHRepository owner;
GHUser creator;
private String state, due_on, title, description, html_url;
private int closed_issues, open_issues, number;
protected String closed_at;
public GitHub getRoot() {
return root;
}
public GHRepository getOwner() {
return owner;
}
public GHUser getCreator() {
return creator;
}
public Date getDueOn() {
if (due_on == null) return null;
return GitHub.parseDate(due_on);
}
/**
* When was this milestone closed?
*/
public Date getClosedAt() throws IOException {
return GitHub.parseDate(closed_at);
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public int getClosedIssues() {
return closed_issues;
}
public int getOpenIssues() {
return open_issues;
}
public int getNumber() {
return number;
}
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
public GHMilestoneState getState() {
return Enum.valueOf(GHMilestoneState.class, state.toUpperCase(Locale.ENGLISH));
}
/**
* Closes this milestone.
*/
public void close() throws IOException {
edit("state", "closed");
}
/**
* Reopens this milestone.
*/
public void reopen() throws IOException {
edit("state", "open");
}
private void edit(String key, Object value) throws IOException {
new Requester(root)._with(key, value).method("PATCH").to(getApiRoute());
}
protected String getApiRoute() {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/milestones/"+number;
}
public GHMilestone wrap(GHRepository repo) {
this.owner = repo;
this.root = repo.root;
return this;
}
}

View File

@@ -0,0 +1,11 @@
package org.kohsuke.github;
/**
*
* @author Yusuke Kokubo
*
*/
public enum GHMilestoneState {
OPEN,
CLOSED
}

View File

@@ -0,0 +1,218 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* Represents the account that's logging into GitHub.
*
* @author Kohsuke Kawaguchi
*/
public class GHMyself extends GHUser {
/**
* Type of repositories returned during listing.
*/
public enum RepositoryListFilter {
/**
* All public and private repositories that current user has access or collaborates to
*/
ALL,
/**
* Public and private repositories owned by current user
*/
OWNER,
/**
* Public repositories that current user has access or collaborates to
*/
PUBLIC,
/**
* Private repositories that current user has access or collaborates to
*/
PRIVATE,
/**
* Public and private repositories that current user is a member
*/
MEMBER;
}
/**
* @deprecated
* Use {@link #getEmails2()}
*/
public List<String> getEmails() throws IOException {
List<GHEmail> src = getEmails2();
List<String> r = new ArrayList<String>(src.size());
for (GHEmail e : src) {
r.add(e.getEmail());
}
return r;
}
/**
* Returns the read-only list of e-mail addresses configured for you.
*
* This corresponds to the stuff you configure in https://github.com/settings/emails,
* and not to be confused with {@link #getEmail()} that shows your public e-mail address
* set in https://github.com/settings/profile
*
* @return
* Always non-null.
*/
public List<GHEmail> getEmails2() throws IOException {
GHEmail[] addresses = root.retrieve().to("/user/emails", GHEmail[].class);
return Collections.unmodifiableList(Arrays.asList(addresses));
}
/**
* Returns the read-only list of all the pulic keys of the current user.
*
* NOTE: When using OAuth authenticaiton, the READ/WRITE User scope is
* required by the GitHub APIs, otherwise you will get a 404 NOT FOUND.
*
* @return
* Always non-null.
*/
public List<GHKey> getPublicKeys() throws IOException {
return Collections.unmodifiableList(Arrays.asList(root.retrieve().to("/user/keys", GHKey[].class)));
}
/**
* Returns the read-only list of all the public verified keys of the current user.
*
* Differently from the getPublicKeys() method, the retrieval of the user's
* verified public keys does not require any READ/WRITE OAuth Scope to the
* user's profile.
*
* @return
* Always non-null.
*/
public List<GHVerifiedKey> getPublicVerifiedKeys() throws IOException {
return Collections.unmodifiableList(Arrays.asList(root.retrieve().to(
"/users/" + getLogin() + "/keys", GHVerifiedKey[].class)));
}
/**
* Gets the organization that this user belongs to.
*/
public GHPersonSet<GHOrganization> getAllOrganizations() throws IOException {
GHPersonSet<GHOrganization> orgs = new GHPersonSet<GHOrganization>();
Set<String> names = new HashSet<String>();
for (GHOrganization o : root.retrieve().to("/user/orgs", GHOrganization[].class)) {
if (names.add(o.getLogin())) // in case of rumoured duplicates in the data
orgs.add(root.getOrganization(o.getLogin()));
}
return orgs;
}
/**
* Gets the all repositories this user owns (public and private).
*/
public synchronized Map<String,GHRepository> getAllRepositories() throws IOException {
Map<String,GHRepository> repositories = new TreeMap<String, GHRepository>();
for (GHRepository r : listAllRepositories()) {
repositories.put(r.getName(),r);
}
return Collections.unmodifiableMap(repositories);
}
/**
* Lists up all repositories this user owns (public and private).
*
* Unlike {@link #getAllRepositories()}, this does not wait until all the repositories are returned.
* Repositories are returned by GitHub API with a 30 items per page.
*/
@Override
public PagedIterable<GHRepository> listRepositories() {
return listRepositories(30);
}
/**
* List repositories that are accessible to the authenticated user (public and private) using the specified page size.
*
* This includes repositories owned by the authenticated user, repositories that belong to other users
* where the authenticated user is a collaborator, and other organizations' repositories that the authenticated
* user has access to through an organization membership.
*
* @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
*
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return listRepositories(pageSize, RepositoryListFilter.ALL);
}
/**
* List repositories of a certain type that are accessible by current authenticated user using the specified page size.
*
* @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
* @param repoType type of repository returned in the listing
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize, final RepositoryListFilter repoType) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().with("type",repoType).asIterator("/user/repos", GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
}.withPageSize(pageSize);
}
/**
* @deprecated
* Use {@link #listRepositories()}
*/
public PagedIterable<GHRepository> listAllRepositories() {
return listRepositories();
}
/**
* List your organization memberships
*/
public PagedIterable<GHMembership> listOrgMemberships() {
return listOrgMemberships(null);
}
/**
* List your organization memberships
*
* @param state
* Filter by a specific state
*/
public PagedIterable<GHMembership> listOrgMemberships(final GHMembership.State state) {
return new PagedIterable<GHMembership>() {
public PagedIterator<GHMembership> _iterator(int pageSize) {
return new PagedIterator<GHMembership>(root.retrieve().with("state",state).asIterator("/user/memberships/orgs", GHMembership[].class, pageSize)) {
@Override
protected void wrapUp(GHMembership[] page) {
GHMembership.wrap(page,root);
}
};
}
};
}
/**
* Gets your membership in a specific organization.
*/
public GHMembership getMembership(GHOrganization o) throws IOException {
return root.retrieve().to("/user/memberships/orgs/"+o.getLogin(),GHMembership.class).wrap(root);
}
// public void addEmails(Collection<String> emails) throws IOException {
//// new Requester(root,ApiVersion.V3).withCredential().to("/user/emails");
// root.retrieveWithAuth3()
// }
}

View File

@@ -0,0 +1,208 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Date;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Listens to GitHub notification stream.
*
* <p>
* This class supports two modes of retrieving notifications that can
* be controlled via {@link #nonBlocking(boolean)}.
*
* <p>
* In the blocking mode, which is the default, iterator will be infinite.
* The call to {@link Iterator#next()} will block until a new notification
* arrives. This is useful for application that runs perpetually and reacts
* to notifications.
*
* <p>
* In the non-blocking mode, the iterator will only report the set of
* notifications initially retrieved from GitHub, then quit. This is useful
* for a batch application to process the current set of notifications.
*
* @author Kohsuke Kawaguchi
* @see GitHub#listNotifications()
* @see GHRepository#listNotifications()
*/
public class GHNotificationStream implements Iterable<GHThread> {
private final GitHub root;
private Boolean all, participating;
private String since;
private String apiUrl;
private boolean nonBlocking = false;
/*package*/ GHNotificationStream(GitHub root, String apiUrl) {
this.root = root;
this.apiUrl = apiUrl;
}
/**
* Should the stream include notifications that are already read?
*/
public GHNotificationStream read(boolean v) {
all = v;
return this;
}
/**
* Should the stream be restricted to notifications in which the user
* is directly participating or mentioned?
*/
public GHNotificationStream participating(boolean v) {
participating = v;
return this;
}
public GHNotificationStream since(long timestamp) {
return since(new Date(timestamp));
}
public GHNotificationStream since(Date dt) {
since = GitHub.printDate(dt);
return this;
}
/**
* If set to true, {@link #iterator()} will stop iterating instead of blocking and
* waiting for the updates to arrive.
*/
public GHNotificationStream nonBlocking(boolean v) {
this.nonBlocking = v;
return this;
}
/**
* Returns an infinite blocking {@link Iterator} that returns
* {@link GHThread} as notifications arrive.
*/
public Iterator<GHThread> iterator() {
// capture the configuration setting here
final Requester req = new Requester(root).method("GET")
.with("all", all).with("participating", participating).with("since", since);
return new Iterator<GHThread>() {
/**
* Stuff we've fetched but haven't returned to the caller.
* Newer ones first.
*/
private GHThread[] threads = EMPTY_ARRAY;
/**
* Next element in {@link #threads} to return. This counts down.
*/
private int idx=-1;
/**
* threads whose updated_at is older than this should be ignored.
*/
private long lastUpdated = -1;
/**
* Next request should have "If-Modified-Since" header with this value.
*/
private String lastModified;
/**
* When is the next polling allowed?
*/
private long nextCheckTime = -1;
private GHThread next;
public GHThread next() {
if (next==null) {
next = fetch();
if (next==null)
throw new NoSuchElementException();
}
GHThread r = next;
next = null;
return r;
}
public boolean hasNext() {
if (next==null)
next = fetch();
return next!=null;
}
GHThread fetch() {
try {
while (true) {// loop until we get new threads to return
// if we have fetched un-returned threads, use them first
while (idx>=0) {
GHThread n = threads[idx--];
long nt = n.getUpdatedAt().getTime();
if (nt >= lastUpdated) {
lastUpdated = nt;
return n.wrap(root);
}
}
if (nonBlocking && nextCheckTime>=0)
return null; // nothing more to report, and we aren't blocking
// observe the polling interval before making the call
while (true) {
long now = System.currentTimeMillis();
if (nextCheckTime < now) break;
long waitTime = Math.min(Math.max(nextCheckTime - now, 1000), 60 * 1000);
Thread.sleep(waitTime);
}
req.setHeader("If-Modified-Since", lastModified);
threads = req.to(apiUrl, GHThread[].class);
if (threads==null) {
threads = EMPTY_ARRAY; // if unmodified, we get empty array
} else {
// we get a new batch, but we want to ignore the ones that we've seen
lastUpdated++;
}
idx = threads.length-1;
nextCheckTime = calcNextCheckTime();
lastModified = req.getResponseHeader("Last-Modified");
}
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private long calcNextCheckTime() {
String v = req.getResponseHeader("X-Poll-Interval");
if (v==null) v="60";
long seconds = Integer.parseInt(v);
return System.currentTimeMillis() + seconds*1000;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public void markAsRead() throws IOException {
markAsRead(-1);
}
/**
* Marks all the notifications as read.
*/
public void markAsRead(long timestamp) throws IOException {
final Requester req = new Requester(root).method("PUT");
if (timestamp>=0)
req.with("last_read_at", GitHub.printDate(new Date(timestamp)));
req.asHttpStatusCode(apiUrl);
}
private static final GHThread[] EMPTY_ARRAY = new GHThread[0];
}

View File

@@ -0,0 +1,115 @@
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang.reflect.FieldUtils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Date;
/**
* Most (all?) domain objects in GitHub seems to have these 4 properties.
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public abstract class GHObject {
protected String url;
protected int id;
protected String created_at;
protected String updated_at;
/*package*/ GHObject() {
}
/**
* When was this resource created?
*/
@WithBridgeMethods(value=String.class, adapterMethod="createdAtStr")
public Date getCreatedAt() throws IOException {
return GitHub.parseDate(created_at);
}
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getCreatedAt")
private Object createdAtStr(Date id, Class type) {
return created_at;
}
/**
* API URL of this object.
*/
@WithBridgeMethods(value=String.class, adapterMethod="urlToString")
public URL getUrl() {
return GitHub.parseURL(url);
}
/**
* URL of this object for humans, which renders some HTML.
*/
@WithBridgeMethods(value=String.class, adapterMethod="urlToString")
public abstract URL getHtmlUrl() throws IOException;
/**
* When was this resource last updated?
*/
public Date getUpdatedAt() throws IOException {
return GitHub.parseDate(updated_at);
}
/**
* Unique ID number of this resource.
*/
@WithBridgeMethods(value=String.class, adapterMethod="intToString")
public int getId() {
return id;
}
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getId")
private Object intToString(int id, Class type) {
return String.valueOf(id);
}
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getHtmlUrl")
private Object urlToString(URL url, Class type) {
return url==null ? null : url.toString();
}
/**
* String representation to assist debugging and inspection. The output format of this string
* is not a committed part of the API and is subject to change.
*/
@Override
public String toString() {
return new ReflectionToStringBuilder(this, TOSTRING_STYLE, null, null, false, false) {
@Override
protected boolean accept(Field field) {
return super.accept(field) && !field.isAnnotationPresent(SkipFromToString.class);
}
}.toString();
}
private static final ToStringStyle TOSTRING_STYLE = new ToStringStyle() {
{
this.setUseShortClassName(true);
}
@Override
public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
// skip unimportant properties. '_' is a heuristics as important properties tend to have short names
if (fieldName.contains("_"))
return;
// avoid recursing other GHObject
if (value instanceof GHObject)
return;
// likewise no point in showing root
if (value instanceof GitHub)
return;
super.append(buffer,fieldName,value,fullDetail);
}
};
}

View File

@@ -0,0 +1,27 @@
/*
* © Copyright 2015 - SourceClear Inc
*/
package org.kohsuke.github;
class GHOrgHook extends GHHook {
/**
* Organization that the hook belongs to.
*/
/*package*/ transient GHOrganization organization;
/*package*/ GHOrgHook wrap(GHOrganization owner) {
this.organization = owner;
return this;
}
@Override
GitHub getRoot() {
return organization.root;
}
@Override
String getApiRoute() {
return String.format("/orgs/%s/hooks/%d", organization.getLogin(), id);
}
}

View File

@@ -1,52 +1,196 @@
package org.kohsuke.github;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* @author Kohsuke Kawaguchi
*/
public class GHOrganization extends GHPerson {
/*package*/ GHOrganization wrapUp(GitHub root) {
return (GHOrganization)super.wrapUp(root);
}
/**
* Creates a new repository.
*
* @return
* Newly created repository.
* @deprecated
* Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect.
*/
public GHRepository createRepository(String name, String description, String homepage, String team, boolean isPublic) throws IOException {
// such API doesn't exist, so fall back to HTML scraping
WebClient wc = root.createWebClient();
HtmlPage pg = (HtmlPage)wc.getPage("https://github.com/organizations/"+login+"/repositories/new");
HtmlForm f = pg.getForms().get(1);
f.getInputByName("repository[name]").setValueAttribute(name);
f.getInputByName("repository[description]").setValueAttribute(description);
f.getInputByName("repository[homepage]").setValueAttribute(homepage);
f.getSelectByName("team_id").getOptionByText(team).setSelected(true);
f.submit(f.getButtonByCaption("Create Repository"));
GHTeam t = getTeams().get(team);
if (t==null)
throw new IllegalArgumentException("No such team: "+team);
return createRepository(name, description, homepage, t, isPublic);
}
return getRepository(name);
/**
* @deprecated
* Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect.
*/
public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException {
if (team==null)
throw new IllegalArgumentException("Invalid team");
return createRepository(name).description(description).homepage(homepage).private_(!isPublic).team(team).create();
}
// GHRepository r = new Poster(root).withCredential()
// .with("name", name).with("description", description).with("homepage", homepage)
// .with("public", isPublic ? 1 : 0).to(root.getApiURL("/organizations/"+login+"/repos/create"), JsonRepository.class).repository;
// r.root = root;
// return r;
/**
* Starts a builder that creates a new repository.
*
* <p>
* You use the returned builder to set various properties, then call {@link GHCreateRepositoryBuilder#create()}
* to finally createa repository.
*/
public GHCreateRepositoryBuilder createRepository(String name) throws IOException {
return new GHCreateRepositoryBuilder(root,"/orgs/"+login+"/repos",name);
}
/**
* Teams by their names.
*/
public Map<String,GHTeam> getTeams() throws IOException {
return root.retrieveWithAuth("/organizations/"+login+"/teams",JsonTeams.class).toMap(this);
Map<String,GHTeam> r = new TreeMap<String, GHTeam>();
for (GHTeam t : listTeams()) {
r.put(t.getName(),t);
}
return r;
}
/**
* List up all the teams.
*/
public PagedIterable<GHTeam> listTeams() throws IOException {
return new PagedIterable<GHTeam>() {
public PagedIterator<GHTeam> _iterator(int pageSize) {
return new PagedIterator<GHTeam>(root.retrieve().asIterator(String.format("/orgs/%s/teams", login), GHTeam[].class, pageSize)) {
@Override
protected void wrapUp(GHTeam[] page) {
for (GHTeam c : page)
c.wrapUp(GHOrganization.this);
}
};
}
};
}
/**
* Finds a team that has the given name in its {@link GHTeam#getName()}
*/
public GHTeam getTeamByName(String name) throws IOException {
for (GHTeam t : listTeams()) {
if(t.getName().equals(name))
return t;
}
return null;
}
/**
* Finds a team that has the given slug in its {@link GHTeam#getSlug()}
*/
public GHTeam getTeamBySlug(String slug) throws IOException {
for (GHTeam t : listTeams()) {
if(t.getSlug().equals(slug))
return t;
}
return null;
}
/**
* Checks if this organization has the specified user as a member.
*/
public boolean hasMember(GHUser user) {
try {
root.retrieve().to("/orgs/" + login + "/members/" + user.getLogin());
return true;
} catch (IOException ignore) {
return false;
}
}
/**
* Remove a member of the organisation - which will remove them from
* all teams, and remove their access to the organizations repositories.
*/
public void remove(GHUser user) throws IOException {
root.retrieve().method("DELETE").to("/orgs/" + login + "/members/" + user.getLogin());
}
/**
* Checks if this organization has the specified user as a public member.
*/
public boolean hasPublicMember(GHUser user) {
try {
root.retrieve().to("/orgs/" + login + "/public_members/" + user.getLogin());
return true;
} catch (IOException ignore) {
return false;
}
}
/**
* Publicizes the membership.
*/
public void publicize(GHUser u) throws IOException {
root.retrieve().method("PUT").to("/orgs/" + login + "/public_members/" + u.getLogin(), null);
}
/**
* @deprecated use {@link #listMembers()}
*/
public List<GHUser> getMembers() throws IOException {
return listMembers().asList();
}
/**
* All the members of this organization.
*/
public PagedIterable<GHUser> listMembers() throws IOException {
return listMembers("members");
}
/**
* All the public members of this organization.
*/
public PagedIterable<GHUser> listPublicMembers() throws IOException {
return listMembers("public_members");
}
private PagedIterable<GHUser> listMembers(String suffix) throws IOException {
return listMembers(suffix, null);
}
public PagedIterable<GHUser> listMembersWithFilter(String filter) throws IOException {
return listMembers("members", filter);
}
private PagedIterable<GHUser> listMembers(final String suffix, final String filter) throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
String filterParams = (filter == null) ? "" : ("?filter=" + filter);
return new PagedIterator<GHUser>(root.retrieve().asIterator(String.format("/orgs/%s/%s%s", login, suffix, filterParams), GHUser[].class, pageSize)) {
@Override
protected void wrapUp(GHUser[] users) {
GHUser.wrap(users, root);
}
};
}
};
}
/**
* Conceals the membership.
*/
public void conceal(GHUser u) throws IOException {
root.retrieve().method("DELETE").to("/orgs/" + login + "/public_members/" + u.getLogin(), null);
}
public enum Permission { ADMIN, PUSH, PULL }
@@ -55,28 +199,33 @@ public class GHOrganization extends GHPerson {
* Creates a new team and assigns the repositories.
*/
public GHTeam createTeam(String name, Permission p, Collection<GHRepository> repositories) throws IOException {
Poster post = new Poster(root).withCredential().with("team[name]", name).with("team[permission]", p.name().toLowerCase());
Requester post = new Requester(root).with("name", name).with("permission", p);
List<String> repo_names = new ArrayList<String>();
for (GHRepository r : repositories) {
post.with("team[repo_names][]",r.getOwnerName()+'/'+r.getName());
repo_names.add(r.getName());
}
return post.to("/organizations/"+login+"/teams",JsonTeam.class).wrap(this);
post.with("repo_names",repo_names);
return post.method("POST").to("/orgs/" + login + "/teams", GHTeam.class).wrapUp(this);
}
public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException {
return createTeam(name,p, Arrays.asList(repositories));
return createTeam(name, p, Arrays.asList(repositories));
}
/**
* List up repositories that has some open pull requests.
*
* This used to be an efficient method that didn't involve traversing every repository, but now
* it doesn't do any optimization.
*/
public List<GHRepository> getRepositoriesWithOpenPullRequests() throws IOException {
WebClient wc = root.createWebClient();
HtmlPage pg = (HtmlPage)wc.getPage("https://github.com/organizations/"+login+"/dashboard/pulls");
List<GHRepository> r = new ArrayList<GHRepository>();
for (HtmlAnchor e : pg.getElementById("js-issue-list").<HtmlAnchor>selectNodes(".//UL[@class='smallnav']/LI[not(@class='zeroed')]/A")) {
String a = e.getHrefAttribute();
String name = a.substring(a.lastIndexOf('/')+1);
r.add(getRepository(name));
for (GHRepository repository : listRepositories(100)) {
repository.wrap(root);
List<GHPullRequest> pullRequests = repository.getPullRequests(GHIssueState.OPEN);
if (pullRequests.size() > 0) {
r.add(repository);
}
}
return r;
}
@@ -91,4 +240,78 @@ public class GHOrganization extends GHPerson {
}
return all;
}
/**
* Lists events performed by a user (this includes private events if the caller is authenticated.
*/
public PagedIterable<GHEventInfo> listEvents() throws IOException {
return new PagedIterable<GHEventInfo>() {
public PagedIterator<GHEventInfo> _iterator(int pageSize) {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/orgs/%s/events", login), GHEventInfo[].class, pageSize)) {
@Override
protected void wrapUp(GHEventInfo[] page) {
for (GHEventInfo c : page)
c.wrapUp(root);
}
};
}
};
}
/**
* Lists up all the repositories using the specified page size.
*
* @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
*
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
*/
@Override
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/orgs/" + login + "/repos?per_page=" + pageSize, GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
};
}
/**
* Retrieves the currently configured hooks.
*/
public List<GHHook> getHooks() throws IOException {
return GHHooks.orgContext(this).getHooks();
}
public GHHook getHook(int id) throws IOException {
return GHHooks.orgContext(this).getHook(id);
}
/**
*
* See https://api.github.com/hooks for possible names and their configuration scheme.
* TODO: produce type-safe binding
*
* @param name
* Type of the hook to be created. See https://api.github.com/hooks for possible names.
* @param config
* The configuration hash.
* @param events
* Can be null. Types of events to hook into.
*/
public GHHook createHook(String name, Map<String,String> config, Collection<GHEvent> events, boolean active) throws IOException {
return GHHooks.orgContext(this).createHook(name, config, events, active);
}
public GHHook createWebHook(URL url, Collection<GHEvent> events) throws IOException {
return createHook("web", Collections.singletonMap("url", url.toExternalForm()),events,true);
}
public GHHook createWebHook(URL url) throws IOException {
return createWebHook(url, null);
}
}

View File

@@ -1,7 +1,7 @@
/*
* The MIT License
*
* Copyright (c) 2010, Kohsuke Kawaguchi
* Copyright 2016 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,24 +21,39 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Locale;
/**
* @author Kohsuke Kawaguchi
* Permission for a user in a repository.
* @see <a href="https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level">API</a>
*/
class JsonRepositories {
public List<GHRepository> repositories;
/*package*/ class GHPermission {
public Map<String,GHRepository> wrap(GitHub root) {
Map<String,GHRepository> map = new TreeMap<String, GHRepository>();
for (GHRepository r : repositories) {
r.root = root;
map.put(r.getName(),r);
}
return map;
private String permission;
private GHUser user;
/**
* @return one of {@code admin}, {@code write}, {@code read}, or {@code none}
*/
public String getPermission() {
return permission;
}
public GHPermissionType getPermissionType() {
return Enum.valueOf(GHPermissionType.class, permission.toUpperCase(Locale.ENGLISH));
}
public GHUser getUser() {
return user;
}
void wrapUp(GitHub root) {
if (user != null) {
user.root = root;
}
}
}

View File

@@ -0,0 +1,11 @@
package org.kohsuke.github;
/**
* @author Kohsuke Kawaguchi
*/
public enum GHPermissionType {
ADMIN,
WRITE,
READ,
NONE
}

View File

@@ -1,7 +1,13 @@
package org.kohsuke.github;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -10,39 +16,239 @@ import java.util.TreeMap;
*
* @author Kohsuke Kawaguchi
*/
public abstract class GHPerson {
public abstract class GHPerson extends GHObject {
/*package almost final*/ GitHub root;
protected String gravatar_id,login;
// core data fields that exist even for "small" user data (such as the user info in pull request)
protected String login, avatar_url, gravatar_id;
protected int public_gist_count,public_repo_count,following_count,id;
// other fields (that only show up in full data)
protected String location,blog,email,name,company;
protected String html_url;
protected int followers,following,public_repos,public_gists;
/*package*/ GHPerson wrapUp(GitHub root) {
this.root = root;
return this;
}
/**
* Gets the repositories this user owns.
* Fully populate the data by retrieving missing data.
*
* Depending on the original API call where this object is created, it may not contain everything.
*/
protected synchronized void populate() throws IOException {
if (created_at!=null) {
return; // already populated
}
if (root.isOffline()) {
return; // cannot populate, will have to live with what we have
}
root.retrieve().to(url, this);
}
/**
* Gets the public repositories this user owns.
*
* <p>
* To list your own repositories, including private repositories,
* use {@link GHMyself#listRepositories()}
*/
public synchronized Map<String,GHRepository> getRepositories() throws IOException {
Map<String,GHRepository> repositories = new TreeMap<String, GHRepository>();
for (int i=1; ; i++) {
Map<String, GHRepository> map = root.retrieve("/repos/show/" + login + "?page=" + i, JsonRepositories.class).wrap(root);
repositories.putAll(map);
if (map.isEmpty()) break;
for (GHRepository r : listRepositories(100)) {
repositories.put(r.getName(),r);
}
return Collections.unmodifiableMap(repositories);
}
public GHRepository getRepository(String name) throws IOException {
return root.retrieve("/repos/show/" + login + '/' + name, JsonRepository.class).wrap(root);
/**
* Lists up all the repositories using a 30 items page size.
*
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
*/
public PagedIterable<GHRepository> listRepositories() {
return listRepositories(30);
}
/**
* Lists up all the repositories using the specified page size.
*
* @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
*
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/users/" + login + "/repos?per_page=" + pageSize, GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
};
}
/**
* Loads repository list in a paginated fashion.
*
* <p>
* For a person with a lot of repositories, GitHub returns the list of repositories in a paginated fashion.
* Unlike {@link #getRepositories()}, this method allows the caller to start processing data as it arrives.
*
* Every {@link Iterator#next()} call results in I/O. Exceptions that occur during the processing is wrapped
* into {@link Error}.
*
* @deprecated
* Use {@link #listRepositories()}
*/
public synchronized Iterable<List<GHRepository>> iterateRepositories(final int pageSize) {
return new Iterable<List<GHRepository>>() {
public Iterator<List<GHRepository>> iterator() {
final Iterator<GHRepository[]> pager = root.retrieve().asIterator("/users/" + login + "/repos?per_page="+pageSize,GHRepository[].class, pageSize);
return new Iterator<List<GHRepository>>() {
public boolean hasNext() {
return pager.hasNext();
}
public List<GHRepository> next() {
GHRepository[] batch = pager.next();
for (GHRepository r : batch)
r.root = root;
return Arrays.asList(batch);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
/**
*
* @return
* null if the repository was not found
*/
public GHRepository getRepository(String name) throws IOException {
try {
return root.retrieve().to("/repos/" + login + '/' + name, GHRepository.class).wrap(root);
} catch (FileNotFoundException e) {
return null;
}
}
/**
* Lists events for an organization or an user.
*/
public abstract PagedIterable<GHEventInfo> listEvents() throws IOException;
/**
* Gravatar ID of this user, like 0cb9832a01c22c083390f3c5dcb64105
*
* @deprecated
* No longer available in the v3 API.
*/
public String getGravatarId() {
return gravatar_id;
}
/**
* Returns a string like 'https://secure.gravatar.com/avatar/0cb9832a01c22c083390f3c5dcb64105'
* that indicates the avatar image URL.
*/
public String getAvatarUrl() {
if (avatar_url!=null)
return avatar_url;
if (gravatar_id!=null)
return "https://secure.gravatar.com/avatar/"+gravatar_id;
return null;
}
/**
* Gets the login ID of this user, like 'kohsuke'
*/
public String getLogin() {
return login;
}
/**
* Gets the human-readable name of the user, like "Kohsuke Kawaguchi"
*/
public String getName() throws IOException {
populate();
return name;
}
/**
* Gets the company name of this user, like "Sun Microsystems, Inc."
*/
public String getCompany() throws IOException {
populate();
return company;
}
/**
* Gets the location of this user, like "Santa Clara, California"
*/
public String getLocation() throws IOException {
populate();
return location;
}
public Date getCreatedAt() throws IOException {
populate();
return super.getCreatedAt();
}
public Date getUpdatedAt() throws IOException {
populate();
return super.getUpdatedAt();
}
/**
* Gets the blog URL of this user.
*/
public String getBlog() throws IOException {
populate();
return blog;
}
@Override
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
/**
* Gets the e-mail address of the user.
*/
public String getEmail() throws IOException {
populate();
return email;
}
public int getPublicGistCount() throws IOException {
populate();
return public_gists;
}
public int getPublicRepoCount() throws IOException {
populate();
return public_repos;
}
public int getFollowingCount() throws IOException {
populate();
return following;
}
public int getFollowersCount() throws IOException {
populate();
return followers;
}
}

View File

@@ -0,0 +1,43 @@
package org.kohsuke.github;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
/**
* Set of {@link GHPerson} with helper lookup methods.
*
* @author Kohsuke Kawaguchi
*/
public class GHPersonSet<T extends GHPerson> extends HashSet<T> {
private static final long serialVersionUID = 1L;
public GHPersonSet() {
}
public GHPersonSet(Collection<? extends T> c) {
super(c);
}
public GHPersonSet(T... c) {
super(Arrays.asList(c));
}
public GHPersonSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
}
public GHPersonSet(int initialCapacity) {
super(initialCapacity);
}
/**
* Finds the item by its login.
*/
public T byLogin(String login) {
for (T t : this)
if (t.getLogin().equals(login))
return t;
return null;
}
}

View File

@@ -23,22 +23,60 @@
*/
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.Date;
import java.util.Locale;
/**
* A pull request.
*
* @author Kohsuke Kawaguchi
* @see GHRepository#getPullRequest(int)
*/
@SuppressWarnings({"UnusedDeclaration"})
public class GHPullRequest extends GHIssue {
private String closed_at, patch_url, issue_updated_at;
private GHUser issue_user, user;
// labels??
private GHCommitPointer base, head;
private String mergeable, diff_url;
private String patch_url, diff_url, issue_url;
private GHCommitPointer base;
private String merged_at;
private GHCommitPointer head;
// details that are only available when obtained from ID
private GHUser merged_by;
private int review_comments, additions;
private boolean merged;
private Boolean mergeable;
private int deletions;
private String mergeable_state;
private int changed_files;
private String merge_commit_sha;
/**
* GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API
* route as opposed to 'issues' API route. This flag remembers whether we made the GET call on the 'issues' route
* on this object to fill in those missing details
*/
private transient boolean fetchedIssueDetails;
GHPullRequest wrapUp(GHRepository owner) {
this.wrap(owner);
return wrapUp(owner.root);
}
GHPullRequest wrapUp(GitHub root) {
if (owner != null) owner.wrap(root);
if (base != null) base.wrapUp(root);
if (head != null) head.wrapUp(root);
if (merged_by != null) merged_by.wrapUp(root);
return this;
}
@Override
protected String getApiRoute() {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/pulls/"+number;
}
/**
* The URL of the patch file.
@@ -47,12 +85,13 @@ public class GHPullRequest extends GHIssue {
public URL getPatchUrl() {
return GitHub.parseURL(patch_url);
}
/**
* User who submitted a pull request.
* The URL of the patch file.
* like https://github.com/jenkinsci/jenkins/pull/100.patch
*/
public GHUser getUser() {
return user;
public URL getIssueUrl() {
return GitHub.parseURL(issue_url);
}
/**
@@ -64,22 +103,15 @@ public class GHPullRequest extends GHIssue {
}
/**
* The change that should be pulled.
* The change that should be pulled. The tip of the commits to merge.
*/
public GHCommitPointer getHead() {
return head;
}
public Date getIssueUpdatedAt() {
return GitHub.parseDate(issue_updated_at);
}
/**
* The HTML page of this pull request,
* like https://github.com/jenkinsci/jenkins/pull/100
*/
public URL getUrl() {
return super.getUrl();
@Deprecated
public Date getIssueUpdatedAt() throws IOException {
return super.getUpdatedAt();
}
/**
@@ -90,7 +122,182 @@ public class GHPullRequest extends GHIssue {
return GitHub.parseURL(diff_url);
}
public Date getClosedAt() {
return GitHub.parseDate(closed_at);
public Date getMergedAt() {
return GitHub.parseDate(merged_at);
}
@Override
public Collection<GHLabel> getLabels() throws IOException {
fetchIssue();
return super.getLabels();
}
@Override
public GHUser getClosedBy() {
return null;
}
@Override
public PullRequest getPullRequest() {
return null;
}
//
// details that are only available via get with ID
//
public GHUser getMergedBy() throws IOException {
populate();
return merged_by;
}
public int getReviewComments() throws IOException {
populate();
return review_comments;
}
public int getAdditions() throws IOException {
populate();
return additions;
}
public boolean isMerged() throws IOException {
populate();
return merged;
}
public Boolean getMergeable() throws IOException {
populate();
return mergeable;
}
public int getDeletions() throws IOException {
populate();
return deletions;
}
public String getMergeableState() throws IOException {
populate();
return mergeable_state;
}
public int getChangedFiles() throws IOException {
populate();
return changed_files;
}
/**
* See <a href="https://developer.github.com/changes/2013-04-25-deprecating-merge-commit-sha">GitHub blog post</a>
*/
public String getMergeCommitSha() throws IOException {
populate();
return merge_commit_sha;
}
/**
* Fully populate the data by retrieving missing data.
*
* Depending on the original API call where this object is created, it may not contain everything.
*/
private void populate() throws IOException {
if (merged_by!=null) return; // already populated
if (root.isOffline()) {
return; // cannot populate, will have to live with what we have
}
root.retrieve().to(url, this).wrapUp(owner);
}
/**
* Retrieves all the commits associated to this pull request.
*/
public PagedIterable<GHPullRequestFileDetail> listFiles() {
return new PagedIterable<GHPullRequestFileDetail>() {
public PagedIterator<GHPullRequestFileDetail> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiRoute()),
GHPullRequestFileDetail[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequestFileDetail[] page) {
}
};
}
};
}
/**
* Obtains all the review comments associated with this pull request.
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return new PagedIterable<GHPullRequestReviewComment>() {
public PagedIterator<GHPullRequestReviewComment> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestReviewComment>(root.retrieve().asIterator(getApiRoute() + "/comments",
GHPullRequestReviewComment[].class, pageSize)) {
protected void wrapUp(GHPullRequestReviewComment[] page) {
for (GHPullRequestReviewComment c : page)
c.wrapUp(GHPullRequest.this);
}
};
}
};
}
/**
* Retrieves all the commits associated to this pull request.
*/
public PagedIterable<GHPullRequestCommitDetail> listCommits() {
return new PagedIterable<GHPullRequestCommitDetail>() {
public PagedIterator<GHPullRequestCommitDetail> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestCommitDetail>(root.retrieve().asIterator(
String.format("%s/commits", getApiRoute()),
GHPullRequestCommitDetail[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequestCommitDetail[] page) {
for (GHPullRequestCommitDetail c : page)
c.wrapUp(GHPullRequest.this);
}
};
}
};
}
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException {
return new Requester(root).method("POST")
.with("body", body)
.with("commit_id", sha)
.with("path", path)
.with("position", position)
.to(getApiRoute() + "/comments", GHPullRequestReviewComment.class).wrapUp(this);
}
/**
* Merge this pull request.
*
* The equivalent of the big green "Merge pull request" button.
*
* @param msg
* Commit message. If null, the default one will be used.
*/
public void merge(String msg) throws IOException {
merge(msg,null);
}
/**
* Merge this pull request.
*
* The equivalent of the big green "Merge pull request" button.
*
* @param msg
* Commit message. If null, the default one will be used.
* @param sha
* SHA that pull request head must match to allow merge.
*/
public void merge(String msg, String sha) throws IOException {
new Requester(root).method("PUT").with("commit_message",msg).with("sha",sha).to(getApiRoute()+"/merge");
}
private void fetchIssue() throws IOException {
if (!fetchedIssueDetails) {
new Requester(root).to(getIssuesApiRoute(), this);
fetchedIssueDetails = true;
}
}
}

View File

@@ -0,0 +1,150 @@
/*
* The MIT License
*
* Copyright (c) 2013, Luca Milanesio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URL;
/**
* Commit detail inside a {@link GHPullRequest}.
*
* @author Luca Milanesio
* @see GHPullRequest#listCommits()
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
public class GHPullRequestCommitDetail {
private GHPullRequest owner;
/*package*/ void wrapUp(GHPullRequest owner) {
this.owner = owner;
}
/**
* @deprecated Use {@link GitUser}
*/
public static class Authorship extends GitUser {
}
public static class Tree {
String sha;
String url;
public String getSha() {
return sha;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
}
public static class Commit {
Authorship author;
Authorship committer;
String message;
Tree tree;
String url;
int comment_count;
@WithBridgeMethods(value = Authorship.class, castRequired = true)
public GitUser getAuthor() {
return author;
}
@WithBridgeMethods(value = Authorship.class, castRequired = true)
public GitUser getCommitter() {
return committer;
}
public String getMessage() {
return message;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
public int getComment_count() {
return comment_count;
}
public Tree getTree() {
return tree;
}
}
public static class CommitPointer {
String sha;
String url;
String html_url;
public URL getUrl() {
return GitHub.parseURL(url);
}
public URL getHtml_url() {
return GitHub.parseURL(html_url);
}
public String getSha() {
return sha;
}
}
String sha;
Commit commit;
String url;
String html_url;
String comments_url;
CommitPointer[] parents;
public String getSha() {
return sha;
}
public Commit getCommit() {
return commit;
}
public URL getApiUrl() {
return GitHub.parseURL(url);
}
public URL getUrl() {
return GitHub.parseURL(html_url);
}
public URL getCommentsUrl() {
return GitHub.parseURL(comments_url);
}
public CommitPointer[] getParents() {
CommitPointer[] newValue = new CommitPointer[parents.length];
System.arraycopy(parents, 0, newValue, 0, parents.length);
return newValue;
}
}

View File

@@ -0,0 +1,86 @@
/*
* The MIT License
*
* Copyright (c) 2015, Julien Henry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.kohsuke.github;
import java.net.URL;
/**
* File detail inside a {@link GHPullRequest}.
*
* @author Julien Henry
* @see GHPullRequest#listFiles()
*/
public class GHPullRequestFileDetail {
String sha;
String filename;
String status;
int additions;
int deletions;
int changes;
String blob_url;
String raw_url;
String contents_url;
String patch;
public String getSha() {
return sha;
}
public String getFilename() {
return filename;
}
public String getStatus() {
return status;
}
public int getAdditions() {
return additions;
}
public int getDeletions() {
return deletions;
}
public int getChanges() {
return changes;
}
public URL getBlobUrl() {
return GitHub.parseURL(blob_url);
}
public URL getRawUrl() {
return GitHub.parseURL(raw_url);
}
public URL getContentsUrl() {
return GitHub.parseURL(contents_url);
}
public String getPatch() {
return patch;
}
}

View File

@@ -0,0 +1,58 @@
package org.kohsuke.github;
/**
* Lists up pull requests with some filtering and sorting.
*
* @author Kohsuke Kawaguchi
* @see GHRepository#queryPullRequests()
*/
public class GHPullRequestQueryBuilder extends GHQueryBuilder<GHPullRequest> {
private final GHRepository repo;
/*package*/ GHPullRequestQueryBuilder(GHRepository repo) {
super(repo.root);
this.repo = repo;
}
public GHPullRequestQueryBuilder state(GHIssueState state) {
req.with("state",state);
return this;
}
public GHPullRequestQueryBuilder head(String head) {
req.with("head",head);
return this;
}
public GHPullRequestQueryBuilder base(String base) {
req.with("base",base);
return this;
}
public GHPullRequestQueryBuilder sort(Sort sort) {
req.with("sort",sort);
return this;
}
public enum Sort { CREATED, UPDATED, POPULARITY, LONG_RUNNING }
public GHPullRequestQueryBuilder direction(GHDirection d) {
req.with("direction",d);
return this;
}
@Override
public PagedIterable<GHPullRequest> list() {
return new PagedIterable<GHPullRequest>() {
public PagedIterator<GHPullRequest> _iterator(int pageSize) {
return new PagedIterator<GHPullRequest>(req.asIterator(repo.getApiTailUrl("pulls"), GHPullRequest[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequest[] page) {
for (GHPullRequest pr : page)
pr.wrapUp(repo);
}
};
}
};
}
}

View File

@@ -0,0 +1,131 @@
/*
* The MIT License
*
* Copyright (c) 2010, Kohsuke Kawaguchi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import static org.kohsuke.github.Previews.*;
/**
* Review comment to the pull request
*
* @author Julien Henry
* @see GHPullRequest#listReviewComments()
* @see GHPullRequest#createReviewComment(String, String, String, int)
*/
public class GHPullRequestReviewComment extends GHObject implements Reactable {
GHPullRequest owner;
private String body;
private GHUser user;
private String path;
private int position;
private int originalPosition;
/*package*/ GHPullRequestReviewComment wrapUp(GHPullRequest owner) {
this.owner = owner;
return this;
}
/**
* Gets the pull request to which this review comment is associated.
*/
public GHPullRequest getParent() {
return owner;
}
/**
* The comment itself.
*/
public String getBody() {
return body;
}
/**
* Gets the user who posted this comment.
*/
public GHUser getUser() throws IOException {
return owner.root.getUser(user.getLogin());
}
public String getPath() {
return path;
}
public int getPosition() {
return position;
}
public int getOriginalPosition() {
return originalPosition;
}
@Override
public URL getHtmlUrl() {
return null;
}
protected String getApiRoute() {
return "/repos/"+owner.getRepository().getFullName()+"/pulls/comments/"+id;
}
/**
* Updates the comment.
*/
public void update(String body) throws IOException {
new Requester(owner.root).method("PATCH").with("body", body).to(getApiRoute(),this);
this.body = body;
}
/**
* Deletes this review comment.
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(getApiRoute());
}
@Preview @Deprecated
public GHReaction createReaction(ReactionContent content) throws IOException {
return new Requester(owner.root)
.withPreview(SQUIRREL_GIRL)
.with("content", content.getContent())
.to(getApiRoute()+"/reactions", GHReaction.class).wrap(owner.root);
}
@Preview @Deprecated
public PagedIterable<GHReaction> listReactions() {
return new PagedIterable<GHReaction>() {
public PagedIterator<GHReaction> _iterator(int pageSize) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) {
@Override
protected void wrapUp(GHReaction[] page) {
for (GHReaction c : page)
c.wrap(owner.root);
}
};
}
};
}
}

View File

@@ -0,0 +1,21 @@
package org.kohsuke.github;
/**
* Used to specify filters, sort order, etc for listing items in a collection.
*
* @author Kohsuke Kawaguchi
*/
public abstract class GHQueryBuilder<T> {
protected final GitHub root;
protected final Requester req;
/*package*/ GHQueryBuilder(GitHub root) {
this.root = root;
this.req = root.retrieve();
}
/**
* Start listing items by using the settings built up on this object.
*/
public abstract PagedIterable<T> list();
}

View File

@@ -0,0 +1,42 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
/**
* Rate limit.
* @author Kohsuke Kawaguchi
*/
public class GHRateLimit {
/**
* Remaining calls that can be made.
*/
public int remaining;
/**
* Allotted API call per hour.
*/
public int limit;
/**
* The time at which the current rate limit window resets in UTC epoch seconds.
*/
public Date reset;
/**
* Non-epoch date
*/
@SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
justification = "The value comes from JSON deserialization")
public Date getResetDate() {
return new Date(reset.getTime() * 1000);
}
@Override
public String toString() {
return "GHRateLimit{" +
"remaining=" + remaining +
", limit=" + limit +
", resetDate=" + getResetDate() +
'}';
}
}

View File

@@ -0,0 +1,55 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import static org.kohsuke.github.Previews.SQUIRREL_GIRL;
/**
* Reaction to issue, comment, PR, and so on.
*
* @author Kohsuke Kawaguchi
* @see Reactable
*/
@Preview @Deprecated
public class GHReaction extends GHObject {
private GitHub root;
private GHUser user;
private ReactionContent content;
/*package*/ GHReaction wrap(GitHub root) {
this.root = root;
user.wrapUp(root);
return this;
}
/**
* The kind of reaction left.
*/
public ReactionContent getContent() {
return content;
}
/**
* User who left the reaction.
*/
public GHUser getUser() {
return user;
}
/**
* Reaction has no HTML URL. Don't call this method.
*/
@Deprecated
public URL getHtmlUrl() {
return null;
}
/**
* Removes this reaction.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").withPreview(SQUIRREL_GIRL).to("/reactions/"+id);
}
}

View File

@@ -0,0 +1,107 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
/**
* Provides information on a Git ref from GitHub.
*
* @author Michael Clarke
*/
public class GHRef {
/*package almost final*/ GitHub root;
private String ref, url;
private GHObject object;
/**
* Name of the ref, such as "refs/tags/abc"
*/
public String getRef() {
return ref;
}
/**
* The API URL of this tag, such as https://api.github.com/repos/jenkinsci/jenkins/git/refs/tags/1.312
*/
public URL getUrl() {
return GitHub.parseURL(url);
}
/**
* The object that this ref points to.
*/
public GHObject getObject() {
return object;
}
/**
* Updates this ref to the specified commit.
*
* @param sha
* The SHA1 value to set this reference to
*/
public void updateTo(String sha) throws IOException {
updateTo(sha, false);
}
/**
* Updates this ref to the specified commit.
*
* @param sha
* The SHA1 value to set this reference to
* @param force
* Whether or not to force this ref update.
*/
public void updateTo(String sha, Boolean force) throws IOException {
new Requester(root)
.with("sha", sha).with("force", force).method("PATCH").to(url, GHRef.class).wrap(root);
}
/**
* Deletes this ref from the repository using the GitHub API.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(url);
}
/*package*/ GHRef wrap(GitHub root) {
this.root = root;
return this;
}
/*package*/ static GHRef[] wrap(GHRef[] in, GitHub root) {
for (GHRef r : in) {
r.wrap(root);
}
return in;
}
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public static class GHObject {
private String type, sha, url;
/**
* Type of the object, such as "commit"
*/
public String getType() {
return type;
}
/**
* SHA1 of this object.
*/
public String getSha() {
return sha;
}
/**
* API URL to this Git data, such as https://api.github.com/repos/jenkinsci/jenkins/git/commits/b72322675eb0114363a9a86e9ad5a170d1d07ac0
*/
public URL getUrl() {
return GitHub.parseURL(url);
}
}
}

View File

@@ -0,0 +1,161 @@
package org.kohsuke.github;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static java.lang.String.format;
/**
* Release in a github repository.
*
* @see GHRepository#getReleases()
* @see GHRepository#createRelease(String)
*/
public class GHRelease extends GHObject {
GitHub root;
GHRepository owner;
private String html_url;
private String assets_url;
private String upload_url;
private String tag_name;
private String target_commitish;
private String name;
private String body;
private boolean draft;
private boolean prerelease;
private Date published_at;
private String tarball_url;
private String zipball_url;
public String getAssetsUrl() {
return assets_url;
}
public String getBody() {
return body;
}
public boolean isDraft() {
return draft;
}
public GHRelease setDraft(boolean draft) throws IOException {
edit("draft", draft);
this.draft = draft;
return this;
}
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public GHRepository getOwner() {
return owner;
}
public void setOwner(GHRepository owner) {
this.owner = owner;
}
public boolean isPrerelease() {
return prerelease;
}
public Date getPublished_at() {
return new Date(published_at.getTime());
}
public GitHub getRoot() {
return root;
}
public String getTagName() {
return tag_name;
}
public String getTargetCommitish() {
return target_commitish;
}
public String getUploadUrl() {
return upload_url;
}
public String getZipballUrl() {
return zipball_url;
}
public String getTarballUrl() {
return tarball_url;
}
GHRelease wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
return this;
}
static GHRelease[] wrap(GHRelease[] releases, GHRepository owner) {
for (GHRelease release : releases) {
release.wrap(owner);
}
return releases;
}
/**
* Because github relies on SNI (http://en.wikipedia.org/wiki/Server_Name_Indication) this method will only work on
* Java 7 or greater. Options for fixing this for earlier JVMs can be found here
* http://stackoverflow.com/questions/12361090/server-name-indication-sni-on-java but involve more complicated
* handling of the HTTP requests to github's API.
*/
public GHAsset uploadAsset(File file, String contentType) throws IOException {
Requester builder = new Requester(owner.root);
String url = format("https://uploads.github.com%s/releases/%d/assets?name=%s",
owner.getApiTailUrl(""), getId(), file.getName());
return builder.contentType(contentType)
.with(new FileInputStream(file))
.to(url, GHAsset.class).wrap(this);
}
public List<GHAsset> getAssets() throws IOException {
Requester builder = new Requester(owner.root);
GHAsset[] assets = builder
.method("GET")
.to(getApiTailUrl("assets"), GHAsset[].class);
return Arrays.asList(GHAsset.wrap(assets, this));
}
/**
* Deletes this release.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(owner.getApiTailUrl("releases/"+id));
}
/**
* Edit this release.
*/
private void edit(String key, Object value) throws IOException {
new Requester(root)._with(key, value).method("PATCH").to(owner.getApiTailUrl("releases/"+id));
}
private String getApiTailUrl(String end) {
return owner.getApiTailUrl(format("releases/%s/%s",id,end));
}
}

View File

@@ -0,0 +1,79 @@
package org.kohsuke.github;
import java.io.IOException;
/**
* Builder pattern for creating a {@link GHRelease}
*
* @see GHRepository#createRelease(String)
*/
public class GHReleaseBuilder {
private final GHRepository repo;
private final Requester builder;
public GHReleaseBuilder(GHRepository ghRepository, String tag) {
this.repo = ghRepository;
this.builder = new Requester(repo.root);
builder.with("tag_name", tag);
}
/**
* @param body The release notes body.
*/
public GHReleaseBuilder body(String body) {
if (body != null) {
builder.with("body", body);
}
return this;
}
/**
* Specifies the commitish value that determines where the Git tag is created from. Can be any branch or
* commit SHA.
*
* @param commitish Defaults to the repositorys default branch (usually "master"). Unused if the Git tag
* already exists.
*/
public GHReleaseBuilder commitish(String commitish) {
if (commitish != null) {
builder.with("target_commitish", commitish);
}
return this;
}
/**
* Optional.
*
* @param draft {@code true} to create a draft (unpublished) release, {@code false} to create a published one.
* Default is {@code false}.
*/
public GHReleaseBuilder draft(boolean draft) {
builder.with("draft", draft);
return this;
}
/**
* @param name the name of the release
*/
public GHReleaseBuilder name(String name) {
if (name != null) {
builder.with("name", name);
}
return this;
}
/**
* Optional
*
* @param prerelease {@code true} to identify the release as a prerelease. {@code false} to identify the release
* as a full release. Default is {@code false}.
*/
public GHReleaseBuilder prerelease(boolean prerelease) {
builder.with("prerelease", prerelease);
return this;
}
public GHRelease create() throws IOException {
return builder.to(repo.getApiTailUrl("releases"), GHRelease.class).wrap(repo);
}
}

View File

@@ -0,0 +1,23 @@
package org.kohsuke.github;
class GHRepoHook extends GHHook {
/**
* Repository that the hook belongs to.
*/
/*package*/ transient GHRepository repository;
/*package*/ GHRepoHook wrap(GHRepository owner) {
this.repository = owner;
return this;
}
@Override
GitHub getRoot() {
return repository.root;
}
@Override
String getApiRoute() {
return String.format("/repos/%s/%s/hooks/%d", repository.getOwnerName(), repository.getName(), id);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* Search repositories.
*
* @author Kohsuke Kawaguchi
* @see GitHub#searchRepositories()
*/
public class GHRepositorySearchBuilder extends GHSearchBuilder<GHRepository> {
/*package*/ GHRepositorySearchBuilder(GitHub root) {
super(root,RepositorySearchResult.class);
}
/**
* Search terms.
*/
public GHRepositorySearchBuilder q(String term) {
super.q(term);
return this;
}
public GHRepositorySearchBuilder in(String v) {
return q("in:"+v);
}
public GHRepositorySearchBuilder size(String v) {
return q("size:"+v);
}
public GHRepositorySearchBuilder forks(String v) {
return q("forks:"+v);
}
public GHRepositorySearchBuilder created(String v) {
return q("created:"+v);
}
public GHRepositorySearchBuilder pushed(String v) {
return q("pushed:"+v);
}
public GHRepositorySearchBuilder user(String v) {
return q("user:"+v);
}
public GHRepositorySearchBuilder repo(String v) {
return q("repo:"+v);
}
public GHRepositorySearchBuilder language(String v) {
return q("language:"+v);
}
public GHRepositorySearchBuilder stars(String v) {
return q("stars:"+v);
}
public GHRepositorySearchBuilder order(GHDirection v) {
req.with("order",v);
return this;
}
public GHRepositorySearchBuilder sort(Sort sort) {
req.with("sort",sort);
return this;
}
public enum Sort { STARS, FORKS, UPDATED }
private static class RepositorySearchResult extends SearchResult<GHRepository> {
private GHRepository[] items;
@Override
/*package*/ GHRepository[] getItems(GitHub root) {
for (GHRepository item : items)
item.wrap(root);
return items;
}
}
@Override
protected String getApiUrl() {
return "/search/repositories";
}
}

View File

@@ -0,0 +1,52 @@
package org.kohsuke.github;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Base class for various search builders.
*
* @author Kohsuke Kawaguchi
*/
public abstract class GHSearchBuilder<T> extends GHQueryBuilder<T> {
protected final List<String> terms = new ArrayList<String>();
/**
* Data transfer object that receives the result of search.
*/
private final Class<? extends SearchResult<T>> receiverType;
/*package*/ GHSearchBuilder(GitHub root, Class<? extends SearchResult<T>> receiverType) {
super(root);
this.receiverType = receiverType;
}
/**
* Search terms.
*/
public GHQueryBuilder<T> q(String term) {
terms.add(term);
return this;
}
/**
* Performs the search.
*/
@Override
public PagedSearchIterable<T> list() {
return new PagedSearchIterable<T>(root) {
public PagedIterator<T> _iterator(int pageSize) {
req.set("q", StringUtils.join(terms, " "));
return new PagedIterator<T>(adapt(req.asIterator(getApiUrl(), receiverType, pageSize))) {
protected void wrapUp(T[] page) {
// SearchResult.getItems() should do it
}
};
}
};
}
protected abstract String getApiUrl();
}

View File

@@ -0,0 +1,51 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
/**
* A stargazer at a repository on GitHub.
*
* @author noctarius
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHStargazer {
private GHRepository repository;
private String starred_at;
private GHUser user;
/**
* Gets the repository that is stargazed
*
* @return the starred repository
*/
public GHRepository getRepository() {
return repository;
}
/**
* Gets the date when the repository was starred, however old stars before
* August 2012, will all show the date the API was changed to support starred_at.
*
* @return the date the stargazer was added
*/
public Date getStarredAt() {
return GitHub.parseDate(starred_at);
}
/**
* Gets the user that starred the repository
*
* @return the stargazer user
*/
public GHUser getUser() {
return user;
}
void wrapUp(GHRepository repository) {
this.repository = repository;
user.wrapUp(repository.root);
}
}

View File

@@ -0,0 +1,64 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Date;
/**
* Represents your subscribing to a repository / conversation thread..
*
* @author Kohsuke Kawaguchi
* @see GHRepository#getSubscription()
* @see GHThread#getSubscription()
*/
public class GHSubscription {
private String created_at, url, repository_url, reason;
private boolean subscribed, ignored;
private GitHub root;
private GHRepository repo;
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public String getUrl() {
return url;
}
public String getRepositoryUrl() {
return repository_url;
}
public String getReason() {
return reason;
}
public boolean isSubscribed() {
return subscribed;
}
public boolean isIgnored() {
return ignored;
}
public GHRepository getRepository() {
return repo;
}
/**
* Removes this subscription.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(url);
}
GHSubscription wrapUp(GHRepository repo) {
this.repo = repo;
return wrapUp(repo.root);
}
GHSubscription wrapUp(GitHub root) {
this.root = root;
return this;
}
}

View File

@@ -0,0 +1,42 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Represents a tag in {@link GHRepository}
*
* @see GHRepository#listTags()
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHTag {
private GHRepository owner;
private GitHub root;
private String name;
private GHCommit commit;
/*package*/ GHTag wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if (commit!=null)
commit.wrapUp(owner);
return this;
}
public GHRepository getOwner() {
return owner;
}
public GitHub getRoot() {
return root;
}
public String getName() {
return name;
}
public GHCommit getCommit() {
return commit;
}
}

View File

@@ -1,8 +1,10 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* A team in GitHub organization.
@@ -10,11 +12,29 @@ import java.util.Set;
* @author Kohsuke Kawaguchi
*/
public class GHTeam {
private String name,permission;
private String name,permission,slug;
private int id;
private GHOrganization organization; // populated by GET /user/teams where Teams+Orgs are returned together
protected /*final*/ GHOrganization org;
/*package*/ GHTeam wrapUp(GHOrganization owner) {
this.org = owner;
return this;
}
/*package*/ GHTeam wrapUp(GitHub root) { // auto-wrapUp when organization is known from GET /user/teams
this.organization.wrapUp(root);
return wrapUp(organization);
}
/*package*/ static GHTeam[] wrapUp(GHTeam[] teams, GHOrganization owner) {
for (GHTeam t : teams) {
t.wrapUp(owner);
}
return teams;
}
public String getName() {
return name;
}
@@ -23,6 +43,10 @@ public class GHTeam {
return permission;
}
public String getSlug() {
return slug;
}
public int getId() {
return id;
}
@@ -30,37 +54,101 @@ public class GHTeam {
/**
* Retrieves the current members.
*/
public PagedIterable<GHUser> listMembers() throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(org.root.retrieve().asIterator(api("/members"), GHUser[].class, pageSize)) {
@Override
protected void wrapUp(GHUser[] page) {
GHUser.wrap(page, org.root);
}
};
}
};
}
public Set<GHUser> getMembers() throws IOException {
return org.root.retrieveWithAuth(api("/members"),JsonUsersWithDetails.class).toSet(org.root);
return Collections.unmodifiableSet(listMembers().asSet());
}
/**
* Checks if this team has the specified user as a member.
*/
public boolean hasMember(GHUser user) {
try {
org.root.retrieve().to("/teams/" + id + "/members/" + user.getLogin());
return true;
} catch (IOException ignore) {
return false;
}
}
public Map<String,GHRepository> getRepositories() throws IOException {
return org.root.retrieveWithAuth(api("/repositories"),JsonRepositories.class).wrap(org.root);
Map<String,GHRepository> m = new TreeMap<String, GHRepository>();
for (GHRepository r : listRepositories()) {
m.put(r.getName(), r);
}
return m;
}
public PagedIterable<GHRepository> listRepositories() {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(org.root.retrieve().asIterator(api("/repos"), GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository r : page)
r.wrap(org.root);
}
};
}
};
}
/**
* Adds a member to the team.
*
* The user will be invited to the organization if required.
*
* @since 1.59
*/
public void add(GHUser u) throws IOException {
org.root.retrieveWithAuth(api("/members?name="+u.getLogin()),null, "POST");
org.root.retrieve().method("PUT").to(api("/memberships/" + u.getLogin()), null);
}
/**
* Removes a member to the team.
*/
public void remove(GHUser u) throws IOException {
org.root.retrieveWithAuth(api("/members?name="+u.getLogin()),null, "DELETE");
org.root.retrieve().method("DELETE").to(api("/members/" + u.getLogin()), null);
}
public void add(GHRepository r) throws IOException {
org.root.retrieveWithAuth(api("/repositories?name="+r.getOwnerName()+'/'+r.getName()),null, "POST");
add(r,null);
}
public void add(GHRepository r, GHOrganization.Permission permission) throws IOException {
org.root.retrieve().method("PUT")
.with("permission",permission)
.to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
}
public void remove(GHRepository r) throws IOException {
org.root.retrieveWithAuth(api("/repositories?name="+r.getOwnerName()+'/'+r.getName()),null, "DELETE");
org.root.retrieve().method("DELETE").to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
}
/**
* Deletes this team.
*/
public void delete() throws IOException {
org.root.retrieve().method("DELETE").to(api(""));
}
private String api(String tail) {
return "/teams/"+id+tail;
}
public GHOrganization getOrganization() {
return org;
}
}

View File

@@ -0,0 +1,149 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
/**
* A conversation in the notification API.
*
* @see <a href="https://developer.github.com/v3/activity/notifications/">documentation</a>
* @see GHNotificationStream
* @author Kohsuke Kawaguchi
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHThread extends GHObject {
private GitHub root;
private GHRepository repository;
private Subject subject;
private String reason;
private boolean unread;
private String last_read_at;
private String url,subscription_url;
static class Subject {
String title;
String url;
String latest_comment_url;
String type;
}
private GHThread() {// no external construction allowed
}
/**
* Returns null if the entire thread has never been read.
*/
public Date getLastReadAt() {
return GitHub.parseDate(last_read_at);
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
public String getReason() {
return reason;
}
public GHRepository getRepository() {
return repository;
}
// TODO: how to expose the subject?
public boolean isRead() {
return !unread;
}
public String getTitle() {
return subject.title;
}
public String getType() {
return subject.type;
}
public String getLastCommentUrl() {
return subject.latest_comment_url;
}
/**
* If this thread is about an issue, return that issue.
*
* @return null if this thread is not about an issue.
*/
public GHIssue getBoundIssue() throws IOException {
if (!"Issue".equals(subject.type) && "PullRequest".equals(subject.type))
return null;
return repository.getIssue(
Integer.parseInt(subject.url.substring(subject.url.lastIndexOf('/') + 1)));
}
/**
* If this thread is about a pull request, return that pull request.
*
* @return null if this thread is not about a pull request.
*/
public GHPullRequest getBoundPullRequest() throws IOException {
if (!"PullRequest".equals(subject.type))
return null;
return repository.getPullRequest(
Integer.parseInt(subject.url.substring(subject.url.lastIndexOf('/') + 1)));
}
/**
* If this thread is about a commit, return that commit.
*
* @return null if this thread is not about a commit.
*/
public GHCommit getBoundCommit() throws IOException {
if (!"Commit".equals(subject.type))
return null;
return repository.getCommit(subject.url.substring(subject.url.lastIndexOf('/') + 1));
}
/*package*/ GHThread wrap(GitHub root) {
this.root = root;
if (this.repository!=null)
this.repository.wrap(root);
return this;
}
/**
* Marks this thread as read.
*/
public void markAsRead() throws IOException {
new Requester(root).method("PATCH").to(url);
}
/**
* Subscribes to this conversation to get notifications.
*/
public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException {
return new Requester(root)
.with("subscribed", subscribed)
.with("ignored", ignored)
.method("PUT").to(subscription_url, GHSubscription.class).wrapUp(root);
}
/**
* Returns the current subscription for this thread.
*
* @return null if no subscription exists.
*/
public GHSubscription getSubscription() throws IOException {
try {
return new Requester(root).to(subscription_url, GHSubscription.class).wrapUp(root);
} catch (FileNotFoundException e) {
return null;
}
}
}

View File

@@ -0,0 +1,75 @@
package org.kohsuke.github;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Provides information for Git Trees
* https://developer.github.com/v3/git/trees/
*
* @author Daniel Teixeira - https://github.com/ddtxra
* @see GHCommit#getTree()
* @see GHRepository#getTree(String)
* @see GHTreeEntry#asTree()
*/
public class GHTree {
/* package almost final */GHRepository repo;
private boolean truncated;
private String sha, url;
private GHTreeEntry[] tree;
/**
* The SHA for this trees
*/
public String getSha() {
return sha;
}
/**
* Return an array of entries of the trees
*/
public List<GHTreeEntry> getTree() {
return Collections.unmodifiableList(Arrays.asList(tree));
}
/**
* Finds a tree entry by its name.
*
* IOW, find a directory entry by a file name.
*/
public GHTreeEntry getEntry(String path) {
for (GHTreeEntry e : tree) {
if (e.getPath().equals(path))
return e;
}
return null;
}
/**
* Returns true if the number of items in the tree array exceeded the GitHub maximum limit.
* @return true true if the number of items in the tree array exceeded the GitHub maximum limit otherwise false.
*/
public boolean isTruncated() {
return truncated;
}
/**
* The API URL of this tag, such as
* "url": "https://api.github.com/repos/octocat/Hello-World/trees/fc6274d15fa3ae2ab983129fb037999f264ba9a7",
*/
public URL getUrl() {
return GitHub.parseURL(url);
}
/* package */GHTree wrap(GHRepository repo) {
this.repo = repo;
for (GHTreeEntry e : tree) {
e.tree = this;
}
return this;
}
}

View File

@@ -0,0 +1,108 @@
package org.kohsuke.github;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
* Provides information for Git Trees
* https://developer.github.com/v3/git/trees/
*
* @author Daniel Teixeira - https://github.com/ddtxra
* @see GHTree
*/
public class GHTreeEntry {
/* package almost final */GHTree tree;
private String path, mode, type, sha, url;
private long size;
/**
* Get the path such as
* "subdir/file.txt"
*
* @return the path
*/
public String getPath() {
return path;
}
/**
* Get mode such as
* 100644
*
* @return the mode
*/
public String getMode() {
return mode;
}
/**
* Gets the size of the file, such as
* 132
* @return The size of the path or 0 if it is a directory
*/
public long getSize() {
return size;
}
/**
* Gets the type such as:
* "blob", "tree", etc.
*
* @return The type
*/
public String getType() {
return type;
}
/**
* SHA1 of this object.
*/
public String getSha() {
return sha;
}
/**
* API URL to this Git data, such as
* https://api.github.com/repos/jenkinsci
* /jenkins/git/commits/b72322675eb0114363a9a86e9ad5a170d1d07ac0
*/
public URL getUrl() {
return GitHub.parseURL(url);
}
/**
* If this tree entry represents a file, then return its information.
* Otherwise null.
*/
public GHBlob asBlob() throws IOException {
if (type.equals("blob"))
return tree.repo.getBlob(sha);
else
return null;
}
/**
* If this tree entry represents a file, then return its content.
* Otherwise null.
*/
public InputStream readAsBlob() throws IOException {
if (type.equals("blob"))
return tree.repo.readBlob(sha);
else
return null;
}
/**
* If this tree entry represents a directory, then return it.
* Otherwise null.
*/
public GHTree asTree() throws IOException {
if (type.equals("tree"))
return tree.repo.getTree(sha);
else
return null;
}
}

View File

@@ -23,7 +23,10 @@
*/
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/**
@@ -32,109 +35,165 @@ import java.util.Set;
* @author Kohsuke Kawaguchi
*/
public class GHUser extends GHPerson {
private String name,company,location,created_at,blog,email;
private int followers_count;
/**
* Gets the human-readable name of the user, like "Kohsuke Kawaguchi"
*/
public String getName() {
return name;
}
/**
* Gets the company name of this user, like "Sun Microsystems, Inc."
*/
public String getCompany() {
return company;
}
/**
* Gets the location of this user, like "Santa Clara, California"
*/
public String getLocation() {
return location;
}
public String getCreatedAt() {
return created_at;
}
/**
* Gets the blog URL of this user.
*/
public String getBlog() {
return blog;
}
/**
* Gets the login ID of this user, like 'kohsuke'
*/
public String getLogin() {
return login;
}
/**
* Gets the e-mail address of the user.
*/
public String getEmail() {
return email;
}
public int getPublicGistCount() {
return public_gist_count;
}
public int getPublicRepoCount() {
return public_repo_count;
}
public int getFollowingCount() {
return following_count;
}
/**
* What appears to be a GitHub internal unique number that identifies this user.
*/
public int getId() {
return id;
}
public int getFollowersCount() {
return followers_count;
}
/**
* Follow this user.
*/
public void follow() throws IOException {
new Poster(root).withCredential().to("/user/follow/"+login);
new Requester(root).method("PUT").to("/user/following/" + login);
}
/**
* Unfollow this user.
*/
public void unfollow() throws IOException {
new Poster(root).withCredential().to("/user/unfollow/"+login);
new Requester(root).method("DELETE").to("/user/following/" + login);
}
/**
* Lists the users that this user is following
*/
public Set<GHUser> getFollows() throws IOException {
return root.retrieve("/user/show/"+login+"/following",JsonUsers.class).toSet(root);
@WithBridgeMethods(Set.class)
public GHPersonSet<GHUser> getFollows() throws IOException {
return new GHPersonSet<GHUser>(listFollows().asList());
}
/**
* Lists the users that this user is following
*/
public PagedIterable<GHUser> listFollows() {
return listUser("following");
}
/**
* Lists the users who are following this user.
*/
public Set<GHUser> getFollowers() throws IOException {
return root.retrieve("/user/show/"+login+"/followers",JsonUsers.class).toSet(root);
@WithBridgeMethods(Set.class)
public GHPersonSet<GHUser> getFollowers() throws IOException {
return new GHPersonSet<GHUser>(listFollowers().asList());
}
@Override
public String toString() {
return "User:"+login;
/**
* Lists the users who are following this user.
*/
public PagedIterable<GHUser> listFollowers() {
return listUser("followers");
}
private PagedIterable<GHUser> listUser(final String suffix) {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl(suffix), GHUser[].class, pageSize)) {
protected void wrapUp(GHUser[] page) {
GHUser.wrap(page,root);
}
};
}
};
}
/**
* Lists all the subscribed (aka watched) repositories.
*
* https://developer.github.com/v3/activity/watching/
*/
public PagedIterable<GHRepository> listSubscriptions() {
return listRepositories("subscriptions");
}
/**
* Lists all the repositories that this user has starred.
*/
public PagedIterable<GHRepository> listStarredRepositories() {
return listRepositories("starred");
}
private PagedIterable<GHRepository> listRepositories(final String suffix) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator(getApiTailUrl(suffix), GHRepository[].class, pageSize)) {
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
};
}
/**
* Returns true if this user belongs to the specified organization.
*/
public boolean isMemberOf(GHOrganization org) {
return org.hasMember(this);
}
/**
* Returns true if this user belongs to the specified team.
*/
public boolean isMemberOf(GHTeam team) {
return team.hasMember(this);
}
/**
* Returns true if this user belongs to the specified organization as a public member.
*/
public boolean isPublicMemberOf(GHOrganization org) {
return org.hasPublicMember(this);
}
/*package*/ static GHUser[] wrap(GHUser[] users, GitHub root) {
for (GHUser f : users)
f.root = root;
return users;
}
/**
* Gets the organization that this user belongs to publicly.
*/
@WithBridgeMethods(Set.class)
public GHPersonSet<GHOrganization> getOrganizations() throws IOException {
GHPersonSet<GHOrganization> orgs = new GHPersonSet<GHOrganization>();
Set<String> names = new HashSet<String>();
for (GHOrganization o : root.retrieve().to("/users/" + login + "/orgs", GHOrganization[].class)) {
if (names.add(o.getLogin())) // I've seen some duplicates in the data
orgs.add(root.getOrganization(o.getLogin()));
}
return orgs;
}
/**
* Lists events performed by a user (this includes private events if the caller is authenticated.
*/
public PagedIterable<GHEventInfo> listEvents() throws IOException {
return new PagedIterable<GHEventInfo>() {
public PagedIterator<GHEventInfo> _iterator(int pageSize) {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/users/%s/events", login), GHEventInfo[].class, pageSize)) {
@Override
protected void wrapUp(GHEventInfo[] page) {
for (GHEventInfo c : page)
c.wrapUp(root);
}
};
}
};
}
/**
* Lists Gists created by this user.
*/
public PagedIterable<GHGist> listGists() throws IOException {
return new PagedIterable<GHGist>() {
public PagedIterator<GHGist> _iterator(int pageSize) {
return new PagedIterator<GHGist>(root.retrieve().asIterator(String.format("/users/%s/gists", login), GHGist[].class, pageSize)) {
@Override
protected void wrapUp(GHGist[] page) {
for (GHGist c : page)
c.wrapUp(GHUser.this);
}
};
}
};
}
@Override
@@ -150,4 +209,14 @@ public class GHUser extends GHPerson {
}
return false;
}
String getApiTailUrl(String tail) {
if (tail.length()>0 && !tail.startsWith("/")) tail='/'+tail;
return "/users/" + login + tail;
}
/*package*/ GHUser wrapUp(GitHub root) {
super.wrapUp(root);
return this;
}
}

View File

@@ -0,0 +1,77 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* Search users.
*
* @author Kohsuke Kawaguchi
* @see GitHub#searchUsers()
*/
public class GHUserSearchBuilder extends GHSearchBuilder<GHUser> {
/*package*/ GHUserSearchBuilder(GitHub root) {
super(root,UserSearchResult.class);
}
/**
* Search terms.
*/
public GHUserSearchBuilder q(String term) {
super.q(term);
return this;
}
public GHUserSearchBuilder type(String v) {
return q("type:"+v);
}
public GHUserSearchBuilder in(String v) {
return q("in:"+v);
}
public GHUserSearchBuilder repos(String v) {
return q("repos:"+v);
}
public GHUserSearchBuilder location(String v) {
return q("location:"+v);
}
public GHUserSearchBuilder language(String v) {
return q("language:"+v);
}
public GHUserSearchBuilder created(String v) {
return q("created:"+v);
}
public GHUserSearchBuilder followers(String v) {
return q("followers:"+v);
}
public GHUserSearchBuilder order(GHDirection v) {
req.with("order",v);
return this;
}
public GHUserSearchBuilder sort(Sort sort) {
req.with("sort",sort);
return this;
}
public enum Sort { FOLLOWERS, REPOSITORIES, JOINED }
private static class UserSearchResult extends SearchResult<GHUser> {
private GHUser[] items;
@Override
/*package*/ GHUser[] getItems(GitHub root) {
return GHUser.wrap(items,root);
}
}
@Override
protected String getApiUrl() {
return "/search/users";
}
}

View File

@@ -0,0 +1,13 @@
package org.kohsuke.github;
public class GHVerifiedKey extends GHKey {
public GHVerifiedKey() {
this.verified = true;
}
@Override
public String getTitle() {
return (title == null ? "key-" + id : title);
}
}

View File

@@ -23,175 +23,348 @@
*/
package org.kohsuke.github;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.apache.commons.io.IOUtils;
import org.codehaus.jackson.map.DeserializationConfig.Feature;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.introspect.VisibilityChecker.Std;
import sun.misc.BASE64Encoder;
import java.io.File;
import java.io.FileInputStream;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64;
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.*;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
import static java.util.logging.Level.FINE;
import static org.kohsuke.github.Previews.DRAX;
/**
* Root of the GitHub API.
*
* <h2>Thread safety</h2>
* <p>
* This library aims to be safe for use by multiple threads concurrently, although
* the library itself makes no attempt to control/serialize potentially conflicting
* operations to GitHub, such as updating &amp; deleting a repository at the same time.
*
* @author Kohsuke Kawaguchi
*/
public class GitHub {
/*package*/ final String login;
/*package*/ final String encodedAuthorization;
/*package*/ final String password;
/*package*/ final String apiToken;
private final Map<String,GHUser> users = new HashMap<String, GHUser>();
private final Map<String,GHOrganization> orgs = new HashMap<String, GHOrganization>();
private String oauthAccessToken;
private GitHub(String login, String apiToken, String password) {
this.login = login;
this.apiToken = apiToken;
this.password = password;
BASE64Encoder enc = new sun.misc.BASE64Encoder();
if (apiToken!=null || password!=null) {
String userpassword = password==null ? (login + "/token" + ":" + apiToken) : (login + ':'+password);
encodedAuthorization = enc.encode(userpassword.getBytes());
} else
encodedAuthorization = null;
}
private GitHub (String oauthAccessToken) throws IOException {
this.password = null;
this.encodedAuthorization = null;
this.oauthAccessToken = oauthAccessToken;
this.apiToken = oauthAccessToken;
this.login = getMyself().getLogin();
}
/**
* Obtains the credential from "~/.github"
* Value of the authorization header to be sent with the request.
*/
/*package*/ final String encodedAuthorization;
private final Map<String,GHUser> users = new Hashtable<String, GHUser>();
private final Map<String,GHOrganization> orgs = new Hashtable<String, GHOrganization>();
private final String apiUrl;
/*package*/ final RateLimitHandler rateLimitHandler;
/*package*/ final AbuseLimitHandler abuseLimitHandler;
private HttpConnector connector = HttpConnector.DEFAULT;
private final Object headerRateLimitLock = new Object();
private GHRateLimit headerRateLimit = null;
private volatile GHRateLimit rateLimit = null;
/**
* Creates a client API root object.
*
* <p>
* Several different combinations of the login/oauthAccessToken/password parameters are allowed
* to represent different ways of authentication.
*
* <dl>
* <dt>Loging anonymously
* <dd>Leave all three parameters null and you will be making HTTP requests without any authentication.
*
* <dt>Log in with password
* <dd>Specify the login and password, then leave oauthAccessToken null.
* This will use the HTTP BASIC auth with the GitHub API.
*
* <dt>Log in with OAuth token
* <dd>Specify oauthAccessToken, and optionally specify the login. Leave password null.
* This will send OAuth token to the GitHub API. If the login parameter is null,
* The constructor makes an API call to figure out the user name that owns the token.
* </dl>
*
* @param apiUrl
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
* Password is also considered deprecated as it is no longer required for api usage.
* @param login
* The use ID on GitHub that you are logging in as. Can be omitted if the OAuth token is
* provided or if logging in anonymously. Specifying this would save one API call.
* @param oauthAccessToken
* Secret OAuth token.
* @param password
* User's password. Always used in conjunction with the {@code login} parameter
* @param connector
* HttpConnector to use. Pass null to use default connector.
*/
/* package */ GitHub(String apiUrl, String login, String oauthAccessToken, String password, HttpConnector connector, RateLimitHandler rateLimitHandler, AbuseLimitHandler abuseLimitHandler) throws IOException {
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
this.apiUrl = apiUrl;
if (null != connector) this.connector = connector;
if (oauthAccessToken!=null) {
encodedAuthorization = "token "+oauthAccessToken;
} else {
if (password!=null) {
String authorization = (login + ':' + password);
String charsetName = Charsets.UTF_8.name();
encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes(charsetName)), charsetName);
} else {// anonymous access
encodedAuthorization = null;
}
}
this.rateLimitHandler = rateLimitHandler;
this.abuseLimitHandler = abuseLimitHandler;
if (login==null && encodedAuthorization!=null)
login = getMyself().getLogin();
this.login = login;
}
/**
* Obtains the credential from "~/.github" or from the System Environment Properties.
*/
public static GitHub connect() throws IOException {
Properties props = new Properties();
File homeDir = new File(System.getProperty("user.home"));
FileInputStream in = new FileInputStream(new File(homeDir, ".github"));
try {
props.load(in);
} finally {
IOUtils.closeQuietly(in);
}
return new GitHub(props.getProperty("login"),props.getProperty("token"),props.getProperty("password"));
return GitHubBuilder.fromCredentials().build();
}
public static GitHub connect(String login, String apiToken) throws IOException {
return new GitHub(login,apiToken,null);
/**
* Version that connects to GitHub Enterprise.
*
* @param apiUrl
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
*/
public static GitHub connectToEnterprise(String apiUrl, String oauthAccessToken) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).withOAuthToken(oauthAccessToken).build();
}
public static GitHub connect(String login, String apiToken, String password) throws IOException {
return new GitHub(login,apiToken,password);
public static GitHub connectToEnterprise(String apiUrl, String login, String password) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).withPassword(login, password).build();
}
public static GitHub connectUsingOAuth (String accessToken) throws IOException {
return new GitHub(accessToken);
public static GitHub connect(String login, String oauthAccessToken) throws IOException {
return new GitHubBuilder().withOAuthToken(oauthAccessToken, login).build();
}
/**
* @deprecated
* Either OAuth token or password is sufficient, so there's no point in passing both.
* Use {@link #connectUsingPassword(String, String)} or {@link #connectUsingOAuth(String)}.
*/
public static GitHub connect(String login, String oauthAccessToken, String password) throws IOException {
return new GitHubBuilder().withOAuthToken(oauthAccessToken, login).withPassword(login, password).build();
}
public static GitHub connectUsingPassword(String login, String password) throws IOException {
return new GitHubBuilder().withPassword(login, password).build();
}
public static GitHub connectUsingOAuth(String oauthAccessToken) throws IOException {
return new GitHubBuilder().withOAuthToken(oauthAccessToken).build();
}
public static GitHub connectUsingOAuth(String githubServer, String oauthAccessToken) throws IOException {
return new GitHubBuilder().withEndpoint(githubServer).withOAuthToken(oauthAccessToken).build();
}
/**
* Connects to GitHub anonymously.
*
* All operations that requires authentication will fail.
*/
public static GitHub connectAnonymously() {
return new GitHub(null,null,null);
public static GitHub connectAnonymously() throws IOException {
return new GitHubBuilder().build();
}
/**
* Connects to GitHub Enterprise anonymously.
*
* All operations that requires authentication will fail.
*/
public static GitHub connectToEnterpriseAnonymously(String apiUrl) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).build();
}
/**
* An offline-only {@link GitHub} useful for parsing event notification from an unknown source.
*
* All operations that require a connection will fail.
*
* @return An offline-only {@link GitHub}.
*/
public static GitHub offline() {
try {
return new GitHubBuilder()
.withEndpoint("https://api.github.invalid")
.withConnector(HttpConnector.OFFLINE)
.build();
} catch (IOException e) {
throw new IllegalStateException("The offline implementation constructor should not connect", e);
}
}
/**
* Is this an anonymous connection
* @return {@code true} if operations that require authentication will fail.
*/
public boolean isAnonymous() {
return login==null && encodedAuthorization==null;
}
/**
* Is this an always offline "connection".
* @return {@code true} if this is an always offline "connection".
*/
public boolean isOffline() {
return connector == HttpConnector.OFFLINE;
}
public HttpConnector getConnector() {
return connector;
}
public String getApiUrl() {
return apiUrl;
}
/**
* Sets the custom connector used to make requests to GitHub.
*/
public void setConnector(HttpConnector connector) {
this.connector = connector;
}
/*package*/ void requireCredential() {
if ((login==null || encodedAuthorization==null) && oauthAccessToken == null)
if (isAnonymous())
throw new IllegalStateException("This operation requires a credential but none is given to the GitHub constructor");
}
/*package*/ URL getApiURL(ApiVersion v, String tailApiUrl) throws IOException {
if (oauthAccessToken != null) {
// append the access token
tailApiUrl = tailApiUrl + "?access_token=" + oauthAccessToken;
}
return new URL(v.url+tailApiUrl);
/*package*/ URL getApiURL(String tailApiUrl) throws IOException {
if (tailApiUrl.startsWith("/")) {
if ("github.com".equals(apiUrl)) {// backward compatibility
return new URL(GITHUB_URL + tailApiUrl);
} else {
return new URL(apiUrl + tailApiUrl);
}
} else {
return new URL(tailApiUrl);
}
}
/*package*/ <T> T retrieve(String tailApiUrl, Class<T> type) throws IOException {
return _retrieve(tailApiUrl, type, "GET", false);
/*package*/ Requester retrieve() {
return new Requester(this).method("GET");
}
/*package*/ <T> T retrieveWithAuth(String tailApiUrl, Class<T> type) throws IOException {
return retrieveWithAuth(tailApiUrl,type,"GET");
/**
* Gets the current rate limit.
*/
public GHRateLimit getRateLimit() throws IOException {
try {
return rateLimit = retrieve().to("/rate_limit", JsonRateLimit.class).rate;
} catch (FileNotFoundException e) {
// GitHub Enterprise doesn't have the rate limit, so in that case
// return some big number that's not too big.
// see issue #78
GHRateLimit r = new GHRateLimit();
r.limit = r.remaining = 1000000;
long hour = 60L * 60L; // this is madness, storing the date as seconds in a Date object
r.reset = new Date((System.currentTimeMillis() + hour) / 1000L );
return rateLimit = r;
}
}
/*package*/ <T> T retrieveWithAuth(String tailApiUrl, Class<T> type, String method) throws IOException {
return _retrieve(tailApiUrl, type, method, true);
}
private <T> T _retrieve(String tailApiUrl, Class<T> type, String method, boolean withAuth) throws IOException {
while (true) {// loop while API rate limit is hit
HttpURLConnection uc = (HttpURLConnection) getApiURL(ApiVersion.V2,tailApiUrl).openConnection();
if (withAuth && this.oauthAccessToken == null)
uc.setRequestProperty("Authorization", "Basic " + encodedAuthorization);
uc.setRequestMethod(method);
try {
InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8");
if (type==null) {
String data = IOUtils.toString(r);
return null;
}
return MAPPER.readValue(r,type);
} catch (IOException e) {
handleApiError(e,uc);
/*package*/ void updateRateLimit(@Nonnull GHRateLimit observed) {
synchronized (headerRateLimitLock) {
if (headerRateLimit == null
|| headerRateLimit.getResetDate().getTime() < observed.getResetDate().getTime()
|| headerRateLimit.remaining > observed.remaining) {
headerRateLimit = observed;
LOGGER.log(Level.INFO, "Rate limit now: {0}", headerRateLimit);
}
}
}
/**
* If the error is because of the API limit, wait 10 sec and return normally.
* Otherwise throw an exception reporting an error.
* Returns the most recently observed rate limit data or {@code null} if either there is no rate limit
* (for example GitHub Enterprise) or if no requests have been made.
*
* @return the most recently observed rate limit data or {@code null}.
*/
/*package*/ void handleApiError(IOException e, HttpURLConnection uc) throws IOException {
if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) {
// API limit reached. wait 10 secs and return normally
try {
Thread.sleep(10000);
return;
} catch (InterruptedException _) {
throw (InterruptedIOException)new InterruptedIOException().initCause(e);
@CheckForNull
public GHRateLimit lastRateLimit() {
synchronized (headerRateLimitLock) {
return headerRateLimit;
}
}
/**
* Gets the current rate limit while trying not to actually make any remote requests unless absolutely necessary.
*
* @return the current rate limit data.
* @throws IOException if we couldn't get the current rate limit data.
*/
@Nonnull
public GHRateLimit rateLimit() throws IOException {
synchronized (headerRateLimitLock) {
if (headerRateLimit != null) {
return headerRateLimit;
}
}
throw (IOException)new IOException(IOUtils.toString(uc.getErrorStream(),"UTF-8")).initCause(e);
GHRateLimit rateLimit = this.rateLimit;
if (rateLimit == null || rateLimit.getResetDate().getTime() < System.currentTimeMillis()) {
rateLimit = getRateLimit();
}
return rateLimit;
}
/**
* Gets the {@link GHUser} that represents yourself.
*/
@WithBridgeMethods(GHUser.class)
public GHMyself getMyself() throws IOException {
requireCredential();
GHMyself u = retrieve().to("/user", GHMyself.class);
u.root = this;
users.put(u.getLogin(), u);
return u;
}
/**
@@ -199,31 +372,31 @@ public class GitHub {
*/
public GHUser getUser(String login) throws IOException {
GHUser u = users.get(login);
if (u==null) {
if (oauthAccessToken != null) {
u = retrieve("/user/show",JsonUser.class).user;
u.root = this;
users.put(u.getLogin(),u);
}
else {
u = retrieve("/user/show/"+login,JsonUser.class).user;
if (u == null) {
u = retrieve().to("/users/" + login, GHUser.class);
u.root = this;
users.put(login,u);
}
users.put(u.getLogin(), u);
}
return u;
}
/**
* clears all cached data in order for external changes (modifications and del
*/
public void refreshCache() {
users.clear();
orgs.clear();
}
/**
* Interns the given {@link GHUser}.
*/
protected GHUser getUser(GHUser orig) throws IOException {
protected GHUser getUser(GHUser orig) {
GHUser u = users.get(orig.getLogin());
if (u==null) {
orig.root = this;
users.put(login,orig);
users.put(orig.getLogin(),orig);
return orig;
}
return u;
@@ -232,23 +405,148 @@ public class GitHub {
public GHOrganization getOrganization(String name) throws IOException {
GHOrganization o = orgs.get(name);
if (o==null) {
o = retrieve("/organizations/"+name,JsonOrganization.class).organization;
o.root = this;
o = retrieve().to("/orgs/" + name, GHOrganization.class).wrapUp(this);
orgs.put(name,o);
}
return o;
}
public Map<String, GHOrganization> getMyOrganizations() throws IOException {
return retrieveWithAuth("/organizations",JsonOrganizations.class).wrap(this);
/**
* Gets the repository object from 'user/reponame' string that GitHub calls as "repository name"
*
* @see GHRepository#getName()
*/
public GHRepository getRepository(String name) throws IOException {
String[] tokens = name.split("/");
return retrieve().to("/repos/" + tokens[0] + '/' + tokens[1], GHRepository.class).wrap(this);
}
/**
* Gets the {@link GHUser} that represents yourself.
* Returns a list of popular open source licenses
*
* WARNING: This uses a PREVIEW API.
*
* @see <a href="https://developer.github.com/v3/licenses/">GitHub API - Licenses</a>
*
* @return a list of popular open source licenses
*/
public GHUser getMyself() throws IOException {
requireCredential();
return getUser(login);
@Preview @Deprecated
public PagedIterable<GHLicense> listLicenses() throws IOException {
return new PagedIterable<GHLicense>() {
public PagedIterator<GHLicense> _iterator(int pageSize) {
return new PagedIterator<GHLicense>(retrieve().withPreview(DRAX).asIterator("/licenses", GHLicense[].class, pageSize)) {
@Override
protected void wrapUp(GHLicense[] page) {
for (GHLicense c : page)
c.wrap(GitHub.this);
}
};
}
};
}
/**
* Returns a list of all users.
*/
public PagedIterable<GHUser> listUsers() throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(retrieve().asIterator("/users", GHUser[].class, pageSize)) {
@Override
protected void wrapUp(GHUser[] page) {
for (GHUser u : page)
u.wrapUp(GitHub.this);
}
};
}
};
}
/**
* Returns the full details for a license
*
* WARNING: This uses a PREVIEW API.
*
* @param key The license key provided from the API
* @return The license details
* @see GHLicense#getKey()
*/
@Preview @Deprecated
public GHLicense getLicense(String key) throws IOException {
return retrieve().withPreview(DRAX).to("/licenses/" + key, GHLicense.class);
}
/**
/**
* This method returns a shallowly populated organizations.
*
* To retrieve full organization details, you need to call {@link #getOrganization(String)}
* TODO: make this automatic.
*/
public Map<String, GHOrganization> getMyOrganizations() throws IOException {
GHOrganization[] orgs = retrieve().to("/user/orgs", GHOrganization[].class);
Map<String, GHOrganization> r = new HashMap<String, GHOrganization>();
for (GHOrganization o : orgs) {
// don't put 'o' into orgs because they are shallow
r.put(o.getLogin(),o.wrapUp(this));
}
return r;
}
/**
* Gets complete map of organizations/teams that current user belongs to.
*
* Leverages the new GitHub API /user/teams made available recently to
* get in a single call the complete set of organizations, teams and permissions
* in a single call.
*/
public Map<String, Set<GHTeam>> getMyTeams() throws IOException {
Map<String, Set<GHTeam>> allMyTeams = new HashMap<String, Set<GHTeam>>();
for (GHTeam team : retrieve().to("/user/teams", GHTeam[].class)) {
team.wrapUp(this);
String orgLogin = team.getOrganization().getLogin();
Set<GHTeam> teamsPerOrg = allMyTeams.get(orgLogin);
if (teamsPerOrg == null) {
teamsPerOrg = new HashSet<GHTeam>();
}
teamsPerOrg.add(team);
allMyTeams.put(orgLogin, teamsPerOrg);
}
return allMyTeams;
}
/**
* Public events visible to you. Equivalent of what's displayed on https://github.com/
*/
public List<GHEventInfo> getEvents() throws IOException {
GHEventInfo[] events = retrieve().to("/events", GHEventInfo[].class);
for (GHEventInfo e : events)
e.wrapUp(this);
return Arrays.asList(events);
}
/**
* Gets a sigle gist by ID.
*/
public GHGist getGist(String id) throws IOException {
return retrieve().to("/gists/"+id,GHGist.class).wrapUp(this);
}
public GHGistBuilder createGist() {
return new GHGistBuilder(this);
}
/**
* Parses the GitHub event object.
*
* This is primarily intended for receiving a POST HTTP call from a hook.
* Unfortunately, hook script payloads aren't self-descriptive, so you need
* to know the type of the payload you are expecting.
*/
public <T extends GHEventPayload> T parseEventPayload(Reader r, Class<T> type) throws IOException {
T t = MAPPER.readValue(r, type);
t.wrapUp(this);
return t;
}
/**
@@ -256,11 +554,78 @@ public class GitHub {
*
* @return
* Newly created repository.
* @deprecated
* Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect.
*/
public GHRepository createRepository(String name, String description, String homepage, boolean isPublic) throws IOException {
return new Poster(this).withCredential()
.with("name", name).with("description", description).with("homepage", homepage)
.with("public", isPublic ? 1 : 0).to("/repos/create", JsonRepository.class).wrap(this);
return createRepository(name).description(description).homepage(homepage).private_(!isPublic).create();
}
/**
* Starts a builder that creates a new repository.
*
* <p>
* You use the returned builder to set various properties, then call {@link GHCreateRepositoryBuilder#create()}
* to finally createa repository.
*
* <p>
* To create a repository in an organization, see
* {@link GHOrganization#createRepository(String, String, String, GHTeam, boolean)}
*/
public GHCreateRepositoryBuilder createRepository(String name) {
return new GHCreateRepositoryBuilder(this,"/user/repos",name);
}
/**
* Creates a new authorization.
*
* The token created can be then used for {@link GitHub#connectUsingOAuth(String)} in the future.
*
* @see <a href="http://developer.github.com/v3/oauth/#create-a-new-authorization">Documentation</a>
*/
public GHAuthorization createToken(Collection<String> scope, String note, String noteUrl) throws IOException{
Requester requester = new Requester(this)
.with("scopes", scope)
.with("note", note)
.with("note_url", noteUrl);
return requester.method("POST").to("/authorizations", GHAuthorization.class).wrap(this);
}
/**
* @see <a href="https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app">docs</a>
*/
public GHAuthorization createOrGetAuth(String clientId, String clientSecret, List<String> scopes, String note,
String note_url)
throws IOException {
Requester requester = new Requester(this)
.with("client_secret", clientSecret)
.with("scopes", scopes)
.with("note", note)
.with("note_url", note_url);
return requester.method("PUT").to("/authorizations/clients/" + clientId, GHAuthorization.class);
}
/**
* @see <a href="https://developer.github.com/v3/oauth_authorizations/#delete-an-authorization">Delete an authorization</a>
*/
public void deleteAuth(long id) throws IOException {
retrieve().method("DELETE").to("/authorizations/" + id);
}
/**
* @see <a href="https://developer.github.com/v3/oauth_authorizations/#check-an-authorization">Check an authorization</a>
*/
public GHAuthorization checkAuth(@Nonnull String clientId, @Nonnull String accessToken) throws IOException {
return retrieve().to("/applications/" + clientId + "/tokens/" + accessToken, GHAuthorization.class);
}
/**
* @see <a href="https://developer.github.com/v3/oauth_authorizations/#reset-an-authorization">Reset an authorization</a>
*/
public GHAuthorization resetAuth(@Nonnull String clientId, @Nonnull String accessToken) throws IOException {
return retrieve().method("POST").to("/applications/" + clientId + "/tokens/" + accessToken, GHAuthorization.class);
}
/**
@@ -268,23 +633,164 @@ public class GitHub {
*/
public boolean isCredentialValid() throws IOException {
try {
retrieveWithAuth("/user/show",JsonUser.class);
retrieve().to("/user", GHUser.class);
return true;
} catch (IOException e) {
if (LOGGER.isLoggable(FINE))
LOGGER.log(FINE, "Exception validating credentials on " + this.apiUrl + " with login '" + this.login + "' " + e, e);
return false;
}
}
private static class GHApiInfo {
private String rate_limit_url;
void check(String apiUrl) throws IOException {
if (rate_limit_url==null)
throw new IOException(apiUrl+" doesn't look like GitHub API URL");
// make sure that the URL is legitimate
new URL(rate_limit_url);
}
}
/**
* Tests the connection.
*
* <p>
* Verify that the API URL and credentials are valid to access this GitHub.
*
* <p>
* This method returns normally if the endpoint is reachable and verified to be GitHub API URL.
* Otherwise this method throws {@link IOException} to indicate the problem.
*/
public void checkApiUrlValidity() throws IOException {
try {
retrieve().to("/", GHApiInfo.class).check(apiUrl);
} catch (IOException e) {
if (isPrivateModeEnabled()) {
throw (IOException)new IOException("GitHub Enterprise server (" + apiUrl + ") with private mode enabled").initCause(e);
}
throw e;
}
}
/**
* Ensures if a GitHub Enterprise server is configured in private mode.
*
* @return {@code true} if private mode is enabled. If it tries to use this method with GitHub, returns {@code
* false}.
*/
private boolean isPrivateModeEnabled() {
try {
HttpURLConnection uc = getConnector().connect(getApiURL("/"));
/*
$ curl -i https://github.mycompany.com/api/v3/
HTTP/1.1 401 Unauthorized
Server: GitHub.com
Date: Sat, 05 Mar 2016 19:45:01 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 130
Status: 401 Unauthorized
X-GitHub-Media-Type: github.v3
X-XSS-Protection: 1; mode=block
X-Frame-Options: deny
Content-Security-Policy: default-src 'none'
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
Access-Control-Allow-Origin: *
X-GitHub-Request-Id: dbc70361-b11d-4131-9a7f-674b8edd0411
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Content-Type-Options: nosniff
*/
return uc.getResponseCode() == HTTP_UNAUTHORIZED
&& uc.getHeaderField("X-GitHub-Media-Type") != null;
} catch (IOException e) {
return false;
}
}
WebClient createWebClient() throws IOException {
WebClient wc = new WebClient();
wc.setJavaScriptEnabled(false);
wc.setCssEnabled(false);
HtmlPage pg = (HtmlPage)wc.getPage("https://github.com/login");
HtmlForm f = pg.getForms().get(0);
f.getInputByName("login").setValueAttribute(login);
f.getInputByName("password").setValueAttribute(password);
f.submit();
return wc;
/**
* Search issues.
*/
public GHIssueSearchBuilder searchIssues() {
return new GHIssueSearchBuilder(this);
}
/**
* Search users.
*/
public GHUserSearchBuilder searchUsers() {
return new GHUserSearchBuilder(this);
}
/**
* Search repositories.
*/
public GHRepositorySearchBuilder searchRepositories() {
return new GHRepositorySearchBuilder(this);
}
/**
* Search content.
*/
public GHContentSearchBuilder searchContent() {
return new GHContentSearchBuilder(this);
}
/**
* List all the notifications.
*/
public GHNotificationStream listNotifications() {
return new GHNotificationStream(this,"/notifications");
}
/**
* This provides a dump of every public repository, in the order that they were created.
* @see <a href="https://developer.github.com/v3/repos/#list-all-public-repositories">documentation</a>
*/
public PagedIterable<GHRepository> listAllPublicRepositories() {
return listAllPublicRepositories(null);
}
/**
* This provides a dump of every public repository, in the order that they were created.
*
* @param since
* The integer ID of the last Repository that youve seen. See {@link GHRepository#getId()}
* @see <a href="https://developer.github.com/v3/repos/#list-all-public-repositories">documentation</a>
*/
public PagedIterable<GHRepository> listAllPublicRepositories(final String since) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(retrieve().with("since",since).asIterator("/repositories", GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(GitHub.this);
}
};
}
};
}
/**
* Render a Markdown document in raw mode.
*
* <p>
* It takes a Markdown document as plaintext and renders it as plain Markdown
* without a repository context (just like a README.md file is rendered this
* is the simplest way to preview a readme online).
*
* @see GHRepository#renderMarkdown(String, MarkdownMode)
*/
public Reader renderMarkdown(String text) throws IOException {
return new InputStreamReader(
new Requester(this)
.with(new ByteArrayInputStream(text.getBytes("UTF-8")))
.contentType("text/plain;charset=UTF-8")
.asStream("/markdown/raw"),
"UTF-8");
}
/*package*/ static URL parseURL(String s) {
@@ -296,9 +802,12 @@ public class GitHub {
}
/*package*/ static Date parseDate(String timestamp) {
if (timestamp==null) return null;
for (String f : TIME_FORMATS) {
try {
return new SimpleDateFormat(f).parse(timestamp);
SimpleDateFormat df = new SimpleDateFormat(f);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df.parse(timestamp);
} catch (ParseException e) {
// try next
}
@@ -306,12 +815,20 @@ public class GitHub {
throw new IllegalStateException("Unable to parse the timestamp: "+timestamp);
}
/*package*/ static String printDate(Date dt) {
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(dt);
}
/*package*/ static final ObjectMapper MAPPER = new ObjectMapper();
private static final String[] TIME_FORMATS = {"yyyy/MM/dd HH:mm:ss ZZZZ","yyyy-MM-dd'T'HH:mm:ss'Z'"};
static {
MAPPER.setVisibilityChecker(new Std(NONE, NONE, NONE, NONE, ANY));
MAPPER.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
/* package */ static final String GITHUB_URL = "https://api.github.com";
private static final Logger LOGGER = Logger.getLogger(GitHub.class.getName());
}

View File

@@ -0,0 +1,203 @@
package org.kohsuke.github;
import org.apache.commons.io.IOUtils;
import org.kohsuke.github.extras.ImpatientHttpConnector;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.Properties;
/**
* Configures connection details and produces {@link GitHub}.
*
* @since 1.59
*/
public class GitHubBuilder {
// default scoped so unit tests can read them.
/* private */ String endpoint = GitHub.GITHUB_URL;
/* private */ String user;
/* private */ String password;
/* private */ String oauthToken;
private HttpConnector connector;
private RateLimitHandler rateLimitHandler = RateLimitHandler.WAIT;
private AbuseLimitHandler abuseLimitHandler = AbuseLimitHandler.WAIT;
public GitHubBuilder() {
}
/**
* First check if the credentials are configured using the ~/.github properties file.
*
* If no user is specified it means there is no configuration present so check the environment instead.
*
* If there is still no user it means there are no credentials defined and throw an IOException.
*
* @return the configured Builder from credentials defined on the system or in the environment.
*
* @throws IOException If there are no credentials defined in the ~/.github properties file or the process environment.
*/
public static GitHubBuilder fromCredentials() throws IOException {
Exception cause = null;
GitHubBuilder builder;
try {
builder = fromPropertyFile();
if (builder.oauthToken != null || builder.user != null)
return builder;
} catch (FileNotFoundException e) {
// fall through
cause = e;
}
builder = fromEnvironment();
if (builder.oauthToken != null || builder.user != null)
return builder;
else
throw (IOException)new IOException("Failed to resolve credentials from ~/.github or the environment.").initCause(cause);
}
/**
* @deprecated
* Use {@link #fromEnvironment()} to pick up standard set of environment variables, so that
* different clients of this library will all recognize one consistent set of coordinates.
*/
public static GitHubBuilder fromEnvironment(String loginVariableName, String passwordVariableName, String oauthVariableName) throws IOException {
return fromEnvironment(loginVariableName, passwordVariableName, oauthVariableName, "");
}
private static void loadIfSet(String envName, Properties p, String propName) {
String v = System.getenv(envName);
if (v != null)
p.put(propName, v);
}
/**
* @deprecated
* Use {@link #fromEnvironment()} to pick up standard set of environment variables, so that
* different clients of this library will all recognize one consistent set of coordinates.
*/
public static GitHubBuilder fromEnvironment(String loginVariableName, String passwordVariableName, String oauthVariableName, String endpointVariableName) throws IOException {
Properties env = new Properties();
loadIfSet(loginVariableName,env,"login");
loadIfSet(passwordVariableName,env,"password");
loadIfSet(oauthVariableName,env,"oauth");
loadIfSet(endpointVariableName,env,"endpoint");
return fromProperties(env);
}
/**
* Creates {@link GitHubBuilder} by picking up coordinates from environment variables.
*
* <p>
* The following environment variables are recognized:
*
* <ul>
* <li>GITHUB_LOGIN: username like 'kohsuke'
* <li>GITHUB_PASSWORD: raw password
* <li>GITHUB_OAUTH: OAuth token to login
* <li>GITHUB_ENDPOINT: URL of the API endpoint
* </ul>
*
* <p>
* See class javadoc for the relationship between these coordinates.
*
* <p>
* For backward compatibility, the following environment variables are recognized but discouraged:
* login, password, oauth
*/
public static GitHubBuilder fromEnvironment() throws IOException {
Properties props = new Properties();
for (Entry<String, String> e : System.getenv().entrySet()) {
String name = e.getKey().toLowerCase(Locale.ENGLISH);
if (name.startsWith("github_")) name=name.substring(7);
props.put(name,e.getValue());
}
return fromProperties(props);
}
public static GitHubBuilder fromPropertyFile() throws IOException {
File homeDir = new File(System.getProperty("user.home"));
File propertyFile = new File(homeDir, ".github");
return fromPropertyFile(propertyFile.getPath());
}
public static GitHubBuilder fromPropertyFile(String propertyFileName) throws IOException {
Properties props = new Properties();
FileInputStream in = null;
try {
in = new FileInputStream(propertyFileName);
props.load(in);
} finally {
IOUtils.closeQuietly(in);
}
return fromProperties(props);
}
public static GitHubBuilder fromProperties(Properties props) {
GitHubBuilder self = new GitHubBuilder();
self.withOAuthToken(props.getProperty("oauth"), props.getProperty("login"));
self.withPassword(props.getProperty("login"), props.getProperty("password"));
self.withEndpoint(props.getProperty("endpoint", GitHub.GITHUB_URL));
return self;
}
public GitHubBuilder withEndpoint(String endpoint) {
this.endpoint = endpoint;
return this;
}
public GitHubBuilder withPassword(String user, String password) {
this.user = user;
this.password = password;
return this;
}
public GitHubBuilder withOAuthToken(String oauthToken) {
return withOAuthToken(oauthToken, null);
}
public GitHubBuilder withOAuthToken(String oauthToken, String user) {
this.oauthToken = oauthToken;
this.user = user;
return this;
}
public GitHubBuilder withConnector(HttpConnector connector) {
this.connector = connector;
return this;
}
public GitHubBuilder withRateLimitHandler(RateLimitHandler handler) {
this.rateLimitHandler = handler;
return this;
}
public GitHubBuilder withAbuseLimitHandler(AbuseLimitHandler handler) {
this.abuseLimitHandler = handler;
return this;
}
/**
* Configures {@linkplain #withConnector(HttpConnector) connector}
* that uses HTTP library in JRE but use a specific proxy, instead of
* the system default one.
*/
public GitHubBuilder withProxy(final Proxy p) {
return withConnector(new ImpatientHttpConnector(new HttpConnector() {
public HttpURLConnection connect(URL url) throws IOException {
return (HttpURLConnection) url.openConnection(p);
}
}));
}
public GitHub build() throws IOException {
return new GitHub(endpoint, user, oauthToken, password, connector, rateLimitHandler, abuseLimitHandler);
}
}

View File

@@ -0,0 +1,41 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
/**
* Represents a user in Git who authors/commits a commit.
*
* In contrast, {@link GHUser} is an user of GitHub. Because Git allows a person to
* use multiple e-mail addresses and names when creating a commit, there's generally
* no meaningful mapping between {@link GHUser} and {@link GitUser}.
*
* @author Kohsuke Kawaguchi
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GitUser {
private String name, email, date;
/**
* Human readable name of the user, such as "Kohsuke Kawaguchi"
*/
public String getName() {
return name;
}
/**
* E-mail address, such as "foo@example.com"
*/
public String getEmail() {
return email;
}
/**
* This field doesn't appear to be consistently available in all the situations where this class
* is used.
*/
public Date getDate() {
return GitHub.parseDate(date);
}
}

View File

@@ -0,0 +1,41 @@
package org.kohsuke.github;
import org.kohsuke.github.extras.ImpatientHttpConnector;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Pluggability for customizing HTTP request behaviors or using altogether different library.
*
* <p>
* For example, you can implement this to st custom timeouts.
*
* @author Kohsuke Kawaguchi
*/
public interface HttpConnector {
/**
* Opens a connection to the given URL.
*/
HttpURLConnection connect(URL url) throws IOException;
/**
* Default implementation that uses {@link URL#openConnection()}.
*/
HttpConnector DEFAULT = new ImpatientHttpConnector(new HttpConnector() {
public HttpURLConnection connect(URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
}
});
/**
* Stub implementation that is always off-line.
*/
HttpConnector OFFLINE = new HttpConnector() {
public HttpURLConnection connect(URL url) throws IOException {
throw new IOException("Offline");
}
};
}

View File

@@ -0,0 +1,118 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.annotation.CheckForNull;
/**
* {@link IOException} for http exceptions because {@link HttpURLConnection} throws un-discerned
* {@link IOException} and it can help to know the http response code to decide how to handle an
* http exceptions.
*
* @author <a href="mailto:cleclerc@cloudbees.com">Cyrille Le Clerc</a>
*/
public class HttpException extends IOException {
static final long serialVersionUID = 1L;
private final int responseCode;
private final String responseMessage;
private final String url;
/**
* @param message The detail message (which is saved for later retrieval
* by the {@link #getMessage()} method)
* @param responseCode Http response code. {@code -1} if no code can be discerned.
* @param responseMessage Http response message
* @param url The url that was invoked
* @see HttpURLConnection#getResponseCode()
* @see HttpURLConnection#getResponseMessage()
*/
public HttpException(String message, int responseCode, String responseMessage, String url) {
super(message);
this.responseCode = responseCode;
this.responseMessage = responseMessage;
this.url = url;
}
/**
* @param message The detail message (which is saved for later retrieval
* by the {@link #getMessage()} method)
* @param responseCode Http response code. {@code -1} if no code can be discerned.
* @param responseMessage Http response message
* @param url The url that was invoked
* @param cause The cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A null value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @see HttpURLConnection#getResponseCode()
* @see HttpURLConnection#getResponseMessage()
*/
public HttpException(String message, int responseCode, String responseMessage, String url, Throwable cause) {
super(message);
initCause(cause);
this.responseCode = responseCode;
this.responseMessage = responseMessage;
this.url = url;
}
/**
* @param responseCode Http response code. {@code -1} if no code can be discerned.
* @param responseMessage Http response message
* @param url The url that was invoked
* @param cause The cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A null value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @see HttpURLConnection#getResponseCode()
* @see HttpURLConnection#getResponseMessage()
*/
public HttpException(int responseCode, String responseMessage, String url, Throwable cause) {
super("Server returned HTTP response code: " + responseCode + ", message: '" + responseMessage + "'" +
" for URL: " + url);
initCause(cause);
this.responseCode = responseCode;
this.responseMessage = responseMessage;
this.url = url;
}
/**
* @param responseCode Http response code. {@code -1} if no code can be discerned.
* @param responseMessage Http response message
* @param url The url that was invoked
* @param cause The cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A null value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @see HttpURLConnection#getResponseCode()
* @see HttpURLConnection#getResponseMessage()
*/
public HttpException(int responseCode, String responseMessage, @CheckForNull URL url, Throwable cause) {
this(responseCode, responseMessage, url == null ? null : url.toString(), cause);
}
/**
* Http response code of the request that cause the exception
*
* @return {@code -1} if no code can be discerned.
*/
public int getResponseCode() {
return responseCode;
}
/**
* Http response message of the request that cause the exception
*
* @return {@code null} if no response message can be discerned.
*/
public String getResponseMessage() {
return responseMessage;
}
/**
* The http URL that caused the exception
*
* @return url
*/
public String getUrl() {
return url;
}
}

View File

@@ -1,33 +0,0 @@
/*
* The MIT License
*
* Copyright (c) 2010, Kohsuke Kawaguchi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
class JsonCollaborators {
List<String> collaborators;
}

View File

@@ -1,38 +0,0 @@
/*
* The MIT License
*
* Copyright (c) 2011, Eric Maupin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
/**
* @author Eric Maupin
*/
class JsonIssue {
GHIssue issue;
GHIssue wrap(GHRepository r) {
issue.owner = r;
issue.root = r.root;
return issue;
}
}

View File

@@ -1,16 +0,0 @@
package org.kohsuke.github;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
class JsonIssueComments {
List<GHIssueComment> comments;
List<GHIssueComment> wrap(GHIssue owner) {
for (GHIssueComment c : comments)
c.owner = owner;
return comments;
}
}

View File

@@ -1,38 +0,0 @@
/*
* The MIT License
*
* Copyright (c) 2011, Eric Maupin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
import java.util.List;
class JsonIssues {
List<GHIssue> issues;
public List<GHIssue> wrap(GHRepository owner) {
for (GHIssue issue : issues) {
issue.owner = owner;
issue.root = owner.root;
}
return issues;
}
}

View File

@@ -1,44 +0,0 @@
/*
* The MIT License
*
* Copyright (c) 2010, Kohsuke Kawaguchi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
*
*/
class JsonOrganizations {
public List<GHOrganization> organizations;
public Map<String,GHOrganization> wrap(GitHub root) {
Map<String,GHOrganization> map = new TreeMap<String, GHOrganization>();
for (GHOrganization o : organizations) {
o.root = root;
map.put(o.getLogin(),o);
}
return map;
}
}

View File

@@ -1,37 +0,0 @@
/*
* The MIT License
*
* Copyright (c) 2010, Kohsuke Kawaguchi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
/**
* @author Kohsuke Kawaguchi
*/
class JsonPullRequest {
public GHPullRequest pull;
public GHPullRequest wrap(GHRepository owner) {
pull.owner = owner;
pull.root = owner.root;
return pull;
}
}

View File

@@ -0,0 +1,8 @@
package org.kohsuke.github;
/**
* @author Kohsuke Kawaguchi
*/
class JsonRateLimit {
GHRateLimit rate;
}

View File

@@ -1,36 +0,0 @@
/*
* The MIT License
*
* Copyright (c) 2010, Kohsuke Kawaguchi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
/**
* @author Kohsuke Kawaguchi
*/
class JsonRepository {
public GHRepository repository;
public GHRepository wrap(GitHub root) {
repository.root = root;
return repository;
}
}

View File

@@ -1,13 +0,0 @@
package org.kohsuke.github;
/**
* @author Kohsuke Kawaguchi
*/
class JsonTeam {
public GHTeam team;
GHTeam wrap(GHOrganization org) {
team.org = org;
return team;
}
}

Some files were not shown because too many files have changed in this diff Show More