sbt-github-actions icon indicating copy to clipboard operation
sbt-github-actions copied to clipboard

Plugin to maintain .mergify.yml

Open nafg opened this issue 5 years ago • 10 comments

As a possible alternative to #39, would there be any interest in something like the following rough draft? Basically it keeps the jobs in .mergify.yml up to date when running githubWorkflowGenerate:

import java.io.{File, FileInputStream}
import java.{util => ju}

import scala.collection.JavaConverters._
import scala.util.matching.Regex

import org.yaml.snakeyaml.Yaml
import sbt.AutoPlugin
import sbt.io.IO
import sbtghactions.GenerativeKeys.{githubWorkflowGenerate, githubWorkflowGeneratedCI}
import sbtghactions.GenerativePlugin


object Mergify extends AutoPlugin {
  override def requires = GenerativePlugin
  override def trigger = allRequirements

  type Dict = ju.Map[String, AnyRef]

  override def projectSettings = Seq(
    githubWorkflowGenerate := {
      githubWorkflowGenerate.value
      githubWorkflowGeneratedCI.value
        .find(_.id == "build")
        .foreach { job =>
          val yaml = new Yaml
          val res = yaml.load[Dict](new FileInputStream(".mergify.yml"))
          val conditions =
            res
              .get("pull_request_rules").asInstanceOf[ju.List[Dict]].asScala.map(_.asScala)
              .find(_ ("name") == "Automatically merge successful scala-steward PRs").get
              .apply("conditions").asInstanceOf[ju.List[String]].asScala

          val existing = conditions.filter(_.matches(s"status-success=${Regex.quote(job.name)} \\(.*\\)"))
          conditions --= existing

          val concreteJobNames = for (o <- job.oses; s <- job.scalas; v <- job.javas) yield s"${job.name} ($o, $s, $v)"

          conditions ++= concreteJobNames.map(name => s"status-success=$name")

          IO.write(new File(".mergify.yml"), yaml.dumpAsMap(res))
        }
    }
  )
}

nafg avatar Dec 28 '20 19:12 nafg

This is a really really interesting idea! Particularly since we can make it work nicely with scala-steward and such in the very common case. Is it best to have something like that organizationally within this plugin, or is it better to distribute it separately (e.g. sbt-mergify)?

djspiewak avatar Jan 13 '21 15:01 djspiewak

Having it as part of sbt-github-actions initially will be less work / faster to iterate I think. Can always split it out if there's demand but I suspect that most OSS projects will be using both GHA and mergify

jatcwang avatar Feb 07 '21 13:02 jatcwang

Okay I'm definitely convinced that this is worth doing. I'd be fine with either having it here or in a separate project which depends on this one.

djspiewak avatar Mar 07 '21 21:03 djspiewak

If people want my sloppy version I would be very happy if someone can tell me the quickest way to publish it somewhere people can use it.

To make a more principled version we first need some sort of behavior spec.

nafg avatar Mar 07 '21 23:03 nafg

(once that's coded up it may be worthy of being included here.)

nafg avatar Mar 07 '21 23:03 nafg

Today I've been working on a library to generate Mergify files in a principled manner. I haven't written a DSL yet so code looks like this right now:

  val data =
    Mergify(
      pullRequestRules =
        List(
          PullRequestRule(
            name = "automatic merge successful scala-steward PRs",
            conditions =
              List(
                Condition(Attribute.Author, Some(Operator.Equal -> "scala-steward")),
                Condition(Attribute.CheckSuccess, Some(Operator.Equal -> "Travis CI - Pull Request"))
              ),
            actions =
              ActionSet(
                List(
                  Action.Merge(
                    strict = Some(Json.fromBoolean(true))
                  )
                )
              )
          )
        )
    )

nafg avatar Mar 15 '21 02:03 nafg

Now available:

    resolvers += "jitpack" at "https://jitpack.io"
    libraryDependencies += "com.github.nafg" % "mergify-yaml" % "0.1.0"

Currently it is only built for scala 2.12 because my use case is in sbt builds.

Demo: https://github.com/nafg/mergify-yaml/blob/master/src/test/scala/io/github/nafg/mergify/Demo.scala

nafg avatar Mar 15 '21 03:03 nafg

With a DSL published in 0.2.0, my original code (that I started this issue with) can be replaced with:

import io.github.nafg.mergify.dsl._

import sbt._
import sbtghactions.GenerativePlugin
import sbtghactions.GenerativePlugin.autoImport._


object WriteMergify extends AutoPlugin {
  override def requires = GenerativePlugin
  override def trigger = allRequirements
  override def projectSettings = Seq(
    githubWorkflowGenerate := {
      githubWorkflowGenerate.value
      for (job <- githubWorkflowGeneratedCI.value if job.id == "build")
        IO.write(
          file(".mergify.yml"),
          mergify
            .withRule("Automatically merge successful scala-steward PRs")(
              (Attr.Author :== "scala-steward") +:
                (for (o <- job.oses; s <- job.scalas; v <- job.javas) yield
                  Attr.CheckSuccess :== s"${job.name} ($o, $s, $v)"): _*
            )(Action.Merge(strict = true))
            .toYaml
        )
    }
  )
}

It would be nice if I didn't have to generate the matrix job names myself, not to mention comparing the job id to a magic string. If those were provided by this plugin, the code would be even shorter.

nafg avatar Mar 15 '21 05:03 nafg

It's now on maven central, so

- resolvers += "jitpack" at "https://jitpack.io"
- libraryDependencies += "com.github.nafg" % "mergify-yaml" % "0.1.0"
+ libraryDependencies += "io.github.nafg.mergify" %% "mergify-writer" % "0.2.1"

nafg avatar Mar 19 '21 16:03 nafg

The snippet in https://github.com/djspiewak/sbt-github-actions/issues/46#issuecomment-799127306 is no longer valid in 0.14.x: $v needs to be changed to ${v.render}.

Since it doesn't seem like it will be integrated into this plugin, I've now published the updated snippet as its own sbt plugin. To use it I'm applying the following change:

diff --git a/project/WriteMergify.scala b/project/WriteMergify.scala
deleted file mode 100644
index f99df17..0000000
--- a/project/WriteMergify.scala
+++ /dev/null
@@ -1,28 +0,0 @@
-import io.github.nafg.mergify.dsl._
-import sbt._
-import sbtghactions.GenerativePlugin
-import sbtghactions.GenerativePlugin.autoImport._
-
-
-object WriteMergify extends AutoPlugin {
-  override def requires = GenerativePlugin
-
-  override def trigger = allRequirements
-
-  override def projectSettings = Seq(
-    githubWorkflowGenerate := {
-      githubWorkflowGenerate.value
-      for (job <- githubWorkflowGeneratedCI.value if job.id == "build")
-        IO.write(
-          file(".mergify.yml"),
-          mergify
-            .withRule("Automatically merge successful scala-steward PRs")(
-              (Attr.Author :== "scala-steward") +:
-                (for (o <- job.oses; s <- job.scalas; v <- job.javas) yield
-                  Attr.CheckSuccess :== s"${job.name} ($o, $s, $v)"): _*
-            )(Action.Merge(strict = true))
-            .toYaml
-        )
-    }
-  )
-}
diff --git a/project/build-build.sbt b/project/build-build.sbt
index e60bce8..e7a4bfa 100644
--- a/project/build-build.sbt
+++ b/project/build-build.sbt
@@ -1,2 +1 @@
 libraryDependencies += "org.jsoup" % "jsoup" % "1.14.3"
-libraryDependencies += "io.github.nafg.mergify" %% "mergify-writer" % "0.3.0"
diff --git a/project/plugins.sbt b/project/plugins.sbt
index cf9fab0..1ad8c6d 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,2 +1,2 @@
 addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10")
-addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.13.0")
+addSbtPlugin("io.github.nafg.mergify" % "sbt-mergify-github-actions" % "0.3.0")

You may need to run sbt githubWorkflowGenerate, of course.

nafg avatar Dec 19 '21 18:12 nafg