Skip to content

Commit ecb14cd

Browse files
anamariamvbond15Rafa Paradelajuanpedromoreno
authored
Get the list of teams in an organization. (#350)
* initial refactoring from free monad to tagless final * Added Algebras * Refactored HttpClient, temporarily bypassing HttpRequestBuilderExtension, added runtime implicits, added User alg interpretation * moving /free/domain to /taglessFinal/domain * Adding interpreters for algebras. Interpreters target the /api classes * reformatted/linted, remove ADTs from algebras, added more implicit runtime instnaces * updated algebra signatures to match existing api, removed accessToken as default param, added headers as default param * Modified intepreters to fit new algebra definitions and take accessToken as a default parameter * removing free monad implementation * updating GHWorkflow and Github * for Rafa review * pre merge * Updated F type constraint F[_]: Applicative -> F[_]: ConcurrentEffect * For Rafa comment, progress on replacing scalaj-http with http4s * For Rafa review and refactor * applied some refactoring to have clean layers * Adding toFutue and toId syntax for IO[A] * removing unit tests associated with deleted classes * For Rafa Review, unit tests * updating unit tests for interpreters * unit test linting * refactoring integration test to match new api usage * updating unit and integration test base spec * linting and updating scala version 2.13 and blaze client * fixing TestData for integration test * Updateding FakeResponses for Decoder testing * fix integration test, pull GITHUB4S_ACCESS_TOKEN from sys env * upgrades some models * Revert "upgrades some models" This reverts commit 4771d05 * fixes the unit tests * removes commented import * fixes the decoders issue for the new http client * proves the organization's members with the proper token * enables commented suites * ignores temporally a test because we are getting permission issues * Updating documentation, initial draft * Update contributing.md * fixing github doc links * cleaning interpreter imports, retarget issue for testing (123 -> 17) * remove old api tests * remove mock-server dependency, change http4s version * switching to compile-only check in documentation. mdoc:silent -> mdoc:compile-only * added GET listTeams * Address Ben F. PR comments * Address Lawrence's PR comments * Address Anna M. PR Comments * Address Ana G. PR comments * fixes test * added pagination * merge with master * Update github4s/src/main/scala/github4s/domain/Team.scala Co-Authored-By: Juan Pedro Moreno <4879373+juanpedromoreno@users.noreply.github.com> * Address Ben PR Comments * optimize imports * Address Eric Bond PR Comments * added documentation Co-authored-by: bond15 <bond.eric.23@gmail.com> Co-authored-by: Rafa Paradela <rafa.p@47deg.com> Co-authored-by: Juan Pedro Moreno <4879373+juanpedromoreno@users.noreply.github.com>
1 parent deea5b1 commit ecb14cd

13 files changed

Lines changed: 297 additions & 28 deletions

File tree

docs/docs/team.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
layout: docs
3+
title: Team API
4+
permalink: team
5+
---
6+
7+
# Team API
8+
9+
Github4s supports the [Team API](https://developer.github.com/v3/teams/). As a result,
10+
with Github4s, you can interact with:
11+
12+
- [Team](#team)
13+
- [List team](#list-team)
14+
15+
The following examples assume the following imports and token:
16+
17+
```scala mdoc:silent
18+
import github4s.Github
19+
import github4s.GithubIOSyntax._
20+
import cats.effect.IO
21+
import scala.concurrent.ExecutionContext.Implicits.global
22+
23+
implicit val IOContextShift = IO.contextShift(global)
24+
val accessToken = sys.env.get("GITHUB4S_ACCESS_TOKEN")
25+
```
26+
27+
They also make use of `cats.Id`, but any type container `F` implementing `ConcurrentEffect` will do.
28+
29+
LiftIO syntax for `cats.Id` and `Future` are provided in `GithubIOSyntax`.
30+
31+
## Team
32+
33+
### List team
34+
35+
You can list the teams for a particular organization with `listTeams`; it takes as arguments:
36+
37+
- `org`: name of the organization for which we want to retrieve the teams.
38+
- `pagination`: Limit and Offset for pagination, optional.
39+
40+
To list the teams for organization `47deg`:
41+
42+
```scala mdoc:compile-only
43+
val listTeams = Github[IO](accessToken).teams.listTeams("47deg")
44+
listTeams.unsafeRunSync match {
45+
case Left(e) => println(s"Something went wrong: ${e.getMessage}")
46+
case Right(r) => println(r.result)
47+
}
48+
```
49+
50+
The `result` on the right is the corresponding [List[Team]][team-scala].
51+
52+
See [the API doc](https://developer.github.com/v3/teams/#list-teams) for full reference.
53+
54+
55+
[team-scala]: https://github.com/47deg/github4s/blob/master/github4s/src/main/scala/github4s/domain/Team.scala

docs/src/main/resources/microsite/data/menu.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@ options:
2828

2929
- title: Organization API
3030
url: organization
31+
32+
- title: Team API
33+
url: team

github4s/src/main/scala/github4s/Decoders.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,7 @@ object Decoders {
278278
starred_at <- c.downField("starred_at").as[String]
279279
user <- c.downField("user").as[User]
280280
} yield Stargazer(Some(starred_at), user)))
281+
282+
implicit val decodeTeam: Decoder[Team] = deriveDecoder[Team]
283+
281284
}

github4s/src/main/scala/github4s/Github.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class Github[F[_]: ConcurrentEffect](accessToken: Option[String], timeout: Optio
3838
lazy val gitData: GitData[F] = module.gitData
3939
lazy val pullRequests: PullRequests[F] = module.pullRequests
4040
lazy val organizations: Organizations[F] = module.organizations
41-
41+
lazy val teams: Teams[F] = module.teams
4242
}
4343

4444
object Github {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2016-2020 47 Degrees, LLC. <http://www.47deg.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package github4s.algebras
18+
19+
import github4s.GithubResponses.GHResponse
20+
import github4s.domain._
21+
22+
trait Teams[F[_]] {
23+
24+
/** List the teams for a particular organization
25+
*
26+
* @param org organization for which we wish to retrieve the teams
27+
* @param pagination Limit and Offset for pagination
28+
* @param headers optional user headers to include in the request
29+
* @return GHResponse[List[Team]] the list of teams for this organization
30+
*/
31+
def listTeams(
32+
org: String,
33+
pagination: Option[Pagination] = None,
34+
headers: Map[String, String] = Map()): F[GHResponse[List[Team]]]
35+
36+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2016-2020 47 Degrees, LLC. <http://www.47deg.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package github4s.domain
18+
19+
final case class Team(
20+
id: Int,
21+
node_id: String,
22+
url: String,
23+
html_url: String,
24+
name: String,
25+
slug: String,
26+
description: Option[String],
27+
privacy: String,
28+
permission: String,
29+
members_url: String,
30+
repositories_url: String,
31+
parent: Option[Team] = None
32+
)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2016-2020 47 Degrees, LLC. <http://www.47deg.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package github4s.interpreters
18+
19+
import github4s.Decoders._
20+
import github4s.GithubResponses.GHResponse
21+
import github4s.algebras.Teams
22+
import github4s.domain._
23+
import github4s.http.HttpClient
24+
25+
class TeamsInterpreter[F[_]](implicit client: HttpClient[F], accessToken: Option[String])
26+
extends Teams[F] {
27+
28+
override def listTeams(
29+
org: String,
30+
pagination: Option[Pagination],
31+
headers: Map[String, String]): F[GHResponse[List[Team]]] =
32+
client.get[List[Team]](accessToken, method = s"orgs/$org/teams", headers, Map.empty, pagination)
33+
}

github4s/src/main/scala/github4s/modules/GithubAPIs.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ sealed trait GithubAPIs[F[_]] {
3434
def gitData: GitData[F]
3535
def pullRequests: PullRequests[F]
3636
def organizations: Organizations[F]
37+
def teams: Teams[F]
3738
}
3839

3940
class GithubAPIv3[F[_]: ConcurrentEffect](accessToken: Option[String] = None, timeout: Duration)(
@@ -52,4 +53,6 @@ class GithubAPIv3[F[_]: ConcurrentEffect](accessToken: Option[String] = None, ti
5253
override val gitData: GitData[F] = new GitDataInterpreter[F]
5354
override val pullRequests: PullRequests[F] = new PullRequestsInterpreter[F]
5455
override val organizations: Organizations[F] = new OrganizationsInterpreter[F]
56+
override val teams: Teams[F] = new TeamsInterpreter[F]
57+
5558
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2016-2020 47 Degrees, LLC. <http://www.47deg.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package github4s.integration
18+
19+
import cats.effect.IO
20+
import github4s.GithubIOSyntax._
21+
import github4s.Github
22+
import github4s.domain._
23+
import github4s.utils.{BaseIntegrationSpec, Integration}
24+
25+
trait GHTeamsSpec extends BaseIntegrationSpec {
26+
"Team >> ListTeams" should "return the expected teams when a valid org is provided" taggedAs Integration in {
27+
val response =
28+
Github[IO](accessToken).teams
29+
.listTeams(validRepoOwner, headers = headerUserAgent)
30+
.unsafeRunSync()
31+
32+
testIsRight[List[Team]](response, { r =>
33+
r.result.nonEmpty shouldBe true
34+
r.statusCode shouldBe okStatusCode
35+
})
36+
}
37+
38+
it should "return error when an invalid org is passed" taggedAs Integration in {
39+
val response =
40+
Github[IO](accessToken).teams
41+
.listTeams(invalidRepoName, headers = headerUserAgent)
42+
.unsafeRunSync()
43+
44+
testIsLeft(response)
45+
}
46+
47+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2016-2020 47 Degrees, LLC. <http://www.47deg.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package github4s.unit
18+
19+
import cats.effect.IO
20+
import github4s.GithubResponses.{GHResponse, GHResult}
21+
import github4s.domain._
22+
import github4s.interpreters.TeamsInterpreter
23+
import github4s.utils.BaseSpec
24+
25+
class TeamsSpec extends BaseSpec {
26+
27+
implicit val token = sampleToken
28+
29+
"Teams.listTeam" should "call to httpClient.get with the right parameters" in {
30+
31+
val response: IO[GHResponse[List[Team]]] =
32+
IO(Right(GHResult(List(team), okStatusCode, Map.empty)))
33+
34+
implicit val httpClientMock = httpClientMockGet[List[Team]](
35+
url = s"orgs/$validRepoOwner/teams",
36+
response = response
37+
)
38+
39+
val teams = new TeamsInterpreter[IO]
40+
41+
teams.listTeams(validRepoOwner, headers = headerUserAgent)
42+
}
43+
44+
}

0 commit comments

Comments
 (0)