Skip to content

Commit

Permalink
List pull request files endpoint (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
BenFradet authored and juanpedromoreno committed Apr 24, 2017
1 parent 6b2bcee commit c666ac7
Show file tree
Hide file tree
Showing 14 changed files with 250 additions and 23 deletions.
Expand Up @@ -31,7 +31,6 @@ class GHPullRequestsSpec extends AsyncFlatSpec with Matchers with TestUtils {
scala.concurrent.ExecutionContext.Implicits.global

"PullRequests >> List" should "return a right response when valid repo is provided" in {

val response =
Github(accessToken).pullRequests
.list(validRepoOwner, validRepoName)
Expand All @@ -43,7 +42,6 @@ class GHPullRequestsSpec extends AsyncFlatSpec with Matchers with TestUtils {
}

it should "return a non empty list when valid repo and some filters are provided" in {

val response =
Github(accessToken).pullRequests
.list(
Expand All @@ -67,4 +65,25 @@ class GHPullRequestsSpec extends AsyncFlatSpec with Matchers with TestUtils {
testFutureIsLeft(response)
}

"PullRequests >> ListFiles" should "return a right response when a valid repo is provided" in {
val response =
Github(accessToken).pullRequests
.listFiles(validRepoOwner, validRepoName, validPullRequestNumber)
.execFuture(headerUserAgent)

testFutureIsRight[List[PullRequestFile]](response, { r =>
r.result.nonEmpty shouldBe true
r.statusCode shouldBe okStatusCode
})
}

it should "return error when an invalid repo name is passed" in {
val response =
Github(accessToken).pullRequests
.listFiles(validRepoOwner, invalidRepoName, validPullRequestNumber)
.execFuture(headerUserAgent)

testFutureIsLeft(response)
}

}
2 changes: 2 additions & 0 deletions github4s/js/src/test/scala/github4s/utils/TestUtils.scala
Expand Up @@ -115,4 +115,6 @@ trait TestUtils extends Matchers {
val validCommitMsg = "Add SBT project settings"

val validStatusState = "success"

val validPullRequestNumber = 1
}
Expand Up @@ -29,27 +29,27 @@ import scalaj.http.HttpResponse

class GHPullRequestsSpec extends FlatSpec with Matchers with TestUtils {

"PullRequests >> List" should "return a right response when valid repo is provided" in {

"PullRequests >> List" should "return a right response when a valid repo is provided" in {
val response =
Github(accessToken).pullRequests
.list(validRepoOwner, validRepoName)
.exec[Id, HttpResponse[String]](headerUserAgent)

response should be('right)
response.toOption map { r
r.statusCode shouldBe okStatusCode
}
}

it should "return a non empty list when valid repo and some filters are provided" in {

it should "return a non empty list when a valid repo and some filters are provided" in {
val response =
Github(accessToken).pullRequests
.list(
validRepoOwner,
validRepoName,
List(PRFilterAll, PRFilterSortCreated, PRFilterOrderAsc, PRFilterBase("master")))
.exec[Id, HttpResponse[String]](headerUserAgent)

response should be('right)
response.toOption map { r
r.result.nonEmpty shouldBe true
Expand All @@ -62,6 +62,29 @@ class GHPullRequestsSpec extends FlatSpec with Matchers with TestUtils {
Github(accessToken).pullRequests
.list(validRepoOwner, invalidRepoName)
.exec[Id, HttpResponse[String]](headerUserAgent)

response should be('left)
}

"PullRequests >> ListFiles" should "return a right response when a valid repo is provided" in {
val response =
Github(accessToken).pullRequests
.listFiles(validRepoOwner, validRepoName, validPullRequestNumber)
.exec[Id, HttpResponse[String]](headerUserAgent)

response should be('right)
response.toOption map { r
r.result.nonEmpty shouldBe true
r.statusCode shouldBe okStatusCode
}
}

it should "return error when an invalid repo name is passed" in {
val response =
Github(accessToken).pullRequests
.listFiles(validRepoOwner, invalidRepoName, validPullRequestNumber)
.exec[Id, HttpResponse[String]](headerUserAgent)

response should be('left)
}

Expand Down
25 changes: 25 additions & 0 deletions github4s/jvm/src/test/scala/github4s/unit/ApiSpec.scala
Expand Up @@ -588,6 +588,31 @@ class ApiSpec
response should be('left)
}

"PullRequests >> ListFiles" should "return the expected files when a valid repo is provided" in {
val response = pullRequests.listFiles(
accessToken,
headerUserAgent,
validRepoOwner,
validRepoName,
validPullRequestNumber)
response should be('right)

response.toOption map { r
r.result.nonEmpty shouldBe true
r.statusCode shouldBe okStatusCode
}
}

it should "return an error when an invalid repo name is passed" in {
val response = pullRequests.listFiles(
accessToken,
headerUserAgent,
validRepoOwner,
invalidRepoName,
validPullRequestNumber)
response should be('left)
}

"Statuses >> Get" should "return the expected combined status when a valid ref is provided" in {
val response =
statuses.get(accessToken, headerUserAgent, validRepoOwner, validRepoName, validRefSingle)
Expand Down
19 changes: 19 additions & 0 deletions github4s/jvm/src/test/scala/github4s/unit/GHPullRequestsSpec.scala
Expand Up @@ -48,4 +48,23 @@ class GHPullRequestsSpec extends FlatSpec with Matchers with TestUtils {
verify(pullRequestOps).listPullRequests(validRepoOwner, validRepoName, Nil, token)
}

"GHPullRequests.listFiles" should "call to PullRequestOps with the right parameters" in {

val response: Free[GitHub4s, GHResponse[List[PullRequestFile]]] =
Free.pure(Right(GHResult(List(pullRequestFile), okStatusCode, Map.empty)))

val pullRequestOps = mock[PullRequestOps[GitHub4s]]
when(
pullRequestOps
.listPullRequestFiles(any[String], any[String], any[Int], any[Option[String]]))
.thenReturn(response)

val token = Some("token")
val ghPullRequests = new GHPullRequests(token)(pullRequestOps)
ghPullRequests.listFiles(validRepoOwner, validRepoName, validPullRequestNumber)

verify(pullRequestOps)
.listPullRequestFiles(validRepoOwner, validRepoName, validPullRequestNumber, token)
}

}
31 changes: 31 additions & 0 deletions github4s/jvm/src/test/scala/github4s/unit/PullRequestsSpec.scala
Expand Up @@ -68,4 +68,35 @@ class PullRequestsSpec
)(any[Decoder[List[PullRequest]]])
}

"PullRequests.listFiles" should "call to httpClient.get with the right parameters" in {

val response: GHResponse[List[PullRequestFile]] =
Right(GHResult(List(pullRequestFile), okStatusCode, Map.empty))

val httpClientMock = mock[HttpClient[HttpResponse[String], Id]]
when(
httpClientMock.get[List[PullRequestFile]](
any[Option[String]],
any[String],
any[Map[String, String]],
any[Map[String, String]],
any[Option[Pagination]])(any[Decoder[List[PullRequestFile]]]))
.thenReturn(response)

val token = Some("token")
val pullRequests = new PullRequests[HttpResponse[String], Id] {
override val httpClient: HttpClient[HttpResponse[String], Id] = httpClientMock
}
pullRequests
.listFiles(token, headerUserAgent, validRepoOwner, validRepoName, validPullRequestNumber)

verify(httpClientMock).get[List[PullRequestFile]](
argEq(token),
argEq(s"repos/$validRepoOwner/$validRepoName/pulls/$validPullRequestNumber/files"),
argEq(headerUserAgent),
any[Map[String, String]],
any[Option[Pagination]]
)(any[Decoder[List[PullRequestFile]]])
}

}
18 changes: 18 additions & 0 deletions github4s/jvm/src/test/scala/github4s/utils/FakeResponses.scala
Expand Up @@ -1136,6 +1136,24 @@ trait FakeResponses {
|]
""".stripMargin

val validListPullRequestFilesReponse =
"""
|[
| {
| "sha": "8a8c9c2d17075d3ea643505d1d0e906b6fd7cde3",
| "filename": "README.md",
| "status": "modified",
| "additions": 2,
| "deletions": 1,
| "changes": 3,
| "blob_url": "https://github.com/47deg/github4s/blob/765089ac90b2cb935a45d9ce214d3340e503663c/README.md",
| "raw_url": "https://github.com/47deg/github4s/raw/765089ac90b2cb935a45d9ce214d3340e503663c/README.md",
| "contents_url": "https://api.github.com/repos/47deg/github4s/contents/README.md?ref=765089ac90b2cb935a45d9ce214d3340e503663c",
| "patch": "@@ -1,10 +1,11 @@\n+[![Build Status](https://travis-ci.org/47deg/github4s.svg?branch=master)](https://travis-ci.org/47deg/github4s)\n+\n Github4s\n =============\n \n **Github4s** is a GitHub API wrapper written in Scala.\n \n \n-\n # License\n \n The MIT License (MIT)"
| }
|]
""".stripMargin

val validNewReleaseResponse =
"""
|{
Expand Down
Expand Up @@ -224,6 +224,29 @@ trait MockGithubApiServer extends MockServerService with FakeResponses with Test
.withPath(s"/repos/$validRepoOwner/$invalidRepoName/contributors"))
.respond(response.withStatusCode(notFoundStatusCode).withBody(notFoundResponse))

//Repos >> create release
mockServer
.when(
request
.withMethod("POST")
.withPath(s"/repos/$validRepoOwner/$validRepoName/releases")
.withHeader("Authorization", tokenHeader))
.respond(
response
.withStatusCode(createdStatusCode)
.withBody(validNewReleaseResponse))

mockServer
.when(
request
.withMethod("POST")
.withPath(s"/repos/$validRepoOwner/$validRepoName/releases")
.withHeader(not("Authorization")))
.respond(
response
.withStatusCode(unauthorizedStatusCode)
.withBody(unauthorizedResponse))

//Gists >> post new gist

mockServer
Expand Down Expand Up @@ -425,27 +448,20 @@ trait MockGithubApiServer extends MockServerService with FakeResponses with Test
.withPath(s"/repos/$validRepoOwner/$invalidRepoName/pulls"))
.respond(response.withStatusCode(notFoundStatusCode).withBody(notFoundResponse))

//PullRequests >> listFiles
mockServer
.when(
request
.withMethod("POST")
.withPath(s"/repos/$validRepoOwner/$validRepoName/releases")
.withHeader("Authorization", tokenHeader))
.respond(
response
.withStatusCode(createdStatusCode)
.withBody(validNewReleaseResponse))
.withMethod("GET")
.withPath(s"/repos/$validRepoOwner/$validRepoName/pulls/$validPullRequestNumber/files"))
.respond(response.withStatusCode(okStatusCode).withBody(validListPullRequestFilesReponse))

mockServer
.when(
request
.withMethod("POST")
.withPath(s"/repos/$validRepoOwner/$validRepoName/releases")
.withHeader(not("Authorization")))
.respond(
response
.withStatusCode(unauthorizedStatusCode)
.withBody(unauthorizedResponse))
.withMethod("GET")
.withPath(s"/repos/$validRepoOwner/$invalidRepoName/pulls/$validPullRequestNumber/files"))
.respond(response.withStatusCode(notFoundStatusCode).withBody(notFoundResponse))

//Statuses >> get
mockServer
Expand Down
19 changes: 18 additions & 1 deletion github4s/jvm/src/test/scala/github4s/utils/TestUtils.scala
Expand Up @@ -108,6 +108,9 @@ trait TestUtils {
val validTagTitle = "v0.1.1"
val validTagSha = "c3d0be41ecbe669545ee3e94d31ed9a4bc91ee3c"

val validPullRequestFileSha = "f80f79cafbe3f2ba71311b82e1171e73bd37a470"
val validPullRequestNumber = 1

val validPath = "project/plugins.sbt"

val validStatusState = "success"
Expand Down Expand Up @@ -139,7 +142,7 @@ trait TestUtils {

val pullRequest = PullRequest(
id = 1,
number = 1,
number = validPullRequestNumber,
state = "open",
title = "Title",
body = "Body",
Expand All @@ -155,6 +158,20 @@ trait TestUtils {
assignee = None
)

val pullRequestFile = PullRequestFile(
sha = validPullRequestFileSha,
filename = validPath,
status = "modified",
additions = 3,
deletions = 1,
changes = 4,
blob_url = githubApiUrl,
raw_url = githubApiUrl,
contents_url = githubApiUrl,
patch = "",
previous_filename = None
)

val tag = Tag(
tag = validTagTitle,
sha = validTagSha,
Expand Down
7 changes: 7 additions & 0 deletions github4s/shared/src/main/scala/github4s/GithubAPIs.scala
Expand Up @@ -242,6 +242,13 @@ class GHPullRequests(accessToken: Option[String] = None)(implicit O: PullRequest
filters: List[PRFilter] = Nil
): GHIO[GHResponse[List[PullRequest]]] =
O.listPullRequests(owner, repo, filters, accessToken)

def listFiles(
owner: String,
repo: String,
number: Int
): GHIO[GHResponse[List[PullRequestFile]]] =
O.listPullRequestFiles(owner, repo, number, accessToken)
}

class GHStatuses(accessToken: Option[String] = None)(implicit O: StatusOps[GitHub4s]) {
Expand Down
20 changes: 20 additions & 0 deletions github4s/shared/src/main/scala/github4s/api/PullRequests.scala
Expand Up @@ -64,4 +64,24 @@ class PullRequests[C, M[_]](
headers,
filters.map(_.tupled).toMap)

/**
* List files for a specific pull request
*
* @param accessToken to identify the authenticated user
* @param headers optional user headers to include in the request
* @param owner of the repo
* @param repo name of the repo
* @param number of the pull request for which we want to list the files
* @return a GHResponse with the list of files affected by the pull request identified by number.
*/
def listFiles(
accessToken: Option[String] = None,
headers: Map[String, String] = Map(),
owner: String,
repo: String,
number: Int): M[GHResponse[List[PullRequestFile]]] =
httpClient.get[List[PullRequestFile]](
accessToken,
s"repos/$owner/$repo/pulls/$number/files",
headers)
}

0 comments on commit c666ac7

Please sign in to comment.