Skip to content

Commit 7b8e4ac

Browse files
Support getting release by release Id (#497)
1 parent 0b01fb7 commit 7b8e4ac

5 files changed

Lines changed: 110 additions & 6 deletions

File tree

docs/docs/repository.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ with Github4s, you can interact with:
2424
- [Delete a File](#delete-a-file)
2525
- [Releases](#releases)
2626
- [List of releases](#list-of-releases)
27+
- [Get a single release](#get-a-single-release)
2728
- [The latest release](#the-latest-release)
2829
- [Create a release](#create-a-release)
2930
- [Statuses](#statuses)
@@ -381,6 +382,31 @@ response.result match {
381382

382383
The `result` on the right is the corresponding [List[Release]][repository-scala].
383384

385+
### Get a single release
386+
387+
You can get a release using `getRelease`, it takes as arguments:
388+
389+
- the release coordinates (`releaseId` the id of the release)
390+
- the repository coordinates (`owner` and `name` of the repository).
391+
392+
Get a release by release id:
393+
394+
```scala mdoc:compile-only
395+
val getRelease =
396+
gh.repos.getRelease(
397+
123,
398+
"47deg",
399+
"github4s")
400+
val response = getRelease.unsafeRunSync()
401+
response.result match {
402+
case Left(e) => println(s"Something went wrong: ${e.getMessage}")
403+
case Right(r) => println(r)
404+
}
405+
```
406+
407+
The `result` on the right is the corresponding [Option[Release]][repository-scala].
408+
409+
384410
### The latest release
385411

386412
You can get the latest release using `latestRelease`, it takes as arguments:

github4s/src/main/scala/github4s/algebras/Repositories.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,22 @@ trait Repositories[F[_]] {
271271
headers: Map[String, String] = Map()
272272
): F[GHResponse[List[User]]]
273273

274+
/**
275+
* Get a single release
276+
*
277+
* @param releaseId id of the release
278+
* @param owner of the repo
279+
* @param repo name of the repo
280+
* @param headers optional user headers to include in the request
281+
* @return a GHResponse with List[Release]
282+
*/
283+
def getRelease(
284+
releaseId: Int,
285+
owner: String,
286+
repo: String,
287+
headers: Map[String, String] = Map()
288+
): F[GHResponse[Option[Release]]]
289+
274290
/**
275291
* Latest release
276292
*

github4s/src/main/scala/github4s/interpreters/RepositoriesInterpreter.scala

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616

1717
package github4s.interpreters
1818

19-
import github4s.http.HttpClient
20-
import github4s.algebras.Repositories
2119
import cats.data.NonEmptyList
22-
import github4s.GHResponse
23-
import github4s.domain._
20+
import com.github.marklister.base64.Base64._
2421
import github4s.Decoders._
2522
import github4s.Encoders._
26-
import com.github.marklister.base64.Base64._
23+
import github4s.GHResponse
24+
import github4s.algebras.Repositories
25+
import github4s.domain._
26+
import github4s.http.HttpClient
2727

2828
class RepositoriesInterpreter[F[_]](implicit client: HttpClient[F], accessToken: Option[String])
2929
extends Repositories[F] {
@@ -225,6 +225,20 @@ class RepositoriesInterpreter[F[_]](implicit client: HttpClient[F], accessToken:
225225
client
226226
.get[Option[Release]](accessToken, s"repos/$owner/$repo/releases/latest", headers, Map.empty)
227227

228+
override def getRelease(
229+
releaseId: Int,
230+
owner: String,
231+
repo: String,
232+
headers: Map[String, String]
233+
): F[GHResponse[Option[Release]]] =
234+
client
235+
.get[Option[Release]](
236+
accessToken,
237+
s"repos/$owner/$repo/releases/$releaseId",
238+
headers,
239+
Map.empty
240+
)
241+
228242
override def listReleases(
229243
owner: String,
230244
repo: String,

github4s/src/test/scala/github4s/integration/ReposSpec.scala

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ package github4s.integration
1818

1919
import cats.data.NonEmptyList
2020
import cats.effect.{IO, Resource}
21+
import cats.implicits._
2122
import github4s.GHError.NotFoundError
22-
import github4s.Github
2323
import github4s.domain._
2424
import github4s.utils.{BaseIntegrationSpec, Integration}
25+
import github4s.{GHResponse, Github}
2526

2627
trait ReposSpec extends BaseIntegrationSpec {
2728

@@ -61,6 +62,39 @@ trait ReposSpec extends BaseIntegrationSpec {
6162
response.statusCode shouldBe okStatusCode
6263
}
6364

65+
"Repos >> getRelease" should "return the expected repos when a valid org is provided" taggedAs Integration in {
66+
67+
val responseResource = for {
68+
client <- clientResource
69+
70+
gh: Github[IO] = Github[IO](client, accessToken)
71+
releasesIO =
72+
gh.repos.listReleases(validRepoOwner, validRepoName, None, headers = headerUserAgent)
73+
74+
releasesResponse <- Resource.liftF(releasesIO)
75+
76+
releases <- Resource.liftF(IO.fromEither(releasesResponse.result))
77+
78+
releasesAreFoundCheck: IO[List[(Release, GHResponse[Option[Release]])]] = releases.map {
79+
release =>
80+
val releaseIO = gh.repos
81+
.getRelease(release.id, validRepoOwner, validRepoName, headers = headerUserAgent)
82+
releaseIO.map(r => release -> r)
83+
}.sequence
84+
85+
} yield releasesAreFoundCheck
86+
87+
val responseList: List[(Release, GHResponse[Option[Release]])] = responseResource
88+
.use(identity)
89+
.unsafeRunSync()
90+
91+
forAll(responseList) {
92+
case (release, response) =>
93+
testIsRight[Option[Release]](response, r => r should contain(release))
94+
response.statusCode shouldBe okStatusCode
95+
}
96+
}
97+
6498
"Repos >> LatestRelease" should "return the expected repos when a valid org is provided" taggedAs Integration in {
6599
val response = clientResource
66100
.use { client =>

github4s/src/test/scala/github4s/unit/ReposSpec.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,20 @@ class ReposSpec extends BaseSpec {
7171
repos.latestRelease(validRepoOwner, validRepoName, headers = headerUserAgent)
7272
}
7373

74+
"Repos.getRelease" should "call to httpClient.get with the right parameters" in {
75+
val response: IO[GHResponse[Option[Release]]] =
76+
IO(GHResponse(Option(release).asRight, okStatusCode, Map.empty))
77+
78+
implicit val httpClientMock = httpClientMockGet[Option[Release]](
79+
url = s"repos/$validRepoOwner/$validRepoName/releases/${release.id}",
80+
response = response
81+
)
82+
83+
val repos = new RepositoriesInterpreter[IO]
84+
85+
repos.getRelease(release.id, validRepoOwner, validRepoName, headers = headerUserAgent)
86+
}
87+
7488
"Repos.listOrgRepos" should "call to httpClient.get with the right parameters" in {
7589
val response: IO[GHResponse[List[Repository]]] =
7690
IO(GHResponse(List(repo).asRight, okStatusCode, Map.empty))

0 commit comments

Comments
 (0)