Client to Github API

To access the API you need an instance of a GithubAPI client.

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.

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"

Introduced properties

fun api_url: String

github :: GithubAPI :: api_url

Github API base url.
protected fun api_url=(api_url: String)

github :: GithubAPI :: api_url=

Github API base url.
fun auth: nullable String

github :: GithubAPI :: auth

Github API OAuth token
protected fun auth=(auth: nullable String)

github :: GithubAPI :: auth=

Github API OAuth token
fun clear_cache

github :: GithubAPI :: clear_cache

Delete the cache directory.
init defaultinit(auth: nullable String, user_agent: nullable String)

github :: GithubAPI :: defaultinit

fun deserialize(string: nullable Serializable): nullable Object

github :: GithubAPI :: deserialize

Deserialize an object
fun enable_cache: Bool

github :: GithubAPI :: enable_cache

Enable caching for this client.
fun enable_cache=(enable_cache: Bool)

github :: GithubAPI :: enable_cache=

Enable caching for this client.
fun get(path: String, headers: nullable HeaderMap, data: nullable String): nullable Object

github :: GithubAPI :: get

Execute a GET request on Github API.
fun get_auth_user: nullable User

github :: GithubAPI :: get_auth_user

Get the Github logged user from auth token.
fun get_branch(repo_slug: String, name: String): nullable Branch

github :: GithubAPI :: get_branch

Get the Github branch with name.
fun get_commit(repo_slug: String, sha: String): nullable Commit

github :: GithubAPI :: get_commit

Get the Github commit with sha.
fun get_commit_comment(repo_slug: String, id: Int): nullable CommitComment

github :: GithubAPI :: get_commit_comment

Get the Github commit comment with id.
fun get_commit_status(repo_slug: String, sha: String): nullable CommitStatus

github :: GithubAPI :: get_commit_status

Get the status of a commit
fun get_issue(repo_slug: String, number: Int): nullable Issue

github :: GithubAPI :: get_issue

Get the Github issue #number.
fun get_issue_comment(repo_slug: String, id: Int): nullable IssueComment

github :: GithubAPI :: get_issue_comment

Get the Github issue comment with id.
fun get_issue_comments(repo_slug: String, issue_number: Int, page: nullable Int, per_page: nullable Int): Array[IssueComment]

github :: GithubAPI :: get_issue_comments

List of event on this issue.
fun get_issue_event(repo_slug: String, id: Int): nullable IssueEvent

github :: GithubAPI :: get_issue_event

Get the Github issue event with id.
fun get_issue_events(repo_slug: String, issue_number: Int, page: nullable Int, per_page: nullable Int): Array[IssueEvent]

github :: GithubAPI :: get_issue_events

List of events on this issue.
fun get_label(repo_slug: String, name: String): nullable Label

github :: GithubAPI :: get_label

Get the Github label with name.
fun get_milestone(repo_slug: String, id: Int): nullable Milestone

github :: GithubAPI :: get_milestone

Get the Github milestone with id.
fun get_pull(repo_slug: String, number: Int): nullable PullRequest

github :: GithubAPI :: get_pull

Get the Github pull request #number.
fun get_pull_comment(repo_slug: String, id: Int): nullable PullComment

github :: GithubAPI :: get_pull_comment

Get a specific pull request comment
fun get_pull_comments(repo_slug: String, pull_number: Int, page: nullable Int, per_page: nullable Int): Array[PullComment]

github :: GithubAPI :: get_pull_comments

List of comments on a pull request
fun get_repo(repo_slug: String): nullable Repo

github :: GithubAPI :: get_repo

Get the Github repo with full_name.
fun get_repo_branches(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[Branch]

github :: GithubAPI :: get_repo_branches

List of repo branches.
fun get_repo_contrib_stats(repo_slug: String): Array[ContributorStats]

github :: GithubAPI :: get_repo_contrib_stats

List of contributor related statistics.
fun get_repo_issues(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[Issue]

github :: GithubAPI :: get_repo_issues

List of issues associated with their ids.
fun get_repo_labels(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[Label]

github :: GithubAPI :: get_repo_labels

List of labels associated with their names.
fun get_repo_milestones(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[Milestone]

github :: GithubAPI :: get_repo_milestones

List of milestones associated with their ids.
fun get_repo_pulls(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[PullRequest]

github :: GithubAPI :: get_repo_pulls

List of pull-requests associated with their ids.
fun get_user(login: String): nullable User

github :: GithubAPI :: get_user

Get the Github user with login
fun has_cache(key: String): Bool

github :: GithubAPI :: has_cache

Check if a cache file exists for key.
fun last_error: nullable Error

github :: GithubAPI :: last_error

Last error occured during Github API communications.
fun last_error=(last_error: nullable Error)

github :: GithubAPI :: last_error=

Last error occured during Github API communications.
fun new_headers: HeaderMap

github :: GithubAPI :: new_headers

Headers to use on all requests
fun search_repo_issues(repo_slug: String, query: String, page: nullable Int, per_page: nullable Int): nullable SearchResults

github :: GithubAPI :: search_repo_issues

Search issues in this repo form an advanced query.
fun send(method: String, path: String, headers: nullable HeaderMap, body: nullable String): nullable String

github :: GithubAPI :: send

Send a HTTPRequest to the Github API
fun store: JsonStore

github :: GithubAPI :: store

JsonStore used to cache data.
fun store=(store: JsonStore)

github :: GithubAPI :: store=

JsonStore used to cache data.
fun user_agent: String

github :: GithubAPI :: user_agent

User agent used for HTTP requests.
protected fun user_agent=(user_agent: nullable String)

github :: GithubAPI :: user_agent=

User agent used for HTTP requests.
fun valid_tokens: Array[String]

github :: GithubAPI :: valid_tokens

Tokens mocked as valid
protected fun valid_tokens=(valid_tokens: Array[String])

github :: GithubAPI :: valid_tokens=

Tokens mocked as valid
fun was_error: Bool

github :: GithubAPI :: was_error

Does the last request provoqued an error?
protected fun was_error=(was_error: Bool)

github :: GithubAPI :: was_error=

Does the last request provoqued an error?

Redefined properties

redef type SELF: GithubAPI

github $ GithubAPI :: SELF

Type of this instance, automatically specialized in every class
redef fun get(key: String, headers: nullable HeaderMap, data: nullable String): nullable Object

github :: cache $ GithubAPI :: get

If no cache data is found for key then json is loaded from Github API.
redef fun get_auth_user: nullable User

github :: test_wallet $ GithubAPI :: get_auth_user

Mock so it returns the response from a file

All properties

fun !=(other: nullable Object): Bool

core :: Object :: !=

Have self and other different values?
fun ==(other: nullable Object): Bool

core :: Object :: ==

Have self and other the same value?
type CLASS: Class[SELF]

core :: Object :: CLASS

The type of the class of self.
type SELF: Object

core :: Object :: SELF

Type of this instance, automatically specialized in every class
fun api_url: String

github :: GithubAPI :: api_url

Github API base url.
protected fun api_url=(api_url: String)

github :: GithubAPI :: api_url=

Github API base url.
fun auth: nullable String

github :: GithubAPI :: auth

Github API OAuth token
protected fun auth=(auth: nullable String)

github :: GithubAPI :: auth=

Github API OAuth token
protected fun class_factory(name: String): CLASS

core :: Object :: class_factory

Implementation used by get_class to create the specific class.
fun class_name: String

core :: Object :: class_name

The class name of the object.
fun clear_cache

github :: GithubAPI :: clear_cache

Delete the cache directory.
init defaultinit(auth: nullable String, user_agent: nullable String)

github :: GithubAPI :: defaultinit

fun deserialize(string: nullable Serializable): nullable Object

github :: GithubAPI :: deserialize

Deserialize an object
fun enable_cache: Bool

github :: GithubAPI :: enable_cache

Enable caching for this client.
fun enable_cache=(enable_cache: Bool)

github :: GithubAPI :: enable_cache=

Enable caching for this client.
fun get(path: String, headers: nullable HeaderMap, data: nullable String): nullable Object

github :: GithubAPI :: get

Execute a GET request on Github API.
fun get_auth_user: nullable User

github :: GithubAPI :: get_auth_user

Get the Github logged user from auth token.
fun get_branch(repo_slug: String, name: String): nullable Branch

github :: GithubAPI :: get_branch

Get the Github branch with name.
fun get_class: CLASS

core :: Object :: get_class

The meta-object representing the dynamic type of self.
fun get_commit(repo_slug: String, sha: String): nullable Commit

github :: GithubAPI :: get_commit

Get the Github commit with sha.
fun get_commit_comment(repo_slug: String, id: Int): nullable CommitComment

github :: GithubAPI :: get_commit_comment

Get the Github commit comment with id.
fun get_commit_status(repo_slug: String, sha: String): nullable CommitStatus

github :: GithubAPI :: get_commit_status

Get the status of a commit
fun get_issue(repo_slug: String, number: Int): nullable Issue

github :: GithubAPI :: get_issue

Get the Github issue #number.
fun get_issue_comment(repo_slug: String, id: Int): nullable IssueComment

github :: GithubAPI :: get_issue_comment

Get the Github issue comment with id.
fun get_issue_comments(repo_slug: String, issue_number: Int, page: nullable Int, per_page: nullable Int): Array[IssueComment]

github :: GithubAPI :: get_issue_comments

List of event on this issue.
fun get_issue_event(repo_slug: String, id: Int): nullable IssueEvent

github :: GithubAPI :: get_issue_event

Get the Github issue event with id.
fun get_issue_events(repo_slug: String, issue_number: Int, page: nullable Int, per_page: nullable Int): Array[IssueEvent]

github :: GithubAPI :: get_issue_events

List of events on this issue.
fun get_label(repo_slug: String, name: String): nullable Label

github :: GithubAPI :: get_label

Get the Github label with name.
fun get_milestone(repo_slug: String, id: Int): nullable Milestone

github :: GithubAPI :: get_milestone

Get the Github milestone with id.
fun get_pull(repo_slug: String, number: Int): nullable PullRequest

github :: GithubAPI :: get_pull

Get the Github pull request #number.
fun get_pull_comment(repo_slug: String, id: Int): nullable PullComment

github :: GithubAPI :: get_pull_comment

Get a specific pull request comment
fun get_pull_comments(repo_slug: String, pull_number: Int, page: nullable Int, per_page: nullable Int): Array[PullComment]

github :: GithubAPI :: get_pull_comments

List of comments on a pull request
fun get_repo(repo_slug: String): nullable Repo

github :: GithubAPI :: get_repo

Get the Github repo with full_name.
fun get_repo_branches(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[Branch]

github :: GithubAPI :: get_repo_branches

List of repo branches.
fun get_repo_contrib_stats(repo_slug: String): Array[ContributorStats]

github :: GithubAPI :: get_repo_contrib_stats

List of contributor related statistics.
fun get_repo_issues(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[Issue]

github :: GithubAPI :: get_repo_issues

List of issues associated with their ids.
fun get_repo_labels(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[Label]

github :: GithubAPI :: get_repo_labels

List of labels associated with their names.
fun get_repo_milestones(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[Milestone]

github :: GithubAPI :: get_repo_milestones

List of milestones associated with their ids.
fun get_repo_pulls(repo_slug: String, page: nullable Int, per_page: nullable Int): Array[PullRequest]

github :: GithubAPI :: get_repo_pulls

List of pull-requests associated with their ids.
fun get_user(login: String): nullable User

github :: GithubAPI :: get_user

Get the Github user with login
fun has_cache(key: String): Bool

github :: GithubAPI :: has_cache

Check if a cache file exists for key.
fun hash: Int

core :: Object :: hash

The hash code of the object.
init init

core :: Object :: init

fun inspect: String

core :: Object :: inspect

Developer readable representation of self.
protected fun inspect_head: String

core :: Object :: inspect_head

Return "CLASSNAME:#OBJECTID".
intern fun is_same_instance(other: nullable Object): Bool

core :: Object :: is_same_instance

Return true if self and other are the same instance (i.e. same identity).
fun is_same_serialized(other: nullable Object): Bool

core :: Object :: is_same_serialized

Is self the same as other in a serialization context?
intern fun is_same_type(other: Object): Bool

core :: Object :: is_same_type

Return true if self and other have the same dynamic type.
fun last_error: nullable Error

github :: GithubAPI :: last_error

Last error occured during Github API communications.
fun last_error=(last_error: nullable Error)

github :: GithubAPI :: last_error=

Last error occured during Github API communications.
fun new_headers: HeaderMap

github :: GithubAPI :: new_headers

Headers to use on all requests
intern fun object_id: Int

core :: Object :: object_id

An internal hash code for the object based on its identity.
fun output

core :: Object :: output

Display self on stdout (debug only).
intern fun output_class_name

core :: Object :: output_class_name

Display class name on stdout (debug only).
fun search_repo_issues(repo_slug: String, query: String, page: nullable Int, per_page: nullable Int): nullable SearchResults

github :: GithubAPI :: search_repo_issues

Search issues in this repo form an advanced query.
fun send(method: String, path: String, headers: nullable HeaderMap, body: nullable String): nullable String

github :: GithubAPI :: send

Send a HTTPRequest to the Github API
fun serialization_hash: Int

core :: Object :: serialization_hash

Hash value use for serialization
fun store: JsonStore

github :: GithubAPI :: store

JsonStore used to cache data.
fun store=(store: JsonStore)

github :: GithubAPI :: store=

JsonStore used to cache data.
intern fun sys: Sys

core :: Object :: sys

Return the global sys object, the only instance of the Sys class.
abstract fun to_jvalue(env: JniEnv): JValue

core :: Object :: to_jvalue

fun to_s: String

core :: Object :: to_s

User readable representation of self.
fun user_agent: String

github :: GithubAPI :: user_agent

User agent used for HTTP requests.
protected fun user_agent=(user_agent: nullable String)

github :: GithubAPI :: user_agent=

User agent used for HTTP requests.
fun valid_tokens: Array[String]

github :: GithubAPI :: valid_tokens

Tokens mocked as valid
protected fun valid_tokens=(valid_tokens: Array[String])

github :: GithubAPI :: valid_tokens=

Tokens mocked as valid
fun was_error: Bool

github :: GithubAPI :: was_error

Does the last request provoqued an error?
protected fun was_error=(was_error: Bool)

github :: GithubAPI :: was_error=

Does the last request provoqued an error?
package_diagram github::GithubAPI GithubAPI core::Object Object github::GithubAPI->core::Object github::MockGithubAPI MockGithubAPI github::MockGithubAPI->github::GithubAPI

Parents

interface Object

core :: Object

The root of the class hierarchy.

Children

class MockGithubAPI

github :: MockGithubAPI

GithubAPI testing

Class definitions

github $ GithubAPI
# 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

github :: cache $ GithubAPI
redef class GithubAPI

	# Enable caching for this client.
	# Default is `false`.
	var enable_cache = false is writable

	# JsonStore used to cache data.
	#
	# Default directory is `".github_data/"`.
	var store = new JsonStore(".github_data/") is writable, lazy

	# Delete the cache directory.
	fun clear_cache do store.clear

	# If no cache data is found for `key` then json is loaded from Github API.
	redef fun get(key, headers, data) do
		if not enable_cache then return super
		if store.has_key(key) then
			# print "Get {key} (cache)" # debug
			was_error = false
			return deserialize(store.load_object(key).to_json)
		end
		var obj = super
		if not was_error and obj isa Serializable then
			cache(key, obj)
		end
		return obj
	end

	# Save `json` data in cache under `key`.
	private fun cache(key: String, obj: Serializable) do
		# print "Cache key {key}" # debug
		store.store_object(key, obj.to_json.parse_json.as(JsonObject))
	end

	# Check if a cache file exists for `key`.
	fun has_cache(key: String): Bool do
		return store.has_key(key)
	end
end
lib/github/cache.nit:43,1--82,3

github :: test_wallet $ GithubAPI
redef class GithubAPI

	# Tokens mocked as valid
	#
	# All other tokens will be considered as bad credentials.
	var valid_tokens = ["t1", "t2"]

	# Mock so it returns the response from a file
	#
	# See `update_responses_cache`.
	redef fun get_auth_user do
		if not valid_tokens.has(auth) then
			was_error = true
			last_error = new GithubAPIError("""{
				"message":"Bad credentials",
				"documentation_url":"https://developer.github.com/v3"
			}""", 401, "/user")
			return null
		end

		was_error = false
		last_error = null
		return new User("test")
	end
end
lib/github/tests/test_wallet.nit:19,1--43,3