X-Git-Url: http://nitlanguage.org diff --git a/lib/github/api.nit b/lib/github/api.nit index 815172a..dc4e586 100644 --- a/lib/github/api.nit +++ b/lib/github/api.nit @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Nit object oriented interface to Github api. +# Nit object oriented interface to [Github api](https://developer.github.com/v3/). # # This modules reifies Github API elements as Nit classes. # @@ -21,11 +21,9 @@ module api import github_curl -# Interface to Github REST API. +# Client to Github API # -# Used by all `GithubEntity` to perform requests. -# -# Usage: +# To access the API you need an instance of a `GithubAPI` client. # # ~~~ # # Get Github authentification token. @@ -36,10 +34,10 @@ import github_curl # var api = new GithubAPI(token) # ~~~ # -# The API client allows to get Github API entities: +# The API client allows you to get Github API entities. # # ~~~ -# var repo = api.load_repo("privat/nit") +# var repo = api.load_repo("nitlang/nit") # assert repo != null # assert repo.name == "nit" # @@ -49,9 +47,16 @@ import github_curl # ~~~ class GithubAPI - # Github API OAuth token. + # Github API OAuth token + # + # To access your private ressources, you must + # [authenticate](https://developer.github.com/guides/basics-of-authentication/). + # + # For client applications, Github recommands to use the + # [OAuth tokens](https://developer.github.com/v3/oauth/) authentification method. + # + # # - # This token is used to authenticate the application on Github API. # Be aware that there is [rate limits](https://developer.github.com/v3/rate_limit/) # associated to the key. var auth: String @@ -89,7 +94,7 @@ class GithubAPI # See other `load_*` methods to use more expressive types. # # var api = new GithubAPI(get_github_oauth) - # var obj = api.get("repos/privat/nit") + # var obj = api.get("repos/nitlang/nit") # assert obj isa JsonObject # assert obj["name"] == "nit" # @@ -133,16 +138,16 @@ class GithubAPI # Load the json object from Github. # See `GithubEntity::load_from_github`. - private fun load_from_github(key: String): JsonObject do + protected fun load_from_github(key: String): JsonObject do message(1, "Get {key} (github)") var res = get(key) if was_error then return new JsonObject return res.as(JsonObject) end - # Get the Github user with `login`. + # Get the Github user with `login` # - # Returns `null` if the user cannot be found. + # Loads the `User` from the API or returns `null` if the user cannot be found. # # var api = new GithubAPI(get_github_oauth) # var user = api.load_user("Morriar") @@ -154,12 +159,12 @@ class GithubAPI # Get the Github repo with `full_name`. # - # Returns `null` if the repo cannot be found. + # Loads the `Repo` from the API or returns `null` if the repo cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo.name == "nit" - # assert repo.owner.login == "privat" + # assert repo.owner.login == "nitlang" # assert repo.default_branch.name == "master" fun load_repo(full_name: String): nullable Repo do var repo = new Repo(self, full_name) @@ -171,7 +176,7 @@ class GithubAPI # Returns `null` if the branch cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo != null # var branch = api.load_branch(repo, "master") # assert branch.name == "master" @@ -186,7 +191,7 @@ class GithubAPI # Returns `null` if the commit cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo != null # var commit = api.load_commit(repo, "64ce1f") # assert commit isa Commit @@ -200,7 +205,7 @@ class GithubAPI # Returns `null` if the issue cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo != null # var issue = api.load_issue(repo, 1) # assert issue.title == "Doc" @@ -214,7 +219,7 @@ class GithubAPI # Returns `null` if the pull request cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo != null # var pull = api.load_pull(repo, 1) # assert pull.title == "Doc" @@ -229,7 +234,7 @@ class GithubAPI # Returns `null` if the label cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo != null # var labl = api.load_label(repo, "ok_will_merge") # assert labl != null @@ -243,7 +248,7 @@ class GithubAPI # Returns `null` if the milestone cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo != null # var stone = api.load_milestone(repo, 4) # assert stone.title == "v1.0prealpha" @@ -257,7 +262,7 @@ class GithubAPI # Returns `null` if the event cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo isa Repo # var event = api.load_issue_event(repo, 199674194) # assert event.actor.login == "privat" @@ -266,9 +271,7 @@ class GithubAPI # assert event.issue.number == 945 fun load_issue_event(repo: Repo, id: Int): nullable IssueEvent do var event = new IssueEvent(self, repo, id) - event.load_from_github - if was_error then return null - return event + return event.load_from_github end # Get the Github commit comment with `id`. @@ -276,7 +279,7 @@ class GithubAPI # Returns `null` if the comment cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo != null # var comment = api.load_commit_comment(repo, 8982707) # assert comment.user.login == "Morriar" @@ -292,7 +295,7 @@ class GithubAPI # Returns `null` if the comment cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo != null # var comment = api.load_issue_comment(repo, 6020149) # assert comment.user.login == "privat" @@ -308,7 +311,7 @@ class GithubAPI # Returns `null` if the comment cannot be found. # # var api = new GithubAPI(get_github_oauth) - # var repo = api.load_repo("privat/nit") + # var repo = api.load_repo("nitlang/nit") # assert repo != null # var comment = api.load_review_comment(repo, 21010363) # assert comment.path == "src/modelize/modelize_property.nit" @@ -346,13 +349,15 @@ abstract class GithubEntity end redef fun to_s do return json.to_json + + # Github page url. + fun html_url: String do return json["html_url"].to_s end -# A Github user. +# A Github user # +# Provides access to [Github user data](https://developer.github.com/v3/users/). # Should be accessed from `GithubAPI::load_user`. -# -# See . class User super GithubEntity @@ -367,18 +372,14 @@ class User self.json = json end - # Github User page url. - fun html_url: String do return json["html_url"].to_s - # Avatar image url for this user. fun avatar_url: String do return json["avatar_url"].to_s end # A Github repository. # +# Provides access to [Github repo data](https://developer.github.com/v3/repos/). # Should be accessed from `GithubAPI::load_repo`. -# -# See . class Repo super GithubEntity @@ -396,9 +397,6 @@ class Repo # Repo short name on Github. fun name: String do return json["name"].to_s - # Github User page url. - fun html_url: String do return json["html_url"].to_s - # Get the repo owner. fun owner: User do return new User.from_json(api, json["owner"].as(JsonObject)) @@ -433,6 +431,27 @@ class Repo return res end + # Search issues in this repo form an advanced query. + # + # Example: + # + # ~~~nitish + # var issues = repo.search_issues("is:open label:need_review") + # ~~~ + # + # See . + fun search_issues(query: String): nullable Array[Issue] do + query = "search/issues?q={query} repo:{full_name}" + var response = api.get(query) + if api.was_error then return null + var arr = response.as(JsonObject)["items"].as(JsonArray) + var res = new Array[Issue] + for obj in arr do + res.add new Issue.from_json(api, self, obj.as(JsonObject)) + end + return res + end + # Get the last published issue. fun last_issue: nullable Issue do var array = api.get("repos/{full_name}/issues") @@ -494,6 +513,19 @@ class Repo return res end + # List of contributor related statistics. + fun contrib_stats: Array[ContributorStats] do + api.message(1, "Get contributor stats for {full_name}") + var res = new Array[ContributorStats] + var array = api.get("{key}/stats/contributors") + if array isa JsonArray then + for obj in array do + res.add new ContributorStats.from_json(api, obj.as(JsonObject)) + end + end + return res + end + # Repo default branch. fun default_branch: Branch do var name = json["default_branch"].to_s @@ -567,7 +599,7 @@ end # # Should be accessed from `GithubAPI::load_commit`. # -# See . +# See . class Commit super RepoEntity @@ -623,6 +655,17 @@ class Commit return new ISODate.from_string(author["date"].to_s) end + # List files staged in this commit. + fun files: Array[GithubFile] do + var res = new Array[GithubFile] + var files = json["files"] + if not files isa JsonArray then return res + for obj in files do + res.add(new GithubFile(obj.as(JsonObject))) + end + return res + end + # Commit message. fun message: String do return json["commit"].as(JsonObject)["message"].to_s end @@ -656,6 +699,7 @@ class Issue # List of labels on this issue associated to their names. fun labels: Map[String, Label] do var res = new HashMap[String, Label] + if not json.has_key("labels") then return res for obj in json["labels"].as(JsonArray) do if not obj isa JsonObject then continue var name = obj["name"].to_s @@ -975,6 +1019,12 @@ abstract class Comment # Comment body text. fun body: String do return json["body"].to_s + + # Does the comment contain an acknowledgement (+1) + fun is_ack: Bool + do + return body.has("\\+1\\b".to_re) or body.has(":+1:") or body.has(":shipit:") + end end # A comment made on a commit. @@ -1150,3 +1200,52 @@ class RenameAction # Name after renaming. fun to: String do return json["to"].to_s end + +# Contributors list with additions, deletions, and commit counts. +# +# Should be accessed from `Repo::contrib_stats`. +# +# See . +class ContributorStats + super Comparable + + redef type OTHER: ContributorStats + + # Github API client. + var api: GithubAPI + + # Json content. + var json: JsonObject + + # Init `self` from a `json` object. + init from_json(api: GithubAPI, json: JsonObject) do + self.api = api + self.json = json + end + + # User these statistics are about. + fun author: User do + return new User.from_json(api, json["author"].as(JsonObject)) + end + + # Total number of commit. + fun total: Int do return json["total"].to_s.to_i + + # Are of weeks of activity with detailed statistics. + fun weeks: JsonArray do return json["weeks"].as(JsonArray) + + # ContributorStats can be compared on the total amount of commits. + redef fun <(o) do return total < o.total +end + +# A Github file representation. +# +# Mostly a wrapper around a json object. +class GithubFile + + # Json content. + var json: JsonObject + + # File name. + fun filename: String do return json["filename"].to_s +end