Skip to content

Commit

Permalink
introduce a builder-style structure for Mergify request_reviews
Browse files Browse the repository at this point in the history
  • Loading branch information
bpholt committed Jul 1, 2022
1 parent dce5a89 commit b106844
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 37 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ThisBuild / mergifyPrRules += MergifyPrRule(
"assign scala-steward's PRs for review",
List(MergifyCondition.Custom("author=typelevel-steward[bot]")),
List(
MergifyAction.RequestReviews("armanbilge")
MergifyAction.RequestReviews.fromUsers("armanbilge")
)
)

Expand Down
115 changes: 79 additions & 36 deletions mergify/src/main/scala/org/typelevel/sbt/mergify/MergifyAction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@

package org.typelevel.sbt.mergify

import cats.data.*
import cats.syntax.all.*
import io.circe.*
import io.circe.syntax.*
import cats.data._
import cats.syntax.all._
import io.circe._
import io.circe.syntax._
import org.typelevel.sbt.mergify.MergifyAction.RequestReviews._
import sbt.librarymanagement.Developer

sealed abstract class MergifyAction {
Expand Down Expand Up @@ -62,51 +63,93 @@ object MergifyAction {
}
}

final class RequestReviews(
val users: Either[NonEmptyList[String], NonEmptyMap[String, Int]],
val randomCount: Option[Int])
class RequestReviews private (
private val users: Option[OptionallyWeighted],
private val teams: Option[OptionallyWeighted],
private val usersFromTeams: Option[OptionallyWeighted],
private val randomCount: Option[Int])
extends MergifyAction {
override private[mergify] def name = "request_reviews"
}

object RequestReviews {
def apply(user: String, users: String*) =
new RequestReviews(NonEmptyList.of(user, users: _*).asLeft, None)
private def copy(
users: Option[OptionallyWeighted] = users,
teams: Option[OptionallyWeighted] = teams,
usersFromTeams: Option[OptionallyWeighted] = usersFromTeams,
randomCount: Option[Int] = randomCount): RequestReviews =
new RequestReviews(users, teams, usersFromTeams, randomCount) {}

def apply(weightedUser: (String, Int), weightedUsers: (String, Int)*) =
new RequestReviews(NonEmptyMap.of(weightedUser, weightedUsers: _*).asRight, None)
def andUsers(user: String, users: String*): RequestReviews =
copy(users = Unweighted(NonEmptyList.of(user, users: _*)).some)

def apply(randomCount: Int, user: String, users: String*) =
new RequestReviews(NonEmptyList.of(user, users: _*).asLeft, Option(randomCount))
def andUsers(user: (String, Int), users: (String, Int)*): RequestReviews =
copy(users = Weighted(NonEmptyList.of(user, users: _*)).some)

def apply(randomCount: Int, weightedUser: (String, Int), weightedUsers: (String, Int)*) =
new RequestReviews(
NonEmptyMap.of(weightedUser, weightedUsers: _*).asRight,
Option(randomCount)
)
def andTeams(team: String, teams: String*): RequestReviews =
copy(teams = Unweighted(NonEmptyList.of(team, teams: _*)).some)

def andTeams(team: (String, Int), teams: (String, Int)*): RequestReviews =
copy(teams = Weighted(NonEmptyList.of(team, teams: _*)).some)

def andUsersFromTeams(team: String, teams: String*): RequestReviews =
copy(usersFromTeams = Unweighted(NonEmptyList.of(team, teams: _*)).some)

def andUsersFromTeams(team: (String, Int), teams: (String, Int)*): RequestReviews =
copy(usersFromTeams = Weighted(NonEmptyList.of(team, teams: _*)).some)

def withRandomCount(count: Int): RequestReviews =
copy(randomCount = Option(count))

def andDevelopers(developers: List[Developer]): RequestReviews =
copy(users = NonEmptyList.fromList(developers.map(_.id)).map(Unweighted))
}

object RequestReviews {
def fromUsers(user: String, users: String*) =
new RequestReviews(Unweighted(NonEmptyList.of(user, users: _*)).some, None, None, None)
def fromUsers(user: (String, Int), users: (String, Int)*) =
new RequestReviews(Weighted(NonEmptyList.of(user, users: _*)).some, None, None, None)
def fromTeams(team: String, teams: String*) =
new RequestReviews(None, Unweighted(NonEmptyList.of(team, teams: _*)).some, None, None)
def fromTeams(team: (String, Int), teams: (String, Int)*) =
new RequestReviews(None, Weighted(NonEmptyList.of(team, teams: _*)).some, None, None)
def fromUsersOfTeams(team: String, teams: String*) =
new RequestReviews(None, None, Unweighted(NonEmptyList.of(team, teams: _*)).some, None)
def fromUsersOfTeams(team: (String, Int), teams: (String, Int)*) =
new RequestReviews(None, None, Weighted(NonEmptyList.of(team, teams: _*)).some, None)

def apply(developers: List[Developer]) =
new RequestReviews(
developers
.map(_.id)
.toNel
.getOrElse(throw new RuntimeException("developers must be non-empty"))
.asLeft,
Unweighted(
developers
.map(_.id)
.toNel
.getOrElse(throw new RuntimeException("developers must be non-empty"))
).some,
None,
None,
None)

def apply(developers: List[Developer], randomCount: Int) =
new RequestReviews(
developers
.map(_.id)
.toNel
.getOrElse(throw new RuntimeException("developers must be non-empty"))
.asLeft,
randomCount.some)

implicit def encoder: Encoder[RequestReviews] =
Encoder.forProduct2("users", "random_count") { requestReviews =>
(requestReviews.users.fold(_.asJson, _.asJson), requestReviews.randomCount)
Encoder.forProduct4("users", "teams", "users_from_teams", "random_count") {
requestReviews =>
(
requestReviews.users,
requestReviews.teams,
requestReviews.usersFromTeams,
requestReviews.randomCount
)
}

private sealed trait OptionallyWeighted
private case class Weighted(value: NonEmptyList[(String, Int)]) extends OptionallyWeighted
private case class Unweighted(value: NonEmptyList[String]) extends OptionallyWeighted

private object OptionallyWeighted {
implicit val encoder: Encoder[OptionallyWeighted] = {
case Weighted(value) => value.asJson
case Unweighted(value) => value.asJson
}
}
}

object Update extends MergifyAction {
Expand Down

0 comments on commit b106844

Please sign in to comment.