github :: GithubAPI :: defaultinit
# Client to Github API
#
# To access the API you need an instance of a `GithubAPI` client.
#
# ~~~nitish
# # Get Github authentification token.
# var token = get_github_oauth
# assert not token.is_empty
#
# # Init the client.
# var api = new GithubAPI(token)
# ~~~
#
# The API client allows you to get Github API entities.
#
# ~~~nitish
# var repo = api.get_repo("nitlang/nit")
# assert repo != null
# assert repo.name == "nit"
#
# var user = api.get_user("Morriar")
# assert user != null
# assert user.login == "Morriar"
# ~~~
class GithubAPI
# 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.
#
#
#
# Be aware that there is [rate limits](https://developer.github.com/v3/rate_limit/)
# associated to the key.
var auth: nullable String = null is optional
# User agent used for HTTP requests.
#
# Default is `nit_github_api`.
#
# See <https://developer.github.com/v3/#user-agent-required>
var user_agent: String = "nit_github_api" is optional
# Headers to use on all requests
fun new_headers: HeaderMap do
var map = new HeaderMap
var auth = self.auth
if auth != null then
map["Authorization"] = "token {auth}"
end
map["User-Agent"] = user_agent
# FIXME remove when projects and team are no more in beta
map["Accept"] = "application/vnd.github.inertia-preview+json"
map["Accept"] = "application/vnd.github.hellcat-preview+json"
return map
end
# Github API base url.
#
# Default is `https://api.github.com` and should not be changed.
var api_url = "https://api.github.com"
# Send a HTTPRequest to the Github API
fun send(method, path: String, headers: nullable HeaderMap, body: nullable String): nullable String do
last_error = null
path = sanitize_uri(path)
var uri = "{api_url}{path}"
var request = new CurlHTTPRequest(uri)
request.method = method
request.user_agent = user_agent
request.headers = headers or else self.new_headers
request.body = body
return check_response(uri, request.execute)
end
private fun check_response(uri: String, response: CurlResponse): nullable String do
if response isa CurlResponseSuccess then
was_error = false
return response.body_str
else if response isa CurlResponseFailed then
last_error = new GithubAPIError(
response.error_msg,
response.error_code,
uri
)
was_error = true
return null
else abort
end
# Deserialize an object
fun deserialize(string: nullable Serializable): nullable Object do
if string == null then return null
var deserializer = new GithubDeserializer(string.to_s)
var res = deserializer.deserialize
if deserializer.errors.not_empty then
was_error = true
last_error = new GithubDeserializerErrors("Deserialization failed", deserializer.errors)
return null
else if res isa GithubError then
was_error = true
last_error = res
return null
end
was_error = false
return res
end
# Escape `uri` in an acceptable format for Github.
private fun sanitize_uri(uri: String): String do
# TODO better URI escape.
return uri.replace(" ", "%20")
end
# Last error occured during Github API communications.
var last_error: nullable Error = null is public writable
# Does the last request provoqued an error?
var was_error = false is protected writable
# Execute a GET request on Github API.
#
# This method returns a deserialized result.
#
# For raw data see `send`.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var obj = api.get("/repos/nitlang/nit")
# assert obj isa Repo
# assert obj.name == "nit"
# ~~~
#
# Returns `null` in case of `error`.
#
# ~~~nitish
# obj = api.get("/foo/bar/baz")
# assert obj == null
# assert api.was_error
# assert api.last_error isa GithubError
# ~~~
fun get(path: String, headers: nullable HeaderMap, data: nullable String): nullable Object do
return deserialize(send("GET", path, headers, data))
end
# Get the Github logged user from `auth` token.
#
# Loads the `User` from the API or returns `null` if the user cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var user = api.get_auth_user
# assert user.login == "Morriar"
# ~~~
fun get_auth_user: nullable User do
return get("/user").as(nullable User)
end
# Get the Github user with `login`
#
# Loads the `User` from the API or returns `null` if the user cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var user = api.get_user("Morriar")
# print user or else "null"
# assert user.login == "Morriar"
# ~~~
fun get_user(login: String): nullable User do
return get("/users/{login}").as(nullable User)
end
# Get the Github repo with `full_name`.
#
# Loads the `Repo` from the API or returns `null` if the repo cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo.name == "nit"
# assert repo.owner.login == "nitlang"
# assert repo.default_branch == "master"
# ~~~
fun get_repo(repo_slug: String): nullable Repo do
return get("/repos/{repo_slug}").as(nullable Repo)
end
# List of repo branches.
#
# Pagination:
# * `page`: page to fetch (default: 1)
# * `per_page`: number of branches by page (default: 30)
fun get_repo_branches(repo_slug: String, page, per_page: nullable Int): Array[Branch] do
return new GithubArray[Branch].from(get(
"/repos/{repo_slug}/branches?{pagination(page, per_page)}"))
end
# List of issues associated with their ids.
fun get_repo_issues(repo_slug: String, page, per_page: nullable Int): Array[Issue] do
return new GithubArray[Issue].from(get(
"/repos/{repo_slug}/issues?{pagination(page, per_page)}"))
end
# Search issues in this repo form an advanced query.
#
# Example:
#
# ~~~nitish
# var issues = repo.search_issues("is:open label:need_review")
# ~~~
#
# See <https://developer.github.com/v3/search/#search-issues>.
fun search_repo_issues(repo_slug: String, query: String, page, per_page: nullable Int): nullable SearchResults do
return get("/search/issues?q={query} repo:{repo_slug}&{pagination(page, per_page)}").as(nullable SearchResults)
end
# List of labels associated with their names.
fun get_repo_labels(repo_slug: String, page, per_page: nullable Int): Array[Label] do
return new GithubArray[Label].from(get(
"/repos/{repo_slug}/labels?{pagination(page, per_page)}"))
end
# List of milestones associated with their ids.
fun get_repo_milestones(repo_slug: String, page, per_page: nullable Int): Array[Milestone] do
return new GithubArray[Milestone].from(get(
"/repos/{repo_slug}/milestones?{pagination(page, per_page)}"))
end
# List of pull-requests associated with their ids.
#
# Implementation notes: because PR numbers are not consecutive,
# PR are loaded from pages.
# See: https://developer.github.com/v3/pulls/#list-pull-requests
fun get_repo_pulls(repo_slug: String, page, per_page: nullable Int): Array[PullRequest] do
return new GithubArray[PullRequest].from(get(
"/repos/{repo_slug}/pulls?{pagination(page, per_page)}"))
end
# List of contributor related statistics.
fun get_repo_contrib_stats(repo_slug: String): Array[ContributorStats] do
return new GithubArray[ContributorStats].from(get("/repos/{repo_slug}/stats/contributors"))
end
# Get the Github branch with `name`.
#
# Returns `null` if the branch cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo != null
# var branch = api.get_branch(repo, "master")
# assert branch.name == "master"
# assert branch.commit isa Commit
# ~~~
fun get_branch(repo_slug: String, name: String): nullable Branch do
return get("/repos/{repo_slug}/branches/{name}").as(nullable Branch)
end
# Get the Github commit with `sha`.
#
# Returns `null` if the commit cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo != null
# var commit = api.get_commit(repo, "64ce1f")
# assert commit isa Commit
# ~~~
fun get_commit(repo_slug: String, sha: String): nullable Commit do
return get("/repos/{repo_slug}/commits/{sha}").as(nullable Commit)
end
# Get the status of a commit
#
# The status holds the result of each check ran on a commit like CI, reviews etc.
fun get_commit_status(repo_slug: String, sha: String): nullable CommitStatus do
return get("/repos/{repo_slug}/commits/{sha}/status").as(nullable CommitStatus)
end
# Get the Github issue #`number`.
#
# Returns `null` if the issue cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo != null
# var issue = api.get_issue(repo, 1)
# assert issue.title == "Doc"
# ~~~
fun get_issue(repo_slug: String, number: Int): nullable Issue do
return get("/repos/{repo_slug}/issues/{number}").as(nullable Issue)
end
# List of event on this issue.
fun get_issue_comments(repo_slug: String, issue_number: Int, page, per_page: nullable Int): Array[IssueComment] do
return new GithubArray[IssueComment].from(get(
"/repos/{repo_slug}/issues/{issue_number}/comments?{pagination(page, per_page)}"))
end
# List of events on this issue.
fun get_issue_events(repo_slug: String, issue_number: Int, page, per_page: nullable Int): Array[IssueEvent] do
return new GithubArray[IssueEvent].from(get(
"/repos/{repo_slug}/issues/{issue_number}/events?{pagination(page, per_page)}"))
end
# Get the Github pull request #`number`.
#
# Returns `null` if the pull request cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo != null
# var pull = api.get_pull(repo, 1)
# assert pull.title == "Doc"
# assert pull.user.login == "Morriar"
# ~~~
fun get_pull(repo_slug: String, number: Int): nullable PullRequest do
return get("/repos/{repo_slug}/pulls/{number}").as(nullable PullRequest)
end
# List of comments on a pull request
fun get_pull_comments(repo_slug: String, pull_number: Int, page, per_page: nullable Int): Array[PullComment] do
return new GithubArray[PullComment].from(get(
"/repos/{repo_slug}/pulls/{pull_number}/comments?{pagination(page, per_page)}"))
end
# Get a specific pull request comment
fun get_pull_comment(repo_slug: String, id: Int): nullable PullComment do
return get("/repos/{repo_slug}/pulls/comments/{id}").as(nullable PullComment)
end
# Get the Github label with `name`.
#
# Returns `null` if the label cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo != null
# var labl = api.get_label(repo, "ok_will_merge")
# assert labl != null
# ~~~
fun get_label(repo_slug: String, name: String): nullable Label do
return get("/repos/{repo_slug}/labels/{name}").as(nullable Label)
end
# Get the Github milestone with `id`.
#
# Returns `null` if the milestone cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo != null
# var stone = api.get_milestone(repo, 4)
# assert stone.title == "v1.0prealpha"
# ~~~
fun get_milestone(repo_slug: String, id: Int): nullable Milestone do
return get("/repos/{repo_slug}/milestones/{id}").as(nullable Milestone)
end
# Get the Github issue event with `id`.
#
# Returns `null` if the event cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo isa Repo
# var event = api.get_issue_event(repo, 199674194)
# assert event isa IssueEvent
# assert event.actor.login == "privat"
# assert event.event == "labeled"
# assert event.labl isa Label
# assert event.labl.name == "need_review"
# ~~~
fun get_issue_event(repo_slug: String, id: Int): nullable IssueEvent do
return get("/repos/{repo_slug}/issues/events/{id}").as(nullable IssueEvent)
end
# Get the Github commit comment with `id`.
#
# Returns `null` if the comment cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo != null
# var comment = api.get_commit_comment(repo, 8982707)
# assert comment.user.login == "Morriar"
# assert comment.body == "For testing purposes...\n"
# assert comment.commit_id == "7eacb86d1e24b7e72bc9ac869bf7182c0300ceca"
# ~~~
fun get_commit_comment(repo_slug: String, id: Int): nullable CommitComment do
return get("/repos/{repo_slug}/comments/{id}").as(nullable CommitComment)
end
# Get the Github issue comment with `id`.
#
# Returns `null` if the comment cannot be found.
#
# ~~~nitish
# var api = new GithubAPI(get_github_oauth)
# var repo = api.get_repo("nitlang/nit")
# assert repo != null
# var comment = api.get_issue_comment(repo, 6020149)
# assert comment.user.login == "privat"
# assert comment.created_at.to_s == "2012-05-30T20:16:54Z"
# assert comment.issue_number == 10
# ~~~
fun get_issue_comment(repo_slug: String, id: Int): nullable IssueComment do
return get("/repos/{repo_slug}/issues/comments/{id}").as(nullable IssueComment)
end
private fun pagination(page, per_page: nullable Int): String do
return "page={page or else 1}&per_page={per_page or else 30}"
end
end
lib/github/api.nit:28,1--453,3