Skip to content

Commit 7839654

Browse files
committed
Merge branch 'master' of https://github.com/code-check/github-api-scala into 12-SearchApi
2 parents 94d3254 + 8c7075a commit 7839654

File tree

11 files changed

+191
-24
lines changed

11 files changed

+191
-24
lines changed

data/milestones.json

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,47 @@
11
[
22
{
3-
"title": "Sprint1",
4-
"description": "From 2015/04/13 to 2015/04/26",
5-
"due_on": "2015-04-26"
3+
"title": "Sprint4",
4+
"description": "2015/05/25 to 2015/06/07",
5+
"due_on": "2015-06-07"
66
},
77
{
8-
"title": "Sprint2",
9-
"description": "2015/04/27 to 2015/05/10",
10-
"due_on": "2015-05-10"
8+
"title": "Sprint5",
9+
"description": "2015/06/08 to 2015/06/21",
10+
"due_on": "2015-06-21"
1111
},
1212
{
13-
"title": "Sprint3",
14-
"description": "From 2015/05/11 to 2015/05/24",
15-
"due_on": "2015-05-24"
13+
"title": "Sprint6",
14+
"description": "2015/06/22 to 2015/07/05",
15+
"due_on": "2015-07-05"
1616
},
1717
{
18-
"title": "Sprint4",
19-
"description": "2015/05/25 to 2015/06/07",
20-
"due_on": "2015-06-07"
18+
"title": "Sprint7",
19+
"description": "2015/07/06 to 2015/07/19",
20+
"due_on": "2015-07-19"
21+
},
22+
{
23+
"title": "Sprint8",
24+
"description": "2015/07/20 to 2015/08/02",
25+
"due_on": "2015-08-02"
26+
},
27+
{
28+
"title": "Sprint9",
29+
"description": "2015/08/03 to 2015/08/16",
30+
"due_on": "2015-08-16"
31+
},
32+
{
33+
"title": "Sprint10",
34+
"description": "2015/08/17 to 2015/08/30",
35+
"due_on": "2015-08-30"
36+
},
37+
{
38+
"title": "Sprint11",
39+
"description": "2015/08/31 to 2015/09/13",
40+
"due_on": "2015-09-13"
41+
},
42+
{
43+
"title": "Sprint12",
44+
"description": "2015/09/14 to 2015/09/27",
45+
"due_on": "2015-09-27"
2146
}
2247
]

src/main/scala/codecheck/github/api/GitHubAPI.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ class GitHubAPI(token: String, client: AsyncHttpClient, tokenType: String = "tok
5353
request
5454
.setHeader("Authorization", s"$tokenType $token")
5555
.setHeader("Content-Type", "application/json")
56+
if (method == "PUT" && body == JNothing){
57+
request
58+
.setHeader("Content-Length", "0")
59+
}
5660
request.execute(new AsyncCompletionHandler[Response]() {
5761
def onCompleted(res: Response) = {
5862
val json = Option(res.getResponseBody).filter(_.length > 0).map(parseJson(_)).getOrElse(JNothing)

src/main/scala/codecheck/github/api/OAuthAPI.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import org.json4s.jackson.JsonMethods
1111
import org.json4s.DefaultFormats
1212
import java.util.UUID
1313
import codecheck.github.models.AccessToken
14+
import codecheck.github.exceptions.OAuthAPIException
1415

1516
class OAuthAPI(clientId: String, clientSecret: String, redirectUri: String, client: AsyncHttpClient) {
1617
private implicit val format = DefaultFormats
@@ -48,7 +49,10 @@ class OAuthAPI(clientId: String, clientSecret: String, redirectUri: String, clie
4849
client.prepareRequest(builder.build).execute(new AsyncCompletionHandler[Response]() {
4950
def onCompleted(res: Response) = {
5051
val json = JsonMethods.parse(res.getResponseBody("utf-8"))
51-
deferred.success(AccessToken(json))
52+
(json \ "error").toOption match {
53+
case Some(_) => deferred.failure(new OAuthAPIException(json))
54+
case None => deferred.success(AccessToken(json))
55+
}
5256
res
5357
}
5458
override def onThrowable(t: Throwable) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package codecheck.github.exceptions
2+
3+
import org.json4s.JValue
4+
import codecheck.github.models.OAuthErrorResponse
5+
6+
class OAuthAPIException(body: JValue) extends Exception {
7+
lazy val error = OAuthErrorResponse(body)
8+
9+
override def getMessage = error.toString
10+
11+
}

src/main/scala/codecheck/github/models/Collaborator.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ case class Collaborator(value: JValue) extends AbstractJson(value) {
88
def url = get("url")
99
def site_admin: Boolean = boolean("site_admin")
1010
}
11-
//case class CollaboratorInput extends AbstractInput
11+
//case class CollaboratorInput extends AbstractInput
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package codecheck.github.models
2+
3+
import org.json4s.JValue
4+
5+
case class OAuthErrorResponse(value: JValue) extends AbstractJson(value) {
6+
def error = get("error")
7+
def error_description = get("error_description")
8+
def error_uri = get("error_uri")
9+
}
10+

src/main/scala/codecheck/github/operations/CollaboratorOp.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,28 @@ trait CollaboratorOp {
2020
}
2121
)
2222
}
23+
24+
def isCollaborator(owner: String, repo: String, name: String): Future[Boolean] = {
25+
val path = s"/repos/${owner}/${repo}/collaborators/" + encode(name)
26+
exec("GET", path, fail404 = false).map { res =>
27+
res.statusCode match {
28+
case 404 => false
29+
case 204 => true
30+
}
31+
}
32+
}
33+
34+
def addCollaborator(owner: String, repo: String, name: String): Future[Boolean] = {
35+
val path = s"/repos/${owner}/${repo}/collaborators/" + encode(name)
36+
exec("PUT", path).map {
37+
_.statusCode == 204
38+
}
39+
}
40+
41+
def removeCollaborator(owner: String, repo: String, name: String): Future[Boolean] = {
42+
val path = s"/repos/${owner}/${repo}/collaborators/" + encode(name)
43+
exec("DELETE", path).map {
44+
_.statusCode == 204
45+
}
46+
}
2347
}

src/test/scala/CollaboratorOpSpec.scala

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import org.scalatest.path.FunSpec
2-
import codecheck.github.models.Collaborator
32
import scala.concurrent.Await
3+
import codecheck.github.models.Collaborator
4+
import codecheck.github.exceptions.GitHubAPIException
5+
import codecheck.github.exceptions.NotFoundException
46

57
class CollaboratorOpSpec extends FunSpec with Constants {
68

@@ -16,4 +18,44 @@ class CollaboratorOpSpec extends FunSpec with Constants {
1618
assert(c.site_admin == false)
1719
}
1820
}
21+
describe("isCollaborator"){
22+
it("if it is Collaborator"){
23+
val res = Await.result(api.addCollaborator(user, userRepo, collaboratorUser),TIMEOUT)
24+
assert(res)
25+
val res1 = Await.result(api.isCollaborator(user, userRepo, collaboratorUser),TIMEOUT)
26+
assert(res1 == true)
27+
var res2 = Await.result(api.removeCollaborator(user, userRepo, collaboratorUser),TIMEOUT)
28+
assert(res2)
29+
}
30+
it("if it is not a valid Collaborator"){
31+
val res1 = Await.result(api.isCollaborator(organization, repo, otherUserInvalid),TIMEOUT)
32+
assert(res1 == false)
33+
}
34+
}
35+
describe("addCollaborator"){
36+
it("should add Collaborator User to user Repo"){
37+
val res = Await.result(api.addCollaborator(user, userRepo, collaboratorUser),TIMEOUT)
38+
assert(res)
39+
}
40+
it("should fail for non existent User Repo"){
41+
val res = Await.result(api.addCollaborator(user, repoInvalid, collaboratorUser).failed,TIMEOUT)
42+
res match {
43+
case e: NotFoundException =>
44+
case _ => fail
45+
}
46+
}
47+
}
48+
describe("removeCollaborator"){
49+
it("should remove the Collaborator"){
50+
var res = Await.result(api.removeCollaborator(user, userRepo, collaboratorUser),TIMEOUT)
51+
assert(res)
52+
}
53+
}
54+
it("should fail for non existent User Repo"){
55+
var res = Await.result(api.removeCollaborator(user, repoInvalid, collaboratorUser).failed,TIMEOUT)
56+
res match {
57+
case e: NotFoundException =>
58+
case _ => fail
59+
}
60+
}
1961
}

src/test/scala/Constants.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ trait Constants {
1212
protected val TIMEOUT = 5 seconds
1313
protected val api = Constants.API
1414

15-
protected val user = "fanwashere" //REQUIRED: Edit this to your own username.
16-
1715
//Request membership of dummy organization "celestialbeing" if you are not member. Do not edit.
1816
protected val organization = "celestialbeings"
1917
protected val repo = "test-repo"
@@ -27,13 +25,18 @@ trait Constants {
2725
println(v)
2826
}
2927
}
30-
protected val otherUser = "shunjikonishi"
28+
29+
protected val user = sys.env("GITHUB_USER")
30+
protected val userRepo = sys.env("GITHUB_REPO")
31+
32+
protected val otherUser = "shunjikonishi"
33+
protected val collaboratorUser = "givery-dev"
3134
protected val otherUserInvalid = "loremipsom123"
3235
protected val organizationInvalid = "loremipsom123"
3336
protected val repoInvalid = "loremipsom123"
3437

3538
val wordBank = Array("Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Theta", "Lambda", "Pi", "Sigma")
36-
def generateRandomString: String =
39+
def generateRandomString: String =
3740
wordBank(nextInt(10)) + " " + wordBank(nextInt(10)) + " " + wordBank(nextInt(10))
3841
def generateRandomWord: String = wordBank(nextInt(10))
3942
def generateRandomInt: Int = nextInt(1000)
@@ -44,4 +47,4 @@ object Constants {
4447
implicit val client = new AsyncHttpClient()
4548

4649
val API = GitHubAPI(token)
47-
}
50+
}

src/test/scala/README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
This readme documents the changes to the tests.
33

44
## Initial Setup
5-
1. Change variable user in Constants.scala to your own Github username.
5+
1. Please export username and repository that exists under your name.
66
2. If you have no yet exported your Github token, create one [here](https://github.com/settings/tokens) and export it.
77

88
``` bash
9-
export GITHUB_TOKEN=[Your GitHub Token]
9+
export GITHUB_TOKEN=[Your GitHub Token]
10+
export GITHUB_USER=[Your User Name]
11+
export GITHUB_REPO=[Your Repo name that exists]
1012
```
1113

1214
## Optional settings
13-
- showResponse
15+
- showResponse
1416
-- Set this to true if you would like to see the response JSON data. Otherwise it is omitted when running tests.
1517

1618
The following variables are for futureproofing. Generally won't need to be modified.
@@ -37,4 +39,4 @@ The random string generator is located in Constants.scala and uses words from th
3739
-- Returns a String with a single random word.
3840
- generatedRandomInt()
3941
-- Returns a random Int from 0 to 999. This was added to avoid having to import the Random class in every file (so it is bundled with Constants)
40-
Use these to generate random field values to test create and update functions.
42+
Use these to generate random field values to test create and update functions.

0 commit comments

Comments
 (0)