Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List user repositories api #224

Merged
merged 1 commit into from
Oct 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/src/main/tut/repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ with Github4s, you can interact with:
- [Repositories](#repositories)
- [Get a repository](#get-a-repository)
- [List organization repositories](#list-organization-repositories)
- [List user repositories](#list-user-repositories)
- [List contributors](#list-contributors)
- [List collaborators](#list-collaborators)
- [Commits](#commits)
Expand Down Expand Up @@ -94,6 +95,31 @@ The `result` on the right is the corresponding [List[Repository]][repository-sca
See [the API doc](https://developer.github.com/v3/repos/#list-organization-repositories) for full
reference.

### List user repositories

You can retrieve the list of repositories for a particular user using `listUserRepos`; it
takes as arguments:

- `user`: The user name.
- `type`: The optional type of the returned repositories, can be "all", "owner" or "member", defaults to "owner".
- `pagination`: Limit and Offset for pagination.

To list the repositories for a user:

```tut:silent
val listUserRepos = Github(accessToken).repos.listUserRepos("rafaparadela")

listUserRepos.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 [List[Repository]][repository-scala].

See [the API doc](https://developer.github.com/v3/repos/#list-user-repositories) for full
reference.

### List contributors

List contributors to the specified repository,
Expand Down
34 changes: 34 additions & 0 deletions github4s/jvm/src/test/scala/github4s/unit/ApiSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,40 @@ class ApiSpec
response should be('left)
}

"Repos >> ListUserRepos" should "return the expected repos when a valid user is provided" in {
val response = repos.listUserRepos(
accessToken,
headerUserAgent,
validUsername,
None,
Option(Pagination(validPage, validPerPage)))
response should be('right)

response.toOption map { r ⇒
r.result.nonEmpty shouldBe true
r.statusCode shouldBe okStatusCode
}
}
it should "return an empty list of repos for invalid page parameter" in {
val response = repos.listUserRepos(
accessToken,
headerUserAgent,
validUsername,
None,
Option(Pagination(invalidPage, validPerPage)))
response should be('right)

response.toOption map { r ⇒
r.result.isEmpty shouldBe true
r.statusCode shouldBe okStatusCode
}
}
it should "return error when an invalid user is passed" in {
val response =
repos.listUserRepos(accessToken, headerUserAgent, invalidUsername)
response should be('left)
}

"Repos >> GetContents" should "return the expected contents when valid repo and a valid file path is provided" in {
val response =
repos.getContents(accessToken, headerUserAgent, validRepoOwner, validRepoName, validFilePath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,30 @@ trait MockGithubApiServer extends MockServerService with FakeResponses with Test
.withPath(s"/orgs/$validRepoOwner/repos"))
.respond(response.withStatusCode(notFoundStatusCode).withBody(notFoundResponse))

//Repos >> list user repos
mockServer
.when(
request
.withMethod("GET")
.withPath(s"/users/$validUsername/repos")
.withQueryStringParameter("page", validPage.toString))
.respond(response.withStatusCode(okStatusCode).withBody(listOrgReposValidResponse))

mockServer
.when(
request
.withMethod("GET")
.withPath(s"/users/$validUsername/repos")
.withQueryStringParameter("page", invalidPage.toString))
.respond(response.withStatusCode(okStatusCode).withBody(emptyListResponse))

mockServer
.when(
request
.withMethod("GET")
.withPath(s"/users/$validUsername/repos"))
.respond(response.withStatusCode(notFoundStatusCode).withBody(notFoundResponse))

//Repos >> get contents
mockServer
.when(
Expand Down
7 changes: 7 additions & 0 deletions github4s/shared/src/main/scala/github4s/GithubAPIs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ class GHRepos(accessToken: Option[String] = None)(implicit O: RepositoryOps[GitH
): GHIO[GHResponse[List[Repository]]] =
O.listOrgRepos(org, `type`, pagination, accessToken)

def listUserRepos(
user: String,
`type`: Option[String] = None,
pagination: Option[Pagination] = None
): GHIO[GHResponse[List[Repository]]] =
O.listUserRepos(user, `type`, pagination, accessToken)

def getContents(
owner: String,
repo: String,
Expand Down
25 changes: 25 additions & 0 deletions github4s/shared/src/main/scala/github4s/api/Repos.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,31 @@ class Repos[C, M[_]](
pagination = pagination
)

/**
* List the repositories for a particular user
*
* @param accessToken to identify the authenticated user
* @param headers optional user headers to include in the request
* @param user user for which we wish to retrieve the repositories
* @param `type` visibility of the retrieved repositories, can be "all", "public", "private",
* "forks", "sources" or "member"
* @return GHResponse[List[Repository]] the list of repositories for this user
*/
def listUserRepos(
accessToken: Option[String] = None,
headers: Map[String, String] = Map(),
user: String,
`type`: Option[String] = None,
pagination: Option[Pagination] = Some(httpClient.defaultPagination)
): M[GHResponse[List[Repository]]] =
httpClient.get[List[Repository]](
accessToken,
s"users/$user/repos",
headers,
params = `type`.map(t => Map("type" -> t)).getOrElse(Map.empty),
pagination = pagination
)

/**
* Get the contents of a file or directory in a repository.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ final case class ListOrgRepos(
accessToken: Option[String] = None
) extends RepositoryOp[GHResponse[List[Repository]]]

final case class ListUserRepos(
user: String,
`type`: Option[String] = None,
pagination: Option[Pagination] = None,
accessToken: Option[String] = None
) extends RepositoryOp[GHResponse[List[Repository]]]

final case class GetContents(
owner: String,
repo: String,
Expand Down Expand Up @@ -132,6 +139,14 @@ class RepositoryOps[F[_]](implicit I: InjectK[RepositoryOp, F]) {
): Free[F, GHResponse[List[Repository]]] =
Free.inject[RepositoryOp, F](ListOrgRepos(org, `type`, pagination, accessToken))

def listUserRepos(
user: String,
`type`: Option[String] = None,
pagination: Option[Pagination] = None,
accessToken: Option[String] = None
): Free[F, GHResponse[List[Repository]]] =
Free.inject[RepositoryOp, F](ListUserRepos(user, `type`, pagination, accessToken))

def getContents(
owner: String,
repo: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class Interpreters[M[_], C](
case GetRepo(owner, repo, accessToken) ⇒ repos.get(accessToken, headers, owner, repo)
case ListOrgRepos(org, tipe, pagination, accessToken) ⇒
repos.listOrgRepos(accessToken, headers, org, tipe, pagination)
case ListUserRepos(user, tipe, pagination, accessToken) ⇒
repos.listUserRepos(accessToken, headers, user, tipe, pagination)
case GetContents(owner, repo, path, ref, accessToken) ⇒
repos.getContents(accessToken, headers, owner, repo, path, ref)
case ListCommits(owner, repo, sha, path, author, since, until, pagination, accessToken) ⇒
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ trait GHReposSpec[T] extends BaseIntegrationSpec[T] {
testFutureIsLeft(response)
}

"Repos >> ListUserRepos" should "return the expected repos when a valid user is provided" in {
val response = Github(accessToken).repos
.listUserRepos(validUsername)
.execFuture[T](headerUserAgent)

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

it should "return error when an invalid user is passed" in {
val response = Github(accessToken).repos
.listUserRepos(invalidUsername)
.execFuture[T](headerUserAgent)

testFutureIsLeft(response)
}

"Repos >> GetContents" should "return the expected contents when valid path is provided" in {
val response =
Github(accessToken).repos
Expand Down
14 changes: 14 additions & 0 deletions github4s/shared/src/test/scala/github4s/unit/GHReposSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ class GHReposSpec extends BaseSpec {
ghReposData.listOrgRepos(validRepoOwner)
}

"GHRepos.listUserRepos" should "call to RepositoryOps with the right parameters" in {

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

val repoOps = mock[RepositoryOpsTest]
(repoOps.listUserRepos _)
.expects(validRepoOwner, None, None, sampleToken)
.returns(response)

val ghReposData = new GHRepos(sampleToken)(repoOps)
ghReposData.listUserRepos(validRepoOwner)
}

"GHRepos.contents" should "call to RepositoryOps with the right parameters" in {

val response: Free[GitHub4s, GHResponse[NonEmptyList[Content]]] =
Expand Down
20 changes: 20 additions & 0 deletions github4s/shared/src/test/scala/github4s/unit/ReposSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ class ReposSpec extends BaseSpec {
)
}

"Repos.listUserRepos" should "call to httpClient.get with the right parameters" in {

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

val httpClientMock = httpClientMockGet[List[Repository]](
url = s"users/$validRepoOwner/repos",
response = response
)

val repos = new Repos[String, Id] {
override val httpClient: HttpClient[String, Id] = httpClientMock
}
repos.listUserRepos(
sampleToken,
headerUserAgent,
validRepoOwner
)
}

"Repos.getContents" should "call to httpClient.get with the right parameters" in {

val response: GHResponse[NonEmptyList[Content]] =
Expand Down