Skip to content

Commit

Permalink
add get tree api implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Rey Abe committed Aug 20, 2018
1 parent 7ea9e34 commit 57e9aa2
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 2 deletions.
23 changes: 23 additions & 0 deletions docs/src/main/tut/git_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ with Github4s, you can:
- [Get a Commit](#get-a-commit)
- [Create a Commit](#create-a-commit)
- [Create a Blob](#create-a-blob)
- [Get a Tree](#get-a-tree)
- [Create a Tree](#create-a-tree)
- [Create a Tag](#create-a-tag)

Expand Down Expand Up @@ -208,6 +209,28 @@ are just tools to navigate this tree and to manipulate it.

In the following sections, we'll see how Github4s provides methods to wrap the Git API.


### Get a Tree

You can get a tree using `getTree`; it takes as arguments:

- the repository coordinates (`owner` and `name` of the repository).
- `sha`: the sha of the commit.
- `recursive`: flag whether to get the tree recursively.

```tut:silent
val getCommit = Github(accessToken).gitData.getTree("47deg", "github4s", "d3b048c1f500ee5450e5d7b3d1921ed3e7645891",true)
getCommit.exec[cats.Id, HttpResponse[String]]() match {
case Left(e) => println(s"Something went wrong: ${e.getMessage}")
case Right(r) => println(r.result)
}
```

The `result` on the right is the corresponding [TreeResult][gitdata-scala].

See [the API doc](https://developer.github.com/v3/git/trees/#get-a-tree) for full reference.

### Create a Tree

The tree creation API will take nested entries as well. If both a tree and a nested entries modifying
Expand Down
8 changes: 8 additions & 0 deletions github4s/shared/src/main/scala/github4s/GithubAPIs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,14 @@ class GHGitData(accessToken: Option[String] = None)(implicit O: GitDataOps[GitHu
): GHIO[GHResponse[RefInfo]] =
O.createBlob(owner, repo, content, encoding, accessToken)

def getTree(
owner: String,
repo: String,
sha: String,
recursive: Boolean
): GHIO[GHResponse[TreeResult]] =
O.getTree(owner, repo, sha, recursive, accessToken)

def createTree(
owner: String,
repo: String,
Expand Down
24 changes: 24 additions & 0 deletions github4s/shared/src/main/scala/github4s/api/GitData.scala
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,30 @@ class GitData[C, M[_]](
headers,
dropNullPrint(NewBlobRequest(content, encoding).asJson))

/**
* Get a Tree by sha
*
* @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 sha the sha of the tree
* @param recursive flag whether to get the tree recursively
* @return a GHResponse with the Tree
*/
def tree(
accessToken: Option[String] = None,
headers: Map[String, String] = Map(),
owner: String,
repo: String,
sha: String,
recursive: Boolean = false): M[GHResponse[TreeResult]] =
httpClient.get[TreeResult](
accessToken,
s"repos/$owner/$repo/git/trees/$sha",
headers,
(if (recursive) Map("recursive"->"1") else Map.empty))

/**
* Create a new Tree
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ final case class CreateBlob(
accessToken: Option[String] = None
) extends GitDataOp[GHResponse[RefInfo]]

final case class GetTree(
owner: String,
repo: String,
sha: String,
recursive: Boolean,
accessToken: Option[String] = None
) extends GitDataOp[GHResponse[TreeResult]]

final case class CreateTree(
owner: String,
repo: String,
Expand Down Expand Up @@ -156,6 +164,15 @@ class GitDataOps[F[_]](implicit I: InjectK[GitDataOp, F]) {
): Free[F, GHResponse[RefInfo]] =
Free.inject[GitDataOp, F](CreateBlob(owner, repo, content, encoding, accessToken))

def getTree(
owner: String,
repo: String,
sha: String,
recursive: Boolean,
accessToken: Option[String] = None
): Free[F, GHResponse[TreeResult]] =
Free.inject[GitDataOp, F](GetTree(owner, repo, sha, recursive, accessToken))

def createTree(
owner: String,
repo: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ case class TreeDataBlob(path: String, mode: String, `type`: String, content: Str
case class TreeResult(
override val sha: String,
override val url: String,
tree: List[TreeDataResult])
tree: List[TreeDataResult],
truncated: Option[Boolean] = None)
extends RefInfo(sha, url)

case class TreeDataResult(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ class Interpreters[M[_], C](
gitData.createBlob(accessToken, headers, owner, repo, content, encoding)
case CreateTree(owner, repo, baseTree, treeDataList, accessToken)
gitData.createTree(accessToken, headers, owner, repo, baseTree, treeDataList)
case GetTree(owner, repo, sha, recursive, accessToken)
gitData.tree(accessToken, headers, owner, repo, sha, recursive)
case CreateTag(owner, repo, tag, message, objectSha, objectType, author, accessToken)
gitData.createTag(
accessToken,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package github4s.integration
import cats.data.NonEmptyList
import github4s.Github
import github4s.Github._
import github4s.free.domain.{Ref, RefCommit}
import github4s.free.domain.{Ref, RefCommit, TreeResult}
import github4s.implicits._
import github4s.utils.BaseIntegrationSpec

Expand Down Expand Up @@ -73,4 +73,38 @@ trait GHGitDataSpec[T] extends BaseIntegrationSpec[T] {

testFutureIsLeft(response)
}

"GitData >> GetTree" should "return the file tree non-recursively" in {
val response =
Github(accessToken).gitData
.getTree(validRepoOwner, validRepoName, validCommitSha, recursive=false)
.execFuture[T](headerUserAgent)

testFutureIsRight[TreeResult](response, { r =>
r.statusCode shouldBe okStatusCode
r.result.tree.map(_.path) shouldBe List(".gitignore","build.sbt","project")
r.result.truncated shouldBe Some(false)
})
}

it should "return the file tree recursively" in {
val response =
Github(accessToken).gitData
.getTree(validRepoOwner, validRepoName, validCommitSha, recursive=true)
.execFuture[T](headerUserAgent)

testFutureIsRight[TreeResult](response, { r =>
r.statusCode shouldBe okStatusCode
r.result.tree.map(_.path) shouldBe List(".gitignore", "build.sbt", "project", "project/build.properties", "project/plugins.sbt")
})
}

it should "return an error when an invalid repository name is passed" in {
val response = Github(accessToken).gitData
.getTree(validRepoOwner, invalidRepoName, validCommitSha, recursive=false)
.execFuture[T](headerUserAgent)

testFutureIsLeft(response)
}

}
19 changes: 19 additions & 0 deletions github4s/shared/src/test/scala/github4s/unit/GHGitDataSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,25 @@ class GHGitDataSpec extends BaseSpec {
ghGitData.createBlob(validRepoOwner, validRepoName, validNote, encoding)
}

"GHGitData.getTree" should "call to GitDataOps with the right parameters" in {

val response: Free[GitHub4s, GHResponse[TreeResult]] =
Free.pure(
Right(
GHResult(
TreeResult(validCommitSha, githubApiUrl, treeDataResult, truncated=Some(false)),
okStatusCode,
Map.empty)))

val gitDataOps = mock[GitDataOpsTest]
(gitDataOps.getTree _)
.expects(validRepoOwner, validRepoName, validCommitSha, false, sampleToken)
.returns(response)

val ghGitData = new GHGitData(sampleToken)(gitDataOps)
ghGitData.getTree(validRepoOwner, validRepoName, validCommitSha, recursive=false)
}

"GHGitData.createTree" should "call to GitDataOps with the right parameters" in {

val response: Free[GitHub4s, GHResponse[TreeResult]] =
Expand Down
19 changes: 19 additions & 0 deletions github4s/shared/src/test/scala/github4s/unit/GitDataSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,25 @@ class GitDataSpec extends BaseSpec {
encoding)
}

"GitData.getTree" should "call to httpClient.get with the right parameters" in {

val response: GHResponse[TreeResult] =
Right(
GHResult(
TreeResult(validCommitSha, githubApiUrl, treeDataResult, truncated=Some(false)),
okStatusCode,
Map.empty))
val httpClientMock = httpClientMockGet[TreeResult](
url = s"repos/$validRepoOwner/$validRepoName/git/trees/$validCommitSha",
response = response
)
val gitData = new GitData[String, Id] {
override val httpClient: HttpClient[String, Id] = httpClientMock
}

gitData.tree(sampleToken, headerUserAgent, validRepoOwner, validRepoName, validCommitSha, recursive=false)
}

"GitData.createTree" should "call to httpClient.post with the right parameters" in {

val response: GHResponse[TreeResult] =
Expand Down

0 comments on commit 57e9aa2

Please sign in to comment.