From 1429ec083558334c2148ca60aa2dc98e02b20b6e Mon Sep 17 00:00:00 2001 From: Ivan Doroshenko Date: Thu, 13 Jan 2022 19:09:24 +0300 Subject: [PATCH 1/3] Add PullRequestMergeMethod enum and json coder --- github4s/src/main/scala/github4s/Decoders.scala | 7 +++++++ github4s/src/main/scala/github4s/Encoders.scala | 3 +++ github4s/src/main/scala/github4s/domain/PullRequest.scala | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/github4s/src/main/scala/github4s/Decoders.scala b/github4s/src/main/scala/github4s/Decoders.scala index 62d70541..031fc124 100644 --- a/github4s/src/main/scala/github4s/Decoders.scala +++ b/github4s/src/main/scala/github4s/Decoders.scala @@ -368,6 +368,13 @@ object Decoders { val issue = deriveDecoder[CreatePullRequestIssue] data.widen[CreatePullRequest] or issue.widen[CreatePullRequest] } + implicit val decoderPullRequestMergeMethod: Decoder[PullRequestMergeMethod] = + Decoder[String].emap { + case PRMergeMethodMerge.value => PRMergeMethodMerge.asRight + case PRMergeMethodRebase.value => PRMergeMethodRebase.asRight + case PRMergeMethodSquash.value => PRMergeMethodSquash.asRight + case other => s"Unknown pull request merge method: $other".asLeft + } implicit val decoderCreateReferenceRequest: Decoder[CreateReferenceRequest] = deriveDecoder[CreateReferenceRequest] implicit val decoderDeleteFileRequest: Decoder[DeleteFileRequest] = diff --git a/github4s/src/main/scala/github4s/Encoders.scala b/github4s/src/main/scala/github4s/Encoders.scala index d1e33134..a3b09108 100644 --- a/github4s/src/main/scala/github4s/Encoders.scala +++ b/github4s/src/main/scala/github4s/Encoders.scala @@ -48,6 +48,9 @@ object Encoders { implicit val encodePrrEvent: Encoder[PullRequestReviewEvent] = Encoder.encodeString.contramap(_.value) + implicit val encodePrMergeMethod: Encoder[PullRequestMergeMethod] = + Encoder.encodeString.contramap(_.value) + implicit val encodeEditGistFile: Encoder[EditGistFile] = { deriveEncoder[EditGistFile].mapJsonObject( _.filter(e => !(e._1.equals("filename") && e._2.isNull)) diff --git a/github4s/src/main/scala/github4s/domain/PullRequest.scala b/github4s/src/main/scala/github4s/domain/PullRequest.scala index aa87d49c..977649fa 100644 --- a/github4s/src/main/scala/github4s/domain/PullRequest.scala +++ b/github4s/src/main/scala/github4s/domain/PullRequest.scala @@ -154,3 +154,9 @@ final case class ReviewersResponse( final case class BranchUpdateRequest(expected_head_sha: Option[String]) final case class BranchUpdateResponse(message: String, url: String) + +sealed abstract class PullRequestMergeMethod(val value: String) extends Product with Serializable + +case object PRMergeMethodMerge extends PullRequestMergeMethod("merge") +case object PRMergeMethodSquash extends PullRequestMergeMethod("squash") +case object PRMergeMethodRebase extends PullRequestMergeMethod("rebase") From f954a1b82936a1d91b36665dafe6b221a531d15b Mon Sep 17 00:00:00 2001 From: Ivan Doroshenko Date: Thu, 13 Jan 2022 19:54:43 +0300 Subject: [PATCH 2/3] Add pull request merge interpretator implementation --- .../src/main/scala/github4s/Decoders.scala | 1 + .../src/main/scala/github4s/Encoders.scala | 3 +++ .../src/main/scala/github4s/GHError.scala | 24 +++++++++++++++++++ .../github4s/algebras/PullRequests.scala | 23 ++++++++++++++++++ .../scala/github4s/domain/PullRequest.scala | 9 +++++++ .../main/scala/github4s/http/HttpClient.scala | 2 ++ .../PullRequestsInterpreter.scala | 24 +++++++++++++++++++ 7 files changed, 86 insertions(+) diff --git a/github4s/src/main/scala/github4s/Decoders.scala b/github4s/src/main/scala/github4s/Decoders.scala index 031fc124..cfbbf528 100644 --- a/github4s/src/main/scala/github4s/Decoders.scala +++ b/github4s/src/main/scala/github4s/Decoders.scala @@ -375,6 +375,7 @@ object Decoders { case PRMergeMethodSquash.value => PRMergeMethodSquash.asRight case other => s"Unknown pull request merge method: $other".asLeft } + implicit val decoderPullRequestMergeResponse: Decoder[PullRequestMergeResponse] = deriveDecoder[PullRequestMergeResponse] implicit val decoderCreateReferenceRequest: Decoder[CreateReferenceRequest] = deriveDecoder[CreateReferenceRequest] implicit val decoderDeleteFileRequest: Decoder[DeleteFileRequest] = diff --git a/github4s/src/main/scala/github4s/Encoders.scala b/github4s/src/main/scala/github4s/Encoders.scala index a3b09108..c44f9c62 100644 --- a/github4s/src/main/scala/github4s/Encoders.scala +++ b/github4s/src/main/scala/github4s/Encoders.scala @@ -42,6 +42,9 @@ object Encoders { } } + implicit val encoderPullRequestMergeRequest: Encoder[PullRequestMergeRequest] = + deriveEncoder[PullRequestMergeRequest] + implicit val encodePrrStatus: Encoder[PullRequestReviewState] = Encoder.encodeString.contramap(_.value) diff --git a/github4s/src/main/scala/github4s/GHError.scala b/github4s/src/main/scala/github4s/GHError.scala index be603de6..d71237d9 100644 --- a/github4s/src/main/scala/github4s/GHError.scala +++ b/github4s/src/main/scala/github4s/GHError.scala @@ -141,6 +141,30 @@ object GHError { deriveDecoder[NotFoundError] } + /** + * Corresponds to a 405 status code + * @param message that was given in the response body + */ + final case class MethodNotAllowed(message: String) extends GHError(message) { + override def toString: String = s"MethodNotAllowed($message)" + } + object MethodNotAllowed { + private[github4s] implicit val methodNotAllowedDecoder: Decoder[MethodNotAllowed] = + deriveDecoder[MethodNotAllowed] + } + + /** + * Corresponds to a 409 status code + * @param message that was given in the response body + */ + final case class Conflict(message: String) extends GHError(message) { + override def toString: String = s"Conflict($message)" + } + object Conflict { + private[github4s] implicit val conflictDecoder: Decoder[Conflict] = + deriveDecoder[Conflict] + } + sealed trait ErrorCode object ErrorCode { case object MissingResource extends ErrorCode diff --git a/github4s/src/main/scala/github4s/algebras/PullRequests.scala b/github4s/src/main/scala/github4s/algebras/PullRequests.scala index f75d9b20..e0e1d822 100644 --- a/github4s/src/main/scala/github4s/algebras/PullRequests.scala +++ b/github4s/src/main/scala/github4s/algebras/PullRequests.scala @@ -104,6 +104,29 @@ trait PullRequests[F[_]] { headers: Map[String, String] = Map() ): F[GHResponse[PullRequest]] + /** + * Merge a pull request + * + * @param owner Owner of the repo + * @param repo Name of the repo + * @param number of the pull request for which we want to merge + * @param commitTitle Title for the automatic commit message + * @param commitMessage Extra detail to append to automatic commit message + * @param sha SHA that pull request head must match to allow merge + * @param mergeMethod Merge method to use. Possible values are merge, squash or rebase. Default is merge. + * @param headers Optional user headers to include in the request + */ + def mergePullRequest( + owner: String, + repo: String, + number: Long, + commitTitle: Option[String] = None, + commitMessage: Option[String] = None, + sha: Option[String] = None, + mergeMethod: Option[PullRequestMergeMethod] = None, + headers: Map[String, String] = Map() + ): F[GHResponse[PullRequestMergeResponse]] + /** * List pull request reviews. * diff --git a/github4s/src/main/scala/github4s/domain/PullRequest.scala b/github4s/src/main/scala/github4s/domain/PullRequest.scala index 977649fa..33bf44f3 100644 --- a/github4s/src/main/scala/github4s/domain/PullRequest.scala +++ b/github4s/src/main/scala/github4s/domain/PullRequest.scala @@ -78,6 +78,15 @@ final case class CreatePullRequestIssue( maintainer_can_modify: Option[Boolean] = Some(true) ) extends CreatePullRequest +final case class PullRequestMergeRequest( + commit_title: Option[String], + commit_message: Option[String], + sha: Option[String], + merge_method: Option[PullRequestMergeMethod] +) + +final case class PullRequestMergeResponse(sha: String, merged: Boolean, message: String) + sealed abstract class PRFilter(val name: String, val value: String) extends Product with Serializable { diff --git a/github4s/src/main/scala/github4s/http/HttpClient.scala b/github4s/src/main/scala/github4s/http/HttpClient.scala index 8ed94ed7..44b362c9 100644 --- a/github4s/src/main/scala/github4s/http/HttpClient.scala +++ b/github4s/src/main/scala/github4s/http/HttpClient.scala @@ -208,6 +208,8 @@ object HttpClient { case 401 => response.attemptAs[UnauthorizedError].map(_.asLeft) case 403 => response.attemptAs[ForbiddenError].map(_.asLeft) case 404 => response.attemptAs[GHError](notFoundEntityDecoder).map(_.asLeft) + case 405 => response.attemptAs[MethodNotAllowed].map(_.asLeft) + case 409 => response.attemptAs[Conflict].map(_.asLeft) case 422 => response.attemptAs[UnprocessableEntityError].map(_.asLeft) case 423 => response.attemptAs[RateLimitExceededError].map(_.asLeft) case _ => diff --git a/github4s/src/main/scala/github4s/interpreters/PullRequestsInterpreter.scala b/github4s/src/main/scala/github4s/interpreters/PullRequestsInterpreter.scala index 6535fafc..3aef541e 100644 --- a/github4s/src/main/scala/github4s/interpreters/PullRequestsInterpreter.scala +++ b/github4s/src/main/scala/github4s/interpreters/PullRequestsInterpreter.scala @@ -81,6 +81,30 @@ class PullRequestsInterpreter[F[_]](implicit client: HttpClient[F]) extends Pull .post[CreatePullRequest, PullRequest](s"repos/$owner/$repo/pulls", headers, data) } + override def mergePullRequest( + owner: String, + repo: String, + number: Long, + commitTitle: Option[String], + commitMessage: Option[String], + sha: Option[String], + mergeMethod: Option[PullRequestMergeMethod], + headers: Map[String, String] + ) = { + val request = PullRequestMergeRequest( + commitTitle, + commitMessage, + sha, + mergeMethod + ) + client + .put[PullRequestMergeRequest, PullRequestMergeResponse]( + s"/repos/$owner/$repo/pulls/$number/merge", + headers, + request + ) + } + override def listReviews( owner: String, repo: String, From d1665d344d703c7d849b6239361179e3d05eecba Mon Sep 17 00:00:00 2001 From: Ivan Doroshenko Date: Sat, 15 Jan 2022 11:52:05 +0300 Subject: [PATCH 3/3] Reformat to remove scalafmt error --- github4s/src/main/scala/github4s/Decoders.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/github4s/src/main/scala/github4s/Decoders.scala b/github4s/src/main/scala/github4s/Decoders.scala index cfbbf528..8140db69 100644 --- a/github4s/src/main/scala/github4s/Decoders.scala +++ b/github4s/src/main/scala/github4s/Decoders.scala @@ -375,7 +375,8 @@ object Decoders { case PRMergeMethodSquash.value => PRMergeMethodSquash.asRight case other => s"Unknown pull request merge method: $other".asLeft } - implicit val decoderPullRequestMergeResponse: Decoder[PullRequestMergeResponse] = deriveDecoder[PullRequestMergeResponse] + implicit val decoderPullRequestMergeResponse: Decoder[PullRequestMergeResponse] = + deriveDecoder[PullRequestMergeResponse] implicit val decoderCreateReferenceRequest: Decoder[CreateReferenceRequest] = deriveDecoder[CreateReferenceRequest] implicit val decoderDeleteFileRequest: Decoder[DeleteFileRequest] =