Skip to content

Commit

Permalink
Add support for the add labels endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
BenFradet committed Jun 15, 2018
1 parent ff0e380 commit 4d89e52
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 1 deletion.
22 changes: 22 additions & 0 deletions docs/src/main/tut/issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,28 @@ The `result` on the right is the corresponding [List[Label]][issue-scala]

See [the API doc](https://developer.github.com/v3/issues/labels/#list-labels-on-an-issue) for full reference.

### Add labels

You can add existing labels to an issue with the following parameters:

- the repository coordinates (`owner` and `name` of the repository).
- `number`: The issue number.
- `labels`: The existing labels that require adding.

To add existing labels to an issue:

```tut:silent
val assignedLabelList = Github(accessToken).issues.addLabels("47deg", "github4s", 123, List("bug", "code review"))
assignedLabelList.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 assigned [List[Label]][issue-scala]

See [the API doc](https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue) for full reference.

As you can see, a few features of the issue endpoint are missing.

As a result, if you'd like to see a feature supported, feel free to create an issue and/or a pull request!
Expand Down
39 changes: 39 additions & 0 deletions github4s/jvm/src/test/scala/github4s/unit/ApiSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,45 @@ class ApiSpec
response should be('left)
}

"Issues >> AddLabels" should "return the assigned issue labels when a valid issue number is provided" in {
val response =
issues.addLabels(
accessToken,
headerUserAgent,
validRepoOwner,
validRepoName,
validIssueNumber,
validIssueLabel)
response should be('right)

response.toOption map { r
r.result.nonEmpty shouldBe true
r.statusCode shouldBe okStatusCode
}
}
it should "return an error if an invalid issue number is provided" in {
val response =
issues.addLabels(
accessToken,
headerUserAgent,
validRepoOwner,
validRepoName,
invalidIssueNumber,
validIssueLabel)
response should be('left)
}
it should "return an error if no tokens are provided" in {
val response =
issues.addLabels(
None,
headerUserAgent,
validRepoOwner,
validRepoName,
validIssueNumber,
validIssueLabel)
response should be('left)
}

"Activities >> Set a Thread Subscription" should "return the subscription when a valid thread id is provided" in {
val response =
activities.setThreadSub(accessToken, headerUserAgent, validThreadId, true, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,31 @@ trait MockGithubApiServer extends MockServerService with FakeResponses with Test
.withHeader("Authorization", tokenHeader))
.respond(response.withStatusCode(notFoundStatusCode).withBody(notFoundResponse))

//Issues >> Add labels for an Issue
mockServer
.when(
request
.withMethod("POST")
.withPath(s"/repos/$validRepoOwner/$validRepoName/issues/$validIssueNumber/labels")
.withHeader("Authorization", tokenHeader))
.respond(response.withStatusCode(okStatusCode).withBody(listLabelsValidResponse))

mockServer
.when(
request
.withMethod("POST")
.withPath(s"/repos/$validRepoOwner/$validRepoName/issues/$invalidIssueNumber/lablels")
.withHeader("Authorization", tokenHeader))
.respond(response.withStatusCode(notFoundStatusCode).withBody(notFoundResponse))

mockServer
.when(
request
.withMethod("POST")
.withPath(s"/repos/$validRepoOwner/$validRepoName/issues/$validIssueNumber/labels")
.withHeader(not("Authorization")))
.respond(response.withStatusCode(notFoundStatusCode).withBody(notFoundResponse))

//Issues >> List labels for an Issue
mockServer
.when(
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 @@ -238,6 +238,14 @@ class GHIssues(accessToken: Option[String] = None)(implicit O: IssueOps[GitHub4s
): GHIO[GHResponse[List[Label]]] =
O.listLabels(owner, repo, number, accessToken)

def addLabels(
owner: String,
repo: String,
number: Int,
labels: List[String]
): GHIO[GHResponse[List[Label]]] =
O.addLabels(owner, repo, number, labels, accessToken)

}

class GHActivities(accessToken: Option[String] = None)(implicit O: ActivityOps[GitHub4s]) {
Expand Down
25 changes: 24 additions & 1 deletion github4s/shared/src/main/scala/github4s/api/Issues.scala
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ class Issues[C, M[_]](
httpClient.get[List[Comment]](accessToken, s"repos/$owner/$repo/issues/$number/comments", headers)

/**
*
* Create a comment
*
* @param accessToken to identify the authenticated user
Expand Down Expand Up @@ -276,4 +275,28 @@ class Issues[C, M[_]](
number: Int): M[GHResponse[List[Label]]] =
httpClient.get[List[Label]](accessToken, s"repos/$owner/$repo/issues/$number/labels", headers)

/**
* Add the specified labels to an Issue
*
* @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 Issue number
* @param labels the list of labels to add to the issue
* @return a GHResponse with the list of labels added to the Issue.
*/
def addLabels(
accessToken: Option[String] = None,
headers: Map[String, String] = Map(),
owner: String,
repo: String,
number: Int,
labels: List[String]): M[GHResponse[List[Label]]] =
httpClient.post[List[Label]](
accessToken,
s"repos/$owner/$repo/issues/$number/labels",
headers,
labels.asJson.noSpaces)

}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ final case class ListLabels(
accessToken: Option[String] = None
) extends IssueOp[GHResponse[List[Label]]]

final case class AddLabels(
owner: String,
repo: String,
number: Int,
labels: List[String],
accessToken: Option[String] = None
) extends IssueOp[GHResponse[List[Label]]]

/**
* Exposes Issue operations as a Free monadic algebra that may be combined with other Algebras via
* Coproduct
Expand Down Expand Up @@ -204,6 +212,15 @@ class IssueOps[F[_]](implicit I: InjectK[IssueOp, F]) {
): Free[F, GHResponse[List[Label]]] =
Free.inject[IssueOp, F](ListLabels(owner, repo, number, accessToken))

def addLabels(
owner: String,
repo: String,
number: Int,
labels: List[String],
accessToken: Option[String] = None
): Free[F, GHResponse[List[Label]]] =
Free.inject[IssueOp, F](AddLabels(owner, repo, number, labels, accessToken))

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ class Interpreters[M[_], C](
issues.deleteComment(accessToken, headers, owner, repo, id)
case ListLabels(owner, repo, number, accessToken)
issues.listLabels(accessToken, headers, owner, repo, number)
case AddLabels(owner, repo, number, labels, accessToken)
issues.addLabels(accessToken, headers, owner, repo, number, labels)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,15 @@ trait GHIssuesSpec[T] extends BaseIntegrationSpec[T] {
r.statusCode shouldBe okStatusCode
})
}

"Issues >> AddLabels" should "return a list of labels" in {
val response = Github(accessToken).issues
.addLabels(validRepoOwner, validRepoName, validIssueNumber, validIssueLabel)
.execFuture[T](headerUserAgent)

testFutureIsRight[List[Label]](response, { r =>
r.result.nonEmpty shouldBe true
r.statusCode shouldBe okStatusCode
})
}
}
13 changes: 13 additions & 0 deletions github4s/shared/src/test/scala/github4s/unit/GHIssuesSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,17 @@ class GHIssuesSpec extends BaseSpec {
ghIssues.listLabels(validRepoOwner, validRepoName, validIssueNumber)
}

"Issues.AddLabels" should "call to IssuesOps with the right parameters" in {
val response: Free[GitHub4s, GHResponse[List[Label]]] =
Free.pure(Right(GHResult(List(label), okStatusCode, Map.empty)))

val commentOps = mock[IssueOpsTest]
(commentOps.addLabels _)
.expects(validRepoOwner, validRepoName, validIssueNumber, validIssueLabel, sampleToken)
.returns(response)

val ghIssues = new GHIssues(sampleToken)(commentOps)
ghIssues.addLabels(validRepoOwner, validRepoName, validIssueNumber, validIssueLabel)
}

}
29 changes: 29 additions & 0 deletions github4s/shared/src/test/scala/github4s/unit/IssuesSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,33 @@ class IssuesSpec extends BaseSpec {
validRepoName,
validIssueNumber)
}

"Issues.AddLabels" should "call httpClient.post with the right parameters" in {
val response: GHResponse[List[Label]] =
Right(GHResult(List(label), okStatusCode, Map.empty))

val request =
"""
|[
| "bug",
| "code review"
|]""".stripMargin

val httpClientMock = httpClientMockPost[List[Label]](
url = s"repos/$validRepoOwner/$validRepoName/issues/$validIssueNumber/labels",
json = request,
response = response
)

val issues = new Issues[String, Id] {
override val httpClient: HttpClient[String, Id] = httpClientMock
}
issues.addLabels(
sampleToken,
headerUserAgent,
validRepoOwner,
validRepoName,
validIssueNumber,
validIssueLabel)
}
}

0 comments on commit 4d89e52

Please sign in to comment.