1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Nit object oriented interface to [Github api](https://developer.github.com/v3/).
17 # This modules reifies Github API elements as Nit classes.
19 # For most use-cases you need to use the `GithubAPI` client.
24 # Client to Github API
26 # To access the API you need an instance of a `GithubAPI` client.
29 # # Get Github authentification token.
30 # var token = get_github_oauth
31 # assert not token.is_empty
34 # var api = new GithubAPI(token)
37 # The API client allows you to get Github API entities.
40 # var repo = api.load_repo("nitlang/nit")
42 # assert repo.name == "nit"
44 # var user = api.load_user("Morriar")
46 # assert user.login == "Morriar"
50 # Github API OAuth token
52 # To access your private ressources, you must
53 # [authenticate](https://developer.github.com/guides/basics-of-authentication/).
55 # For client applications, Github recommands to use the
56 # [OAuth tokens](https://developer.github.com/v3/oauth/) authentification method.
60 # Be aware that there is [rate limits](https://developer.github.com/v3/rate_limit/)
61 # associated to the key.
64 # Github API base url.
66 # Default is `https://api.github.com` and should not be changed.
67 var api_url
= "https://api.github.com"
69 # User agent used for HTTP requests.
71 # Default is `nit_github_api`.
73 # See <https://developer.github.com/v3/#user-agent-required>
74 var user_agent
= "nit_github_api"
78 # Internal Curl instance used to perform API calls.
79 private var ghcurl
: GithubCurl is noinit
83 # * `0`: only errors (default)
85 var verbose_lvl
= 0 is public
writable
88 ghcurl
= new GithubCurl(auth
, user_agent
)
91 # Execute a GET request on Github API.
93 # This method returns raw json data.
94 # See other `load_*` methods to use more expressive types.
96 # var api = new GithubAPI(get_github_oauth)
97 # var obj = api.get("repos/nitlang/nit")
98 # assert obj isa JsonObject
99 # assert obj["name"] == "nit"
101 # Returns `null` in case of `error`.
103 # obj = api.get("foo/bar/baz")
105 # assert api.was_error
106 # var err = api.last_error
107 # assert err isa GithubError
108 # assert err.name == "GithubAPIError"
109 # assert err.message == "Not Found"
110 fun get
(path
: String): nullable Jsonable do
111 path
= sanitize_uri
(path
)
112 var res
= ghcurl
.get_and_parse
("{api_url}/{path}")
113 if res
isa Error then
122 # Display a message depending on `verbose_lvl`.
123 fun message
(lvl
: Int, message
: String) do
124 if lvl
<= verbose_lvl
then print message
127 # Escape `uri` in an acceptable format for Github.
128 private fun sanitize_uri
(uri
: String): String do
129 # TODO better URI escape.
130 return uri
.replace
(" ", "%20")
133 # Last error occured during Github API communications.
134 var last_error
: nullable Error = null is public
writable
136 # Does the last request provoqued an error?
137 var was_error
= false is protected writable
139 # Load the json object from Github.
140 # See `GithubEntity::load_from_github`.
141 protected fun load_from_github
(key
: String): JsonObject do
142 message
(1, "Get {key} (github)")
144 if was_error
then return new JsonObject
145 return res
.as(JsonObject)
148 # Get the Github user with `login`
150 # Loads the `User` from the API or returns `null` if the user cannot be found.
152 # var api = new GithubAPI(get_github_oauth)
153 # var user = api.load_user("Morriar")
154 # assert user.login == "Morriar"
155 fun load_user
(login
: String): nullable User do
156 var user
= new User(self, login
)
157 return user
.load_from_github
160 # Get the Github repo with `full_name`.
162 # Loads the `Repo` from the API or returns `null` if the repo cannot be found.
164 # var api = new GithubAPI(get_github_oauth)
165 # var repo = api.load_repo("nitlang/nit")
166 # assert repo.name == "nit"
167 # assert repo.owner.login == "nitlang"
168 # assert repo.default_branch.name == "master"
169 fun load_repo
(full_name
: String): nullable Repo do
170 var repo
= new Repo(self, full_name
)
171 return repo
.load_from_github
174 # Get the Github branch with `name`.
176 # Returns `null` if the branch cannot be found.
178 # var api = new GithubAPI(get_github_oauth)
179 # var repo = api.load_repo("nitlang/nit")
180 # assert repo != null
181 # var branch = api.load_branch(repo, "master")
182 # assert branch.name == "master"
183 # assert branch.commit isa Commit
184 fun load_branch
(repo
: Repo, name
: String): nullable Branch do
185 var branch
= new Branch(self, repo
, name
)
186 return branch
.load_from_github
189 # Get the Github commit with `sha`.
191 # Returns `null` if the commit cannot be found.
193 # var api = new GithubAPI(get_github_oauth)
194 # var repo = api.load_repo("nitlang/nit")
195 # assert repo != null
196 # var commit = api.load_commit(repo, "64ce1f")
197 # assert commit isa Commit
198 fun load_commit
(repo
: Repo, sha
: String): nullable Commit do
199 var commit
= new Commit(self, repo
, sha
)
200 return commit
.load_from_github
203 # Get the Github issue #`number`.
205 # Returns `null` if the issue cannot be found.
207 # var api = new GithubAPI(get_github_oauth)
208 # var repo = api.load_repo("nitlang/nit")
209 # assert repo != null
210 # var issue = api.load_issue(repo, 1)
211 # assert issue.title == "Doc"
212 fun load_issue
(repo
: Repo, number
: Int): nullable Issue do
213 var issue
= new Issue(self, repo
, number
)
214 return issue
.load_from_github
217 # Get the Github pull request #`number`.
219 # Returns `null` if the pull request cannot be found.
221 # var api = new GithubAPI(get_github_oauth)
222 # var repo = api.load_repo("nitlang/nit")
223 # assert repo != null
224 # var pull = api.load_pull(repo, 1)
225 # assert pull.title == "Doc"
226 # assert pull.user.login == "Morriar"
227 fun load_pull
(repo
: Repo, number
: Int): nullable PullRequest do
228 var pull
= new PullRequest(self, repo
, number
)
229 return pull
.load_from_github
232 # Get the Github label with `name`.
234 # Returns `null` if the label cannot be found.
236 # var api = new GithubAPI(get_github_oauth)
237 # var repo = api.load_repo("nitlang/nit")
238 # assert repo != null
239 # var labl = api.load_label(repo, "ok_will_merge")
240 # assert labl != null
241 fun load_label
(repo
: Repo, name
: String): nullable Label do
242 var labl
= new Label(self, repo
, name
)
243 return labl
.load_from_github
246 # Get the Github milestone with `id`.
248 # Returns `null` if the milestone cannot be found.
250 # var api = new GithubAPI(get_github_oauth)
251 # var repo = api.load_repo("nitlang/nit")
252 # assert repo != null
253 # var stone = api.load_milestone(repo, 4)
254 # assert stone.title == "v1.0prealpha"
255 fun load_milestone
(repo
: Repo, id
: Int): nullable Milestone do
256 var milestone
= new Milestone(self, repo
, id
)
257 return milestone
.load_from_github
260 # Get the Github issue event with `id`.
262 # Returns `null` if the event cannot be found.
264 # var api = new GithubAPI(get_github_oauth)
265 # var repo = api.load_repo("nitlang/nit")
266 # assert repo isa Repo
267 # var event = api.load_issue_event(repo, 199674194)
268 # assert event.actor.login == "privat"
269 # assert event.event == "labeled"
270 # assert event.labl.name == "need_review"
271 # assert event.issue.number == 945
272 fun load_issue_event
(repo
: Repo, id
: Int): nullable IssueEvent do
273 var event
= new IssueEvent(self, repo
, id
)
274 return event
.load_from_github
277 # Get the Github commit comment with `id`.
279 # Returns `null` if the comment cannot be found.
281 # var api = new GithubAPI(get_github_oauth)
282 # var repo = api.load_repo("nitlang/nit")
283 # assert repo != null
284 # var comment = api.load_commit_comment(repo, 8982707)
285 # assert comment.user.login == "Morriar"
286 # assert comment.body == "For testing purposes..."
287 # assert comment.commit.sha == "7eacb86d1e24b7e72bc9ac869bf7182c0300ceca"
288 fun load_commit_comment
(repo
: Repo, id
: Int): nullable CommitComment do
289 var comment
= new CommitComment(self, repo
, id
)
290 return comment
.load_from_github
293 # Get the Github issue comment with `id`.
295 # Returns `null` if the comment cannot be found.
297 # var api = new GithubAPI(get_github_oauth)
298 # var repo = api.load_repo("nitlang/nit")
299 # assert repo != null
300 # var comment = api.load_issue_comment(repo, 6020149)
301 # assert comment.user.login == "privat"
302 # assert comment.created_at.to_s == "2012-05-30T20:16:54Z"
303 # assert comment.issue.number == 10
304 fun load_issue_comment
(repo
: Repo, id
: Int): nullable IssueComment do
305 var comment
= new IssueComment(self, repo
, id
)
306 return comment
.load_from_github
309 # Get the Github diff comment with `id`.
311 # Returns `null` if the comment cannot be found.
313 # var api = new GithubAPI(get_github_oauth)
314 # var repo = api.load_repo("nitlang/nit")
315 # assert repo != null
316 # var comment = api.load_review_comment(repo, 21010363)
317 # assert comment.path == "src/modelize/modelize_property.nit"
318 # assert comment.original_position == 26
319 # assert comment.pull.number == 945
320 fun load_review_comment
(repo
: Repo, id
: Int): nullable ReviewComment do
321 var comment
= new ReviewComment(self, repo
, id
)
322 return comment
.load_from_github
326 # Something returned by the Github API.
328 # Mainly a Nit wrapper around a JSON objet.
329 abstract class GithubEntity
331 # Github API instance.
334 # FIXME constructor should be private
336 # Key used to access this entity from Github api base.
337 fun key
: String is abstract
339 # JSON representation of `self`.
341 # This is the same json structure than used by Github API.
342 var json
: JsonObject is noinit
, protected writable
344 # Load `json` from Github API.
345 private fun load_from_github
: nullable SELF do
346 json
= api
.load_from_github
(key
)
347 if api
.was_error
then return null
351 redef fun to_s
do return json
.to_json
354 fun html_url
: String do return json
["html_url"].to_s
359 # Provides access to [Github user data](https://developer.github.com/v3/users/).
360 # Should be accessed from `GithubAPI::load_user`.
364 redef var key
is lazy
do return "users/{login}"
369 # Init `self` from a `json` object.
370 init from_json
(api
: GithubAPI, json
: JsonObject) do
371 init(api
, json
["login"].to_s
)
375 # Avatar image url for this user.
376 fun avatar_url
: String do return json
["avatar_url"].to_s
379 # A Github repository.
381 # Provides access to [Github repo data](https://developer.github.com/v3/repos/).
382 # Should be accessed from `GithubAPI::load_repo`.
386 redef var key
is lazy
do return "repos/{full_name}"
388 # Repo full name on Github.
389 var full_name
: String
391 # Init `self` from a `json` object.
392 init from_json
(api
: GithubAPI, json
: JsonObject) do
393 init(api
, json
["full_name"].to_s
)
397 # Repo short name on Github.
398 fun name
: String do return json
["name"].to_s
400 # Get the repo owner.
402 return new User.from_json
(api
, json
["owner"].as(JsonObject))
405 # List of branches associated with their names.
406 fun branches
: Map[String, Branch] do
407 api
.message
(1, "Get branches for {full_name}")
408 var array
= api
.get
("repos/{full_name}/branches")
409 var res
= new HashMap[String, Branch]
410 if not array
isa JsonArray then return res
412 if not obj
isa JsonObject then continue
413 var name
= obj
["name"].to_s
414 res
[name
] = new Branch.from_json
(api
, self, obj
)
419 # List of issues associated with their ids.
420 fun issues
: Map[Int, Issue] do
421 api
.message
(1, "Get issues for {full_name}")
422 var res
= new HashMap[Int, Issue]
423 var issue
= last_issue
424 if issue
== null then return res
425 res
[issue
.number
] = issue
426 while issue
.number
> 1 do
427 issue
= api
.load_issue
(self, issue
.number
- 1)
428 assert issue
isa Issue
429 res
[issue
.number
] = issue
434 # Search issues in this repo form an advanced query.
439 # var issues = repo.search_issues("is:open label:need_review")
442 # See <https://developer.github.com/v3/search/#search-issues>.
443 fun search_issues
(query
: String): nullable Array[Issue] do
444 query
= "search/issues?q={query} repo:{full_name}"
445 var response
= api
.get
(query
)
446 if api
.was_error
then return null
447 var arr
= response
.as(JsonObject)["items"].as(JsonArray)
448 var res
= new Array[Issue]
450 res
.add
new Issue.from_json
(api
, self, obj
.as(JsonObject))
455 # Get the last published issue.
456 fun last_issue
: nullable Issue do
457 var array
= api
.get
("repos/{full_name}/issues")
458 if not array
isa JsonArray then return null
459 if array
.is_empty
then return null
460 var obj
= array
.first
461 if not obj
isa JsonObject then return null
462 return new Issue.from_json
(api
, self, obj
)
465 # List of labels associated with their names.
466 fun labels
: Map[String, Label] do
467 api
.message
(1, "Get labels for {full_name}")
468 var array
= api
.get
("repos/{full_name}/labels")
469 var res
= new HashMap[String, Label]
470 if not array
isa JsonArray then return res
472 if not obj
isa JsonObject then continue
473 var name
= obj
["name"].to_s
474 res
[name
] = new Label.from_json
(api
, self, obj
)
479 # List of milestones associated with their ids.
480 fun milestones
: Map[Int, Milestone] do
481 api
.message
(1, "Get milestones for {full_name}")
482 var array
= api
.get
("repos/{full_name}/milestones")
483 var res
= new HashMap[Int, Milestone]
484 if array
isa JsonArray then
486 if not obj
isa JsonObject then continue
487 var number
= obj
["number"].as(Int)
488 res
[number
] = new Milestone.from_json
(api
, self, obj
)
494 # List of pull-requests associated with their ids.
496 # Implementation notes: because PR numbers are not consecutive,
497 # PR are loaded from pages.
498 # See: https://developer.github.com/v3/pulls/#list-pull-requests
499 fun pulls
: Map[Int, PullRequest] do
500 api
.message
(1, "Get pulls for {full_name}")
501 var res
= new HashMap[Int, PullRequest]
503 var array
= api
.get
("{key}/pulls?page={page}").as(JsonArray)
504 while not array
.is_empty
do
506 if not obj
isa JsonObject then continue
507 var number
= obj
["number"].as(Int)
508 res
[number
] = new PullRequest.from_json
(api
, self, obj
)
511 array
= api
.get
("{key}/pulls?page={page}").as(JsonArray)
516 # List of contributor related statistics.
517 fun contrib_stats
: Array[ContributorStats] do
518 api
.message
(1, "Get contributor stats for {full_name}")
519 var res
= new Array[ContributorStats]
520 var array
= api
.get
("{key}/stats/contributors")
521 if array
isa JsonArray then
523 res
.add
new ContributorStats.from_json
(api
, obj
.as(JsonObject))
529 # Repo default branch.
530 fun default_branch
: Branch do
531 var name
= json
["default_branch"].to_s
532 var branch
= api
.load_branch
(self, name
)
533 assert branch
isa Branch
538 # A `RepoEntity` is something contained in a `Repo`.
539 abstract class RepoEntity
542 # Repo that contains `self`.
545 # Init `self` from a `json` object.
546 init from_json
(api
: GithubAPI, repo
: Repo, json
: JsonObject) do
555 # Should be accessed from `GithubAPI::load_branch`.
557 # See <https://developer.github.com/v3/repos/#list-branches>.
561 redef var key
is lazy
do return "{repo.key}/branches/{name}"
566 redef init from_json
(api
, repo
, json
) do
567 self.name
= json
["name"].to_s
571 # Get the last commit of `self`.
572 fun commit
: Commit do
573 return new Commit.from_json
(api
, repo
, json
["commit"].as(JsonObject))
576 # List all commits in `self`.
578 # This can be long depending on the branch size.
579 # Commit are returned in an unspecified order.
580 fun commits
: Array[Commit] do
581 var res
= new Array[Commit]
582 var done
= new HashSet[String]
583 var todos
= new Array[Commit]
585 while not todos
.is_empty
do
586 var commit
= todos
.pop
587 if done
.has
(commit
.sha
) then continue
590 for parent
in commit
.parents
do
600 # Should be accessed from `GithubAPI::load_commit`.
602 # See <https://developer.github.com/v3/repos/commits/>.
606 redef var key
is lazy
do return "{repo.key}/commits/{sha}"
611 redef init from_json
(api
, repo
, json
) do
612 self.sha
= json
["sha"].to_s
616 # Parent commits of `self`.
617 fun parents
: Array[Commit] do
618 var res
= new Array[Commit]
619 var parents
= json
["parents"]
620 if not parents
isa JsonArray then return res
621 for obj
in parents
do
622 if not obj
isa JsonObject then continue
623 res
.add
(api
.load_commit
(repo
, obj
["sha"].to_s
).as(not null))
628 # Author of the commit.
629 fun author
: nullable User do
630 if not json
.has_key
("author") then return null
631 var user
= json
["author"]
632 if not user
isa JsonObject then return null
633 return new User.from_json
(api
, user
)
636 # Committer of the commit.
637 fun committer
: nullable User do
638 if not json
.has_key
("committer") then return null
639 var user
= json
["author"]
640 if not user
isa JsonObject then return null
641 return new User.from_json
(api
, user
)
644 # Authoring date as ISODate.
645 fun author_date
: ISODate do
646 var commit
= json
["commit"].as(JsonObject)
647 var author
= commit
["author"].as(JsonObject)
648 return new ISODate.from_string
(author
["date"].to_s
)
651 # Commit date as ISODate.
652 fun commit_date
: ISODate do
653 var commit
= json
["commit"].as(JsonObject)
654 var author
= commit
["committer"].as(JsonObject)
655 return new ISODate.from_string
(author
["date"].to_s
)
658 # List files staged in this commit.
659 fun files
: Array[GithubFile] do
660 var res
= new Array[GithubFile]
661 var files
= json
["files"]
662 if not files
isa JsonArray then return res
664 res
.add
(new GithubFile(obj
.as(JsonObject)))
670 fun message
: String do return json
["commit"].as(JsonObject)["message"].to_s
675 # Should be accessed from `GithubAPI::load_issue`.
677 # See <https://developer.github.com/v3/issues/>.
681 redef var key
is lazy
do return "{repo.key}/issues/{number}"
686 redef init from_json
(api
, repo
, json
) do
687 self.number
= json
["number"].as(Int)
692 fun title
: String do return json
["title"].to_s
694 # User that created this issue.
696 return new User.from_json
(api
, json
["user"].as(JsonObject))
699 # List of labels on this issue associated to their names.
700 fun labels
: Map[String, Label] do
701 var res
= new HashMap[String, Label]
702 if not json
.has_key
("labels") then return res
703 for obj
in json
["labels"].as(JsonArray) do
704 if not obj
isa JsonObject then continue
705 var name
= obj
["name"].to_s
706 res
[name
] = new Label.from_json
(api
, repo
, obj
)
711 # State of the issue on Github.
712 fun state
: String do return json
["state"].to_s
714 # Is the issue locked?
715 fun locked
: Bool do return json
["locked"].as(Bool)
717 # Assigned `User` (if any).
718 fun assignee
: nullable User do
719 var assignee
= json
["assignee"]
720 if not assignee
isa JsonObject then return null
721 return new User.from_json
(api
, assignee
)
724 # `Milestone` (if any).
725 fun milestone
: nullable Milestone do
726 var milestone
= json
["milestone"]
727 if not milestone
isa JsonObject then return null
728 return new Milestone.from_json
(api
, repo
, milestone
)
731 # List of comments made on this issue.
732 fun comments
: Array[IssueComment] do
733 var res
= new Array[IssueComment]
734 var count
= comments_count
736 var array
= api
.get
("{key}/comments?page={page}")
737 if not array
isa JsonArray then
740 while not array
.is_empty
and res
.length
< count
do
742 if not obj
isa JsonObject then continue
743 var id
= obj
["id"].as(Int)
744 res
.add
(api
.load_issue_comment
(repo
, id
).as(not null))
747 array
= api
.get
("{key}/comments?page={page}").as(JsonArray)
752 # Number of comments on this issue.
753 fun comments_count
: Int do return json
["comments"].to_s
.to_i
755 # Creation time in ISODate format.
756 fun created_at
: ISODate do
757 return new ISODate.from_string
(json
["created_at"].to_s
)
760 # Last update time in ISODate format (if any).
761 fun updated_at
: nullable ISODate do
762 var res
= json
["updated_at"]
763 if res
== null then return null
764 return new ISODate.from_string
(res
.to_s
)
767 # Close time in ISODate format (if any).
768 fun closed_at
: nullable ISODate do
769 var res
= json
["closed_at"]
770 if res
== null then return null
771 return new ISODate.from_string
(res
.to_s
)
774 # TODO link to pull request
776 # Full description of the issue.
777 fun body
: String do return json
["body"].to_s
779 # List of events on this issue.
780 fun events
: Array[IssueEvent] do
781 var res
= new Array[IssueEvent]
783 var array
= api
.get
("{key}/events?page={page}").as(JsonArray)
784 while not array
.is_empty
do
786 if not obj
isa JsonObject then continue
787 res
.add
new IssueEvent.from_json
(api
, repo
, obj
)
790 array
= api
.get
("{key}/events?page={page}").as(JsonArray)
795 # User that closed this issue (if any).
796 fun closed_by
: nullable User do
797 var closer
= json
["closed_by"]
798 if not closer
isa JsonObject then return null
799 return new User.from_json
(api
, closer
)
803 # A Github pull request.
805 # Should be accessed from `GithubAPI::load_pull`.
807 # PullRequest are basically Issues with more data.
808 # See <https://developer.github.com/v3/pulls/>.
812 redef var key
is lazy
do return "{repo.key}/pulls/{number}"
814 # Merge time in ISODate format (if any).
815 fun merged_at
: nullable ISODate do
816 var res
= json
["merged_at"]
817 if res
== null then return null
818 return new ISODate.from_string
(res
.to_s
)
822 fun merge_commit_sha
: String do return json
["merge_commit_sha"].to_s
824 # Count of comments made on the pull request diff.
825 fun review_comments
: Int do return json
["review_comments"].to_s
.to_i
827 # Pull request head (can be a commit SHA or a branch name).
829 var json
= json
["head"].as(JsonObject)
830 return new PullRef(api
, json
)
833 # Pull request base (can be a commit SHA or a branch name).
835 var json
= json
["base"].as(JsonObject)
836 return new PullRef(api
, json
)
839 # Is this pull request merged?
840 fun merged
: Bool do return json
["merged"].as(Bool)
842 # Is this pull request mergeable?
843 fun mergeable
: Bool do return json
["mergeable"].as(Bool)
845 # Mergeable state of this pull request.
847 # See <https://developer.github.com/v3/pulls/#list-pull-requests>.
848 fun mergeable_state
: Int do return json
["mergeable_state"].to_s
.to_i
850 # User that merged this pull request (if any).
851 fun merged_by
: nullable User do
852 var merger
= json
["merged_by"]
853 if not merger
isa JsonObject then return null
854 return new User.from_json
(api
, merger
)
857 # Count of commits in this pull request.
858 fun commits
: Int do return json
["commits"].to_s
.to_i
861 fun additions
: Int do return json
["additions"].to_s
.to_i
863 # Deleted line count.
864 fun deletions
: Int do return json
["deletions"].to_s
.to_i
866 # Changed files count.
867 fun changed_files
: Int do return json
["changed_files"].to_s
.to_i
870 # A pull request reference (used for head and base).
873 # Api instance that maintains self.
876 # JSON representation.
879 # Label pointed by `self`.
880 fun labl
: String do return json
["label"].to_s
882 # Reference pointed by `self`.
883 fun ref
: String do return json
["ref"].to_s
885 # Commit SHA pointed by `self`.
886 fun sha
: String do return json
["sha"].to_s
888 # User pointed by `self`.
890 return new User.from_json
(api
, json
["user"].as(JsonObject))
893 # Repo pointed by `self`.
895 return new Repo.from_json
(api
, json
["repo"].as(JsonObject))
901 # Should be accessed from `GithubAPI::load_label`.
903 # See <https://developer.github.com/v3/issues/labels/>.
907 redef var key
is lazy
do return "{repo.key}/labels/{name}"
912 redef init from_json
(api
, repo
, json
) do
913 self.name
= json
["name"].to_s
918 fun color
: String do return json
["color"].to_s
921 # A Github milestone.
923 # Should be accessed from `GithubAPI::load_milestone`.
925 # See <https://developer.github.com/v3/issues/milestones/>.
929 redef var key
is lazy
do return "{repo.key}/milestones/{number}"
931 # The milestone id on Github.
934 redef init from_json
(api
, repo
, json
) do
936 self.number
= json
["number"].as(Int)
940 fun title
: String do return json
["title"].to_s
942 # Milestone long description.
943 fun description
: String do return json
["description"].to_s
945 # Count of opened issues linked to this milestone.
946 fun open_issues
: Int do return json
["open_issues"].to_s
.to_i
948 # Count of closed issues linked to this milestone.
949 fun closed_issues
: Int do return json
["closed_issues"].to_s
.to_i
952 fun state
: String do return json
["state"].to_s
954 # Creation time in ISODate format.
955 fun created_at
: ISODate do
956 return new ISODate.from_string
(json
["created_at"].to_s
)
959 # User that created this milestone.
961 return new User.from_json
(api
, json
["creator"].as(JsonObject))
964 # Due time in ISODate format (if any).
965 fun due_on
: nullable ISODate do
966 var res
= json
["updated_at"]
967 if res
== null then return null
968 return new ISODate.from_string
(res
.to_s
)
971 # Update time in ISODate format (if any).
972 fun updated_at
: nullable ISODate do
973 var res
= json
["updated_at"]
974 if res
== null then return null
975 return new ISODate.from_string
(res
.to_s
)
978 # Close time in ISODate format (if any).
979 fun closed_at
: nullable ISODate do
980 var res
= json
["closed_at"]
981 if res
== null then return null
982 return new ISODate.from_string
(res
.to_s
)
988 # There is two kinds of comments:
990 # * `CommitComment` are made on a commit page.
991 # * `IssueComment` are made on an issue or pull request page.
992 # * `ReviewComment` are made on the diff associated to a pull request.
993 abstract class Comment
996 # Identifier of this comment.
999 redef init from_json
(api
, repo
, json
) do
1000 self.id
= json
["id"].as(Int)
1004 # User that made this comment.
1006 return new User.from_json
(api
, json
["user"].as(JsonObject))
1009 # Creation time in ISODate format.
1010 fun created_at
: ISODate do
1011 return new ISODate.from_string
(json
["created_at"].to_s
)
1014 # Last update time in ISODate format (if any).
1015 fun updated_at
: nullable ISODate do
1016 if not json
.has_key
("updated_at") then return null
1017 return new ISODate.from_string
(json
["updated_at"].to_s
)
1020 # Comment body text.
1021 fun body
: String do return json
["body"].to_s
1023 # Does the comment contain an acknowledgement (+1)
1026 return body
.has
("\\+1\\b".to_re
) or body
.has
(":+1:") or body
.has
(":shipit:")
1030 # A comment made on a commit.
1034 redef var key
is lazy
do return "{repo.key}/comments/{id}"
1037 fun commit
: Commit do
1038 return api
.load_commit
(repo
, json
["commit_id"].to_s
).as(not null)
1041 # Position of the comment on the line.
1042 fun position
: nullable String do
1043 if not json
.has_key
("position") then return null
1044 var res
= json
["position"]
1045 if res
== null then return null
1049 # Line of the comment.
1050 fun line
: nullable String do
1051 if not json
.has_key
("line") then return null
1052 var res
= json
["line"]
1053 if res
== null then return null
1057 # Path of the commented file.
1058 fun path
: String do return json
["path"].to_s
1061 # Comments made on Github issue and pull request pages.
1063 # Should be accessed from `GithubAPI::load_issue_comment`.
1065 # See <https://developer.github.com/v3/issues/comments/>.
1069 redef var key
is lazy
do return "{repo.key}/issues/comments/{id}"
1071 # Issue that contains `self`.
1073 var number
= issue_url
.split
("/").last
.to_i
1074 return api
.load_issue
(repo
, number
).as(not null)
1077 # Link to the issue document on API.
1078 fun issue_url
: String do return json
["issue_url"].to_s
1081 # Comments made on Github pull request diffs.
1083 # Should be accessed from `GithubAPI::load_diff_comment`.
1085 # See <https://developer.github.com/v3/pulls/comments/>.
1089 redef var key
is lazy
do return "{repo.key}/pulls/comments/{id}"
1091 # Pull request that contains `self`.
1092 fun pull
: PullRequest do
1093 var number
= pull_request_url
.split
("/").last
.to_i
1094 return api
.load_pull
(repo
, number
).as(not null)
1097 # Link to the pull request on API.
1098 fun pull_request_url
: String do return json
["pull_request_url"].to_s
1101 fun diff_hunk
: String do return json
["diff_hunk"].to_s
1103 # Path of commented file.
1104 fun path
: String do return json
["path"].to_s
1106 # Position of the comment on the file.
1107 fun position
: Int do return json
["position"].to_s
.to_i
1109 # Original position in the diff.
1110 fun original_position
: Int do return json
["original_position"].to_s
.to_i
1112 # Commit referenced by this comment.
1113 fun commit_id
: String do return json
["commit_id"].to_s
1115 # Original commit id.
1116 fun original_commit_id
: String do return json
["original_commit_id"].to_s
1119 # An event that occurs on a Github `Issue`.
1121 # Should be accessed from `GithubAPI::load_issue_event`.
1123 # See <https://developer.github.com/v3/issues/events/>.
1127 redef var key
is lazy
do return "{repo.key}/issues/events/{id}"
1129 # Event id on Github.
1132 redef init from_json
(api
, repo
, json
) do
1133 self.id
= json
["id"].as(Int)
1137 # Issue that contains `self`.
1139 return new Issue.from_json
(api
, repo
, json
["issue"].as(JsonObject))
1142 # User that initiated the event.
1144 return new User.from_json
(api
, json
["actor"].as(JsonObject))
1147 # Creation time in ISODate format.
1148 fun created_at
: ISODate do
1149 return new ISODate.from_string
(json
["created_at"].to_s
)
1153 fun event
: String do return json
["event"].to_s
1155 # Commit linked to this event (if any).
1156 fun commit_id
: nullable String do
1157 var res
= json
["commit_id"]
1158 if res
== null then return null
1162 # Label linked to this event (if any).
1163 fun labl
: nullable Label do
1164 var res
= json
["label"]
1165 if not res
isa JsonObject then return null
1166 return new Label.from_json
(api
, repo
, res
)
1169 # User linked to this event (if any).
1170 fun assignee
: nullable User do
1171 var res
= json
["assignee"]
1172 if not res
isa JsonObject then return null
1173 return new User.from_json
(api
, res
)
1176 # Milestone linked to this event (if any).
1177 fun milestone
: nullable Milestone do
1178 var res
= json
["milestone"]
1179 if not res
isa JsonObject then return null
1180 return new Milestone.from_json
(api
, repo
, res
)
1183 # Rename linked to this event (if any).
1184 fun rename
: nullable RenameAction do
1185 var res
= json
["rename"]
1186 if res
== null then return null
1187 return new RenameAction(res
.as(JsonObject))
1191 # A rename action maintains the name before and after a renaming action.
1195 var json
: JsonObject
1197 # Name before renaming.
1198 fun from
: String do return json
["from"].to_s
1200 # Name after renaming.
1201 fun to
: String do return json
["to"].to_s
1204 # Contributors list with additions, deletions, and commit counts.
1206 # Should be accessed from `Repo::contrib_stats`.
1208 # See <https://developer.github.com/v3/repos/statistics/>.
1209 class ContributorStats
1212 redef type OTHER: ContributorStats
1214 # Github API client.
1218 var json
: JsonObject
1220 # Init `self` from a `json` object.
1221 init from_json
(api
: GithubAPI, json
: JsonObject) do
1226 # User these statistics are about.
1228 return new User.from_json
(api
, json
["author"].as(JsonObject))
1231 # Total number of commit.
1232 fun total
: Int do return json
["total"].to_s
.to_i
1234 # Are of weeks of activity with detailed statistics.
1235 fun weeks
: JsonArray do return json
["weeks"].as(JsonArray)
1237 # ContributorStats can be compared on the total amount of commits.
1238 redef fun <(o
) do return total
< o
.total
1241 # A Github file representation.
1243 # Mostly a wrapper around a json object.
1247 var json
: JsonObject
1250 fun filename
: String do return json
["filename"].to_s