From d7d77190375a3a49b2a498e107dbb19bab9ac73e Mon Sep 17 00:00:00 2001 From: Grebennikov Roman Date: Mon, 7 Sep 2026 18:05:50 +0200 Subject: [PATCH] setup auto release to sonatype --- .github/workflows/ci.yml | 3 +- .github/workflows/release.yml | 60 +++++++++++++++++++++++++++++++++++ README.md | 14 ++++++++ build.sbt | 14 ++++++-- macros/build.sbt | 8 ++--- project/plugins.sbt | 2 ++ 6 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2e122b..57cdfb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,8 @@ jobs: steps: - uses: actions/checkout@v7 with: - lfs: true + fetch-depth: 0 + fetch-tags: true - uses: actions/cache@v6 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1254806 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,60 @@ +name: Release + +on: + push: + tags: + - '[0-9]+.[0-9]+.[0-9]+*' # 0.4.0, 0.4.0-M1, 0.4.0-RC1 — no v prefix + +permissions: + contents: write # create release + upload assets + +jobs: + release: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + with: + # sbt-dynver derives the version from `git describe`, which needs tags + history + fetch-depth: 0 + fetch-tags: true + + - uses: actions/cache@v6 + with: + path: | + ~/.sbt + ~/.m2 + ~/.ivy2 + ~/.cache + key: ${{ runner.os }}-build-${{ hashFiles('build.sbt', 'project/**') }} + + - uses: actions/setup-java@v6 + with: + distribution: temurin + java-version: 21 + + - uses: sbt/setup-sbt@v1 + + - name: Import PGP key + run: echo "$PGP_SECRET" | gpg --batch --import + env: + PGP_SECRET: ${{ secrets.PGP_SECRET }} + + - name: Verify version is derived from the tag + run: sbt -mem 3000 assertTagVersion + + - name: Run tests + run: sbt -mem 3000 "+test" + + - name: Publish to Maven Central + run: sbt -mem 3000 "+macros/publishSigned" sonaRelease + env: + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + + - name: Create GitHub release + uses: softprops/action-gh-release@v3 + with: + generate_release_notes: true + prerelease: ${{ contains(github.ref_name, '-') }} # 0.4.0-M1 → pre-release + files: target/out/jvm/*/cfor/cfor_*-${{ github.ref_name }}.jar diff --git a/README.md b/README.md index 86bdbae..c9b6c5e 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,20 @@ The [benchmark](notfound) is done on Scala 2.13.5, AdoptOpenJDK 11.0.10 x64. [info] scalaWhileSum:·gc.alloc.rate.norm 1000 avgt 30 ≈ 10⁻³ B/op ``` +## Releasing + +The version is derived from the git tag by sbt-dynver. Pushing a tag publishes signed jars to Maven Central +and creates a GitHub release: +```bash +git tag 0.4.0 && git push origin 0.4.0 +``` + +The release workflow expects these repository secrets: + +* `SONATYPE_USERNAME` / `SONATYPE_PASSWORD`: a [Central Portal](https://central.sonatype.com) user token +* `PGP_SECRET`: armored private key (`gpg --armor --export-secret-keys `), public key uploaded to a keyserver +* `PGP_PASSPHRASE`: passphrase of that key + ## License This project is released under the Apache 2.0 license, as specified in the LICENSE file. diff --git a/build.sbt b/build.sbt index 031df24..b874f6c 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,15 @@ -val cforVersion = "0.3" +ThisBuild / dynverVTagPrefix := false +ThisBuild / versionScheme := Some("early-semver") + +ThisBuild / credentials ++= (for { + user <- sys.env.get("SONATYPE_USERNAME") + pass <- sys.env.get("SONATYPE_PASSWORD") +} yield Credentials("Sonatype Central Portal", "central.sonatype.com", user, pass)).toList + +lazy val assertTagVersion = taskKey[Unit]("assert that version is derived from an exact git tag") +assertTagVersion := { + if (isSnapshot.value) sys.error(s"version ${version.value} is not an exact git tag version") +} def isScala2(scalaVersion: String): Boolean = CrossVersion.partialVersion(scalaVersion) match { @@ -9,7 +20,6 @@ def isScala2(scalaVersion: String): Boolean = lazy val sharedSettings = Seq( crossScalaVersions := Seq("2.13.18", "3.9.0"), organization := "io.github.metarank", - version := cforVersion, scalaVersion := "2.13.18", scalacOptions ++= Seq("-feature", "-deprecation"), libraryDependencies ++= (if (isScala2(scalaVersion.value)) { diff --git a/macros/build.sbt b/macros/build.sbt index b91ac86..1b50bff 100644 --- a/macros/build.sbt +++ b/macros/build.sbt @@ -4,15 +4,15 @@ publishMavenStyle := true publishTo := localStaging.value -licenses := Seq("APL2" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")) +licenses := Seq("APL2" -> uri("http://www.apache.org/licenses/LICENSE-2.0.txt")) -homepage := Some(url("https://github.com/metarank/cfor")) +homepage := Some(uri("https://github.com/metarank/cfor")) scmInfo := Some( ScmInfo( - url("https://github.com/metarank/cfor"), + uri("https://github.com/metarank/cfor"), "scm:git@github.com:metarank/cfor.git" ) ) developers := List( - Developer(id = "romangrebennikov", name = "Roman Grebennikov", email = "grv@dfdx.me", url = url("https://dfdx.me/")) + Developer(id = "romangrebennikov", name = "Roman Grebennikov", email = "grv@dfdx.me", url = uri("https://dfdx.me/")) ) diff --git a/project/plugins.sbt b/project/plugins.sbt index 39dd2fc..d16a517 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,3 +2,5 @@ addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.8") addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.2") addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.7.0") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.6.2") + +addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.1")