lib/core/stream: LineIterator use CachedIterator
[nit.git] / lib / github / api.nit
index a1dcad4..4eb9a97 100644 (file)
 module api
 
 import github_curl
-intrude import json::serialization
+intrude import json::serialization_read
 
 # 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
@@ -37,7 +37,7 @@ intrude import json::serialization
 #
 # The API client allows you to get Github API entities.
 #
-# ~~~
+# ~~~nitish
 # var repo = api.load_repo("nitlang/nit")
 # assert repo != null
 # assert repo.name == "nit"
@@ -116,7 +116,7 @@ class GithubAPI
        #     assert err isa GithubError
        #     assert err.name == "GithubAPIError"
        #     assert err.message == "Not Found"
-       fun get(path: String): nullable Jsonable do
+       fun get(path: String): nullable Serializable do
                path = sanitize_uri(path)
                var res = ghcurl.get_and_parse("{api_url}{path}")
                if res isa Error then
@@ -200,7 +200,9 @@ class GithubAPI
                var array = get("/repos/{repo.full_name}/branches")
                var res = new Array[Branch]
                if not array isa JsonArray then return res
-               return deserialize(array.to_json).as(Array[Branch])
+               var deser = deserialize(array.to_json)
+               if deser isa Array[Object] then return res # empty array
+               return deser.as(Array[Branch])
        end
 
        # List of issues associated with their ids.
@@ -365,9 +367,9 @@ class GithubAPI
                var count = issue.comments or else 0
                var page = 1
                loop
-                       var array = get("/repos/{repo.full_name}/comments?page={page}")
+                       var array = get("/repos/{repo.full_name}/issues/{issue.number}/comments?page={page}")
                        if not array isa JsonArray then break
-                       if array.is_empty or res.length < count then break
+                       if array.is_empty then break
                        for obj in array do
                                if not obj isa JsonObject then continue
                                var id = obj["id"].as(Int)
@@ -375,6 +377,7 @@ class GithubAPI
                                if comment == null then continue
                                res.add(comment)
                        end
+                       if res.length >= count then break
                        page += 1
                end
                return res
@@ -465,7 +468,7 @@ class GithubAPI
        #     assert repo != null
        #     var comment = api.load_commit_comment(repo, 8982707)
        #     assert comment.user.login == "Morriar"
-       #     assert comment.body == "For testing purposes..."
+       #     assert comment.body == "For testing purposes...\n"
        #     assert comment.commit_id == "7eacb86d1e24b7e72bc9ac869bf7182c0300ceca"
        fun load_commit_comment(repo: Repo, id: Int): nullable CommitComment do
                return load_from_github("/repos/{repo.full_name}/comments/{id}").as(nullable CommitComment)
@@ -506,13 +509,10 @@ end
 #
 # Mainly a Nit wrapper around a JSON objet.
 abstract class GithubEntity
-       super Jsonable
        serialize
 
        # Github page url.
        var html_url: nullable String is writable
-
-       redef fun to_json do return serialize_to_json
 end
 
 # A Github user
@@ -520,7 +520,7 @@ end
 # Provides access to [Github user data](https://developer.github.com/v3/users/).
 # Should be accessed from `GithubAPI::load_user`.
 class User
-       super GithubEntity
+       super GitUser
        serialize
 
        # Github login.
@@ -528,6 +528,15 @@ class User
 
        # Avatar image url for this user.
        var avatar_url: nullable String is writable
+
+       # User public name if any.
+       var name: nullable String is writable
+
+       # User public email if any.
+       var email: nullable String is writable
+
+       # User public blog if any.
+       var blog: nullable String is writable
 end
 
 # A Github repository.
@@ -583,10 +592,10 @@ class Commit
        var parents: nullable Array[Commit] = null is writable
 
        # Author of the commit.
-       var author: nullable User is writable
+       var author: nullable GitUser is writable
 
        # Committer of the commit.
-       var committer: nullable User is writable
+       var committer: nullable GitUser is writable
 
        # Authoring date as String.
        var author_date: nullable String is writable
@@ -613,6 +622,46 @@ class Commit
 
        # Commit message.
        var message: nullable String is writable
+
+       # Git commit representation linked to this commit.
+       var commit: nullable GitCommit
+end
+
+# A Git Commit representation
+class GitCommit
+       super GithubEntity
+       serialize
+
+       # Commit SHA.
+       var sha: nullable String is writable
+
+       # Parent commits of `self`.
+       var parents: nullable Array[GitCommit] = null is writable
+
+       # Author of the commit.
+       var author: nullable GitUser is writable
+
+       # Committer of the commit.
+       var committer: nullable GitUser is writable
+
+       # Commit message.
+       var message: nullable String is writable
+end
+
+# Git user authoring data
+class GitUser
+       super GithubEntity
+       serialize
+
+       # Authoring date.
+       var date: nullable String = null is writable
+
+       # Authoring date as ISODate.
+       fun iso_date: nullable ISODate do
+               var date = self.date
+               if date == null then return null
+               return new ISODate.from_string(date)
+       end
 end
 
 # A Github issue.
@@ -689,7 +738,7 @@ class Issue
        var closed_by: nullable User is writable
 
        # Is this issue linked to a pull request?
-       var is_pull_request: Bool is noserialize, writable
+       var is_pull_request: Bool = false is writable
 end
 
 # A Github pull request.
@@ -749,6 +798,9 @@ class PullRequest
 
        # Changed files count.
        var changed_files: Int is writable
+
+       # URL to patch file
+       var patch_url: nullable String is writable
 end
 
 # A pull request reference (used for head and base).
@@ -767,8 +819,10 @@ class PullRef
        # User pointed by `self`.
        var user: User is writable
 
-       # Repo pointed by `self`.
-       var repo: Repo is writable
+       # Repo pointed by `self` (if any).
+       #
+       # A `null` value means the `repo` was deleted.
+       var repo: nullable Repo is writable
 end
 
 # A Github label.
@@ -797,31 +851,35 @@ class Milestone
        serialize
 
        # The milestone id on Github.
-       var number: Int is writable
+       var number: nullable Int = null is writable
 
        # Milestone title.
        var title: String is writable
 
        # Milestone long description.
-       var description: String is writable
+       var description: nullable String is writable
 
        # Count of opened issues linked to this milestone.
-       var open_issues: Int is writable
+       var open_issues: nullable Int = null is writable
 
        # Count of closed issues linked to this milestone.
-       var closed_issues: Int is writable
+       var closed_issues: nullable Int = null is writable
 
        # Milestone state.
-       var state: String is writable
+       var state: nullable String is writable
 
        # Creation time as String.
-       var created_at: String is writable
+       var created_at: nullable String is writable
 
        # Creation time as ISODate.
-       fun iso_created_at: nullable ISODate do return new ISODate.from_string(created_at)
+       fun iso_created_at: nullable ISODate do
+               var created_at = self.created_at
+               if created_at == null then return null
+               return new ISODate.from_string(created_at)
+       end
 
        # User that created this milestone.
-       var creator: User is writable
+       var creator: nullable User is writable
 
        # Due time as String (if any).
        var due_on: nullable String is writable
@@ -1057,10 +1115,7 @@ end
 
 # Make ISO Datew serilizable
 redef class ISODate
-       super Jsonable
        serialize
-
-       redef fun to_json do return serialize_to_json
 end
 
 # JsonDeserializer specific for Github objects.
@@ -1068,7 +1123,7 @@ class GithubDeserializer
        super JsonDeserializer
 
        redef fun class_name_heuristic(json_object) do
-               if json_object.has_key("login") or json_object.has_key("email") then
+               if json_object.has_key("login") then
                        return "User"
                else if json_object.has_key("full_name") then
                        return "Repo"
@@ -1076,8 +1131,12 @@ class GithubDeserializer
                        return "Branch"
                else if json_object.has_key("sha") and json_object.has_key("ref") then
                        return "PullRef"
-               else if json_object.has_key("sha") or (json_object.has_key("id") and json_object.has_key("tree_id")) then
+               else if (json_object.has_key("sha") and json_object.has_key("commit")) or (json_object.has_key("id") and json_object.has_key("tree_id")) then
                        return "Commit"
+               else if json_object.has_key("sha") and json_object.has_key("tree") then
+                       return "GitCommit"
+               else if json_object.has_key("name") and json_object.has_key("date") then
+                       return "GitUser"
                else if json_object.has_key("number") and json_object.has_key("patch_url") then
                        return "PullRequest"
                else if json_object.has_key("open_issues") and json_object.has_key("closed_issues") then
@@ -1097,4 +1156,20 @@ class GithubDeserializer
                end
                return null
        end
+
+       redef fun deserialize_class(name) do
+               if name == "Issue" then
+                       var issue = super.as(Issue)
+                       if path.last.has_key("pull_request") then
+                               issue.is_pull_request = true
+                       end
+                       return issue
+               else if name == "Commit" then
+                       var commit = super.as(Commit)
+                       var git_commit = commit.commit
+                       if git_commit != null then commit.message = git_commit.message
+                       return commit
+               end
+               return super
+       end
 end