Skip to content

Commit

Permalink
Adds create and edit methods for issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Fede Fernández committed Jan 4, 2017
1 parent f6f79f0 commit 7e37e5b
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,24 @@ class GHIssuesSpec extends AsyncFlatSpec with Matchers with TestUtils {
r.statusCode shouldBe okStatusCode
})
}

"Issues >> Edit" should "edit the specified issue" in {
val response = Github(accessToken).issues
.editIssue(validRepoOwner,
validRepoName,
validIssue,
validIssueState,
validIssueTitle,
validIssueBody,
None,
validIssueLabel,
validAssignees)
.execFuture(headerUserAgent)

testFutureIsRight[Issue](response, { r =>
r.result.state shouldBe validIssueState
r.result.title shouldBe validIssueTitle
r.statusCode shouldBe okStatusCode
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,11 @@ trait TestUtils extends Matchers {
IssueTypeIssue,
SearchIn(Set(SearchInTitle))
)

val validIssue = 48
val validIssueTitle = "Sample Title"
val validIssueBody = "Sample Body"
val validIssueState = "closed"
val validIssueLabel = List("bug", "code review")
val validAssignees = List(validUsername)
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,25 @@ class GHIssuesSpec extends FlatSpec with Matchers with TestUtils {
r.statusCode shouldBe okStatusCode
}
}

"Issues >> Edit" should "edit the specified issue" in {
val response = Github(accessToken).issues
.editIssue(validRepoOwner,
validRepoName,
validIssue,
validIssueState,
validIssueTitle,
validIssueBody,
None,
validIssueLabel,
validAssignees)
.exec[Id, HttpResponse[String]](headerUserAgent)

response should be('right)
response.toOption map { r
r.result.state shouldBe validIssueState
r.result.title shouldBe validIssueTitle
r.statusCode shouldBe okStatusCode
}
}
}
7 changes: 7 additions & 0 deletions github4s/jvm/src/test/scala/github4s/utils/TestUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,11 @@ trait TestUtils {
IssueTypeIssue,
SearchIn(Set(SearchInTitle))
)

val validIssue = 48
val validIssueTitle = "Sample Title"
val validIssueBody = "Sample Body"
val validIssueState = "closed"
val validIssueLabel = List("bug", "code review")
val validAssignees = List(validUsername)
}
24 changes: 24 additions & 0 deletions github4s/shared/src/main/scala/github4s/GithubAPIs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,28 @@ class GHIssues(accessToken: Option[String] = None)(implicit O: IssueOps[GitHub4s
searchParams: List[SearchParam]
): GHIO[GHResponse[SearchIssuesResult]] =
O.searchIssues(query, searchParams, accessToken)

def createIssue(
owner: String,
repo: String,
title: String,
body: Option[String] = None,
milestone: Option[Int] = None,
labels: Option[List[String]] = None,
assignees: Option[List[String]] = None
): GHIO[GHResponse[Issue]] =
O.createIssue(owner, repo, title, body, milestone, labels, assignees, accessToken)

def editIssue(
owner: String,
repo: String,
issue: Int,
state: String,
title: String,
body: String,
milestone: Option[Int] = None,
labels: List[String] = List.empty,
assignees: List[String] = List.empty
): GHIO[GHResponse[Issue]] =
O.editIssue(owner, repo, issue, state, title, body, milestone, labels, assignees, accessToken)
}
64 changes: 63 additions & 1 deletion github4s/shared/src/main/scala/github4s/api/Issues.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ package github4s.api

import github4s.GithubResponses.GHResponse
import github4s.{GithubApiUrls, HttpClient, HttpRequestBuilderExtension}
import github4s.free.domain.{Issue, SearchIssuesResult, SearchParam}
import github4s.free.domain._
import github4s.free.interpreters.Capture
import github4s.util.URLEncoder
import io.circe.syntax._
import io.circe.generic.auto._

/** Factory to encapsulate calls related to Issues operations */
Expand Down Expand Up @@ -82,4 +83,65 @@ class Issues[C, M[_]](implicit urls: GithubApiUrls,
.get[SearchIssuesResult](accessToken, "search/issues", headers, Map("q" -> queryString))
}

/**
* Create 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 title The title of the issue.
* @param body The contents of the issue.
* @param milestone The number of the milestone to associate this issue with.
* @param labels Labels to associate with this issue.
* @param assignees Logins for Users to assign to this issue.
*/
def create(accessToken: Option[String] = None,
headers: Map[String, String] = Map(),
owner: String,
repo: String,
title: String,
body: Option[String],
milestone: Option[Int],
labels: Option[List[String]],
assignees: Option[List[String]]): M[GHResponse[Issue]] =
httpClient.post[Issue](
accessToken,
s"repos/$owner/$repo/issues",
headers,
data = NewIssueRequest(title, body, milestone, labels, assignees).asJson.noSpaces)

/**
* Create an issue
*
* @param accessToken to identify the authenticated user
* @param headers optional user headers to include in the request
* @param title The title of the issue.
* @param body The contents of the issue.
* @param state State of the issue. Either open or closed.
* @param milestone The number of the milestone to associate this issue with.
* @param labels Labels to associate with this issue.
* Pass one or more Labels to replace the set of Labels on this Issue.
* Send an empty list to clear all Labels from the Issue.
* @param assignees Logins for Users to assign to this issue.
* Pass one or more user logins to replace the set of assignees on this Issue.
* Send an empty list to clear all assignees from the Issue.
*/
def edit(accessToken: Option[String] = None,
headers: Map[String, String] = Map(),
owner: String,
repo: String,
issue: Int,
state: String,
title: String,
body: String,
milestone: Option[Int],
labels: List[String],
assignees: List[String]): M[GHResponse[Issue]] =
httpClient.patch[Issue](
accessToken,
s"repos/$owner/$repo/issues/$issue",
headers,
data = EditIssueRequest(state, title, body, milestone, labels, assignees).asJson.noSpaces)

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,30 @@ final case class SearchIssues(
accessToken: Option[String] = None
) extends IssueOp[GHResponse[SearchIssuesResult]]

final case class CreateIssue(
owner: String,
repo: String,
title: String,
body: Option[String],
milestone: Option[Int],
labels: Option[List[String]],
assignees: Option[List[String]],
accessToken: Option[String] = None
) extends IssueOp[GHResponse[Issue]]

final case class EditIssue(
owner: String,
repo: String,
issue: Int,
state: String,
title: String,
body: String,
milestone: Option[Int],
labels: List[String],
assignees: List[String],
accessToken: Option[String] = None
) extends IssueOp[GHResponse[Issue]]

/**
* Exposes Issue operations as a Free monadic algebra that may be combined with other Algebras via
* Coproduct
Expand All @@ -61,6 +85,34 @@ class IssueOps[F[_]](implicit I: Inject[IssueOp, F]) {
accessToken: Option[String] = None
): Free[F, GHResponse[SearchIssuesResult]] =
Free.inject[IssueOp, F](SearchIssues(query, searchParams, accessToken))

def createIssue(
owner: String,
repo: String,
title: String,
body: Option[String],
milestone: Option[Int],
labels: Option[List[String]],
assignees: Option[List[String]],
accessToken: Option[String] = None
): Free[F, GHResponse[Issue]] =
Free.inject[IssueOp, F](
CreateIssue(owner, repo, title, body, milestone, labels, assignees, accessToken))

def editIssue(
owner: String,
repo: String,
issue: Int,
state: String,
title: String,
body: String,
milestone: Option[Int],
labels: List[String],
assignees: List[String],
accessToken: Option[String] = None
): Free[F, GHResponse[Issue]] =
Free.inject[IssueOp, F](
EditIssue(owner, repo, issue, state, title, body, milestone, labels, assignees, accessToken))
}

/**
Expand Down
13 changes: 13 additions & 0 deletions github4s/shared/src/main/scala/github4s/free/domain/Issue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,16 @@ case class PullRequest(url: Option[String],
patch_url: Option[String])

case class SearchIssuesResult(total_count: Int, incomplete_results: Boolean, items: List[Issue])

case class NewIssueRequest(title: String,
body: Option[String],
milestone: Option[Int],
labels: Option[List[String]],
assignees: Option[List[String]])

case class EditIssueRequest(state: String,
title: String,
body: String,
milestone: Option[Int],
labels: List[String],
assignees: List[String])
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,30 @@ class Interpreters[M[_], C](implicit A: ApplicativeError[M, Throwable],
issues.list(accessToken, headers, owner, repo)
case SearchIssues(query, searchParams, accessToken)
issues.search(accessToken, headers, query, searchParams)
case CreateIssue(owner, repo, title, body, milestone, labels, assignees, accessToken)
issues
.create(accessToken, headers, owner, repo, title, body, milestone, labels, assignees)
case EditIssue(owner,
repo,
issue,
state,
title,
body,
milestone,
labels,
assignees,
accessToken)
issues.edit(accessToken,
headers,
owner,
repo,
issue,
state,
title,
body,
milestone,
labels,
assignees)
}
}
}
Expand Down

0 comments on commit 7e37e5b

Please sign in to comment.