Skip to content

Commit

Permalink
Adopt GHA-Scala-Library-Release-Workflow (Scala Maven release only)
Browse files Browse the repository at this point in the history
This change adopts `gha-scala-library-release-workflow` for publishing releases,
replacing some of the work done in PR #229 and providing some improvements:

* Automatic version-numbering based on automated compatibility-assessment by sbt-version-policy
* Standardisation with the other projects across the Guardian that have also adopted the workflow
* Reduced configuration (fewer sbt settings, and less workflow yaml)

This specific commit only provides Scala Maven release, removing NPM release
capability, but NPM release capability is returned in the next commit.
  • Loading branch information
rtyley committed Jan 24, 2024
1 parent d892745 commit 1e82bec
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 243 deletions.
93 changes: 7 additions & 86 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,91 +1,12 @@
name: Publish to Sonatype and NPM
name: Release

on:
workflow_dispatch:
release:
types: [published]

jobs:
release_snapshot_sonatype:
if: "github.event.release.prerelease"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
base: main #see https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#pull-request-events
- uses: actions/setup-java@v3
with:
distribution: corretto
java-version: 11
cache: sbt
- uses: actions/setup-node@v3
with:
node-version-file: .nvmrc
# We cannot cache our environment, as it is dynamically generated by the plugin
- name: Get tags
run: git fetch --tags origin
- name: Release pre-release version to Sonatype and NPM
run: |
VERSION=$(git describe --tags | cut -f2 -d"@")
if [[ ${VERSION:0:1} == "v" ]] ; then
VERSION=${VERSION:1}
fi
if [[ ${VERSION: -9} != "-SNAPSHOT" ]] ; then
echo "Version must end in -SNAPSHOT. Adding -SNAPSHOT suffix"
VERSION="$VERSION-SNAPSHOT"
fi
echo $PGP_SECRET | base64 --decode | gpg --batch --import
export GPG_TTY=$(tty)
echo "Releasing version $VERSION Sonatype as snapshot"
# No need to support NPM releases – there's no direct analogue to a SNAPSHOT release.
# Beta releases are classed as 'production' releases.
sbt -J-Xss32M -DRELEASE_TYPE=snapshot "clean" "release cross release-version $VERSION with-defaults"
env:
# We use armour formatted files for keys, but we know the newlines they contain don't survive
# passing through environment vars, so this secret should be an armour-formatted PGP key passed
# through base64.
PGP_SECRET: ${{ secrets.PGP_SECRET }}
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}

release_production_sonatype:
#if: "!github.event.release.prerelease"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
base: main #see https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#pull-request-events
- uses: actions/setup-java@v3
with:
distribution: corretto
java-version: 11
cache: sbt
- uses: actions/setup-node@v3
with:
node-version-file: .nvmrc
registry-url: https://registry.npmjs.org
- name: Release Production to Sonatype
run: |
VERSION=$(git describe --tags | cut -f2 -d"@")
if [[ ${VERSION:0:1} == "v" ]] ; then
VERSION=${VERSION:1}
fi
if [[ ${VERSION: -9} == "-SNAPSHOT" ]] ; then
echo "Version must NOT end in -SNAPSHOT."
exit 1
fi
echo $PGP_SECRET | base64 --decode | gpg --batch --import
export GPG_TTY=$(tty)
echo "Releasing version $VERSION Sonatype as production"
yes | sbt -J-Xss32M "clean" "release cross release-version $VERSION with-defaults" "project typescript" "releaseNpm $VERSION"
env:
PGP_SECRET: ${{ secrets.PGP_SECRET }}
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
release:
uses: guardian/gha-scala-library-release-workflow/.github/workflows/reusable-release.yml@main
permissions: { contents: write, pull-requests: write }
secrets:
SONATYPE_PASSWORD: ${{ secrets.AUTOMATED_MAVEN_RELEASE_SONATYPE_PASSWORD }}
PGP_PRIVATE_KEY: ${{ secrets.AUTOMATED_MAVEN_RELEASE_PGP_SECRET }}
181 changes: 26 additions & 155 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sbt.Keys._
import sbt.Keys.*
import sbt.{Test, Tests}
import sbtrelease.ReleaseStateTransformations._
import sbtrelease.{Version, versionFormatError}
import sbtrelease.ReleaseStateTransformations.*
import sbtversionpolicy.withsbtrelease.ReleaseVersion

// dependency versions
val contentEntityVersion = "2.2.1"
Expand All @@ -23,163 +23,47 @@ val betaReleaseSuffix = "-beta.0"
val snapshotReleaseType = "snapshot"
val snapshotReleaseSuffix = "-SNAPSHOT"

lazy val mavenSettings = Seq(
pomExtra := (
<url>https://github.com/guardian/content-api-models</url>
<scm>
<connection>scm:git:git@github.com:guardian/content-api-models.git</connection>
<developerConnection>scm:git:git@github.com:guardian/content-api-models.git</developerConnection>
<url>git@github.com:guardian/content-api-models.git</url>
</scm>
<developers>
<developer>
<id>cb372</id>
<name>Chris Birchall</name>
<url>https://github.com/cb372</url>
</developer>
<developer>
<id>mchv</id>
<name>Mariot Chauvin</name>
<url>https://github.com/mchv</url>
</developer>
<developer>
<id>LATaylor-guardian</id>
<name>Luke Taylor</name>
<url>https://github.com/LATaylor-guardian</url>
</developer>
<developer>
<id>regiskuckaertz</id>
<name>Regis Kuckaertz</name>
<url>https://github.com/regiskuckaertz</url>
</developer>
<developer>
<id>annebyrne</id>
<name>Anne Byrne</name>
<url>https://github.com/annebyrne</url>
</developer>
<developer>
<id>justinpinner</id>
<name>Justin Pinner</name>
<url>https://github.com/justinpinner</url>
</developer>
</developers>
),
publishTo := sonatypePublishToBundle.value,
publishConfiguration := publishConfiguration.value.withOverwrite(true),
publishMavenStyle := true,
Test / publishArtifact := false,
pomIncludeRepository := { _ => false }
)

lazy val versionSettingsMaybe = {
sys.props.get("RELEASE_TYPE").map {
case v if v == betaReleaseType => betaReleaseSuffix
case v if v == snapshotReleaseType => snapshotReleaseSuffix
}.map { suffix =>
releaseVersion := {
ver => Version(ver).map(_.withoutQualifier.string).map(_.concat(suffix)).getOrElse(versionFormatError(ver))
}
}.toSeq
}

lazy val commonSettings = Seq(
scalaVersion := "2.13.2",
// downgrade scrooge reserved word clashes to warnings
lazy val artifactProductionSettings = Seq(
scalaVersion := "2.13.12",
// This old attempt to downgrade scrooge reserved word clashes is now insufficient... https://github.com/twitter/scrooge/issues/259#issuecomment-1900743695
Compile / scroogeDisableStrict := true,
// scrooge 21.3.0: Builds are now only supported for Scala 2.12+
// https://twitter.github.io/scrooge/changelog.html#id11
crossScalaVersions := Seq("2.12.11", scalaVersion.value),
releasePublishArtifactsAction := PgpKeys.publishSigned.value,
crossScalaVersions := Seq("2.12.18", scalaVersion.value),
organization := "com.gu",
licenses := Seq("Apache v2" -> url("http://www.apache.org/licenses/LICENSE-2.0.html")),
resolvers ++= Resolver.sonatypeOssRepos("public"),
Test / testOptions +=
Tests.Argument(TestFrameworks.ScalaTest, "-u", s"test-results/scala-${scalaVersion.value}", "-o")
) ++ mavenSettings ++ versionSettingsMaybe

/*
Trialling being able to release snapshot versions from WIP branch without updating back to git
e.g. $ sbt [-DRELEASE_TYPE=snapshot|candidate] release cross
or
$ sbt [-DRELEASE_TYPE=snapshot|candidate]
sbt> release cross
sbt> project typeScript
sbt> releaseNpm <version>
One downside here is that you'd have to (I think) exit and re-start sbt without the -D when you
want to run a non-snapshot release. This is probably fine because we only run releases from
our main/master branch when changes are merged in normal circumstances.
*/

lazy val checkReleaseType: ReleaseStep = ReleaseStep({ st: State =>
val releaseType = sys.props.get("RELEASE_TYPE").map {
case v if v == betaReleaseType => betaReleaseType.toUpperCase
case v if v == snapshotReleaseType => snapshotReleaseType.toUpperCase
}.getOrElse("PRODUCTION")

SimpleReader.readLine(s"This will be a $releaseType release. Continue? [y/N]: ") match {
case Some(v) if Seq("Y", "YES").contains(v.toUpperCase) => // we don't care about the value - it's a flow control mechanism
case _ => sys.error(s"Release aborted by user!")
}
// we haven't changed state, just pass it on if we haven't thrown an error from above
st
})

lazy val releaseProcessSteps: Seq[ReleaseStep] = {
val commonSteps:Seq[ReleaseStep] = Seq(
checkSnapshotDependencies,
inquireVersions,
runClean,
runTest,
setReleaseVersion,
)

val localExtraSteps:Seq[ReleaseStep] = Seq(
commitReleaseVersion,
tagRelease,
publishArtifacts,
setNextVersion,
commitNextVersion
)

val snapshotSteps:Seq[ReleaseStep] = Seq(
publishArtifacts,
releaseStepCommand("sonatypeReleaseAll")
)

val prodSteps:Seq[ReleaseStep] = Seq(
releaseStepCommandAndRemaining("+publishSigned"),
releaseStepCommand("sonatypeBundleRelease")
)

val localPostRelease:Seq[ReleaseStep] = Seq(
pushChanges,
)

(sys.props.get("RELEASE_TYPE"), sys.env.get("CI")) match {
case (Some(v), None) if v == snapshotReleaseType => commonSteps ++ localExtraSteps ++ snapshotSteps ++ localPostRelease
case (_, None) => commonSteps ++ localExtraSteps ++ prodSteps ++ localPostRelease
case (Some(v), _) if v == snapshotReleaseType => commonSteps ++ snapshotSteps
case (_, _)=> commonSteps ++ prodSteps
}
}
)

/**
* Root project
*/
lazy val root = Project(id = "root", base = file("."))
.settings(commonSettings)
.aggregate(models, json, scala)
.settings(
publishArtifact := false,
releaseProcess := releaseProcessSteps
publish / skip := true,
releaseVersion := ReleaseVersion.fromAggregatedAssessedCompatibilityWithLatestRelease().value,
releaseProcess := Seq[ReleaseStep](
checkSnapshotDependencies,
inquireVersions,
runClean,
runTest,
setReleaseVersion,
commitReleaseVersion,
tagRelease,
setNextVersion,
commitNextVersion
)
)

/**
* Thrift models project
*/
lazy val models = Project(id = "content-api-models", base = file("models"))
.settings(commonSettings)
.settings(artifactProductionSettings)
.disablePlugins(ScroogeSBT)
.settings(
description := "Scala models for the Guardian's Content API",
Expand All @@ -195,7 +79,7 @@ lazy val models = Project(id = "content-api-models", base = file("models"))
*/
lazy val scala = Project(id = "content-api-models-scala", base = file("scala"))
.dependsOn(models)
.settings(commonSettings)
.settings(artifactProductionSettings)
.settings(
description := "Generated classes of the Scala models for the Guardian's Content API",
scalacOptions ++= Seq("-deprecation", "-unchecked"),
Expand Down Expand Up @@ -225,7 +109,7 @@ lazy val scala = Project(id = "content-api-models-scala", base = file("scala"))
*/
lazy val json = Project(id = "content-api-models-json", base = file("json"))
.dependsOn(scala % "provided")
.settings(commonSettings)
.settings(artifactProductionSettings)
.settings(
description := "Json parser for the Guardian's Content API models",
libraryDependencies ++= Seq(
Expand All @@ -243,30 +127,17 @@ lazy val json = Project(id = "content-api-models-json", base = file("json"))

lazy val benchmarks = Project(id = "benchmarks", base = file("benchmarks"))
.dependsOn(json, scala)
.settings(commonSettings)
.settings(artifactProductionSettings)
.enablePlugins(JmhPlugin)
.settings(
libraryDependencies += "com.google.guava" % "guava" % "19.0",
Jmh / javaOptions ++= Seq("-server", "-Xms4G", "-Xmx4G", "-XX:+UseG1GC", "-XX:-UseBiasedLocking"),
publishArtifact := false
)

lazy val npmBetaReleaseTagMaybe =
sys.props.get("RELEASE_TYPE").map {
case v if v == betaReleaseType =>
// Why hard-code "beta" instead of using the value of the variable? That's to ensure it's always presented as
// --tag beta to the npm release process provided by the ScroogeTypescriptGen plugin regardless of how we identify
// a beta release here
scroogeTypescriptPublishTag := "beta"

case v if v == snapshotReleaseType =>
scroogeTypescriptPublishTag := "snapshot"
}.toSeq

lazy val typescript = (project in file("ts"))
.enablePlugins(ScroogeTypescriptGen)
.settings(commonSettings)
.settings(npmBetaReleaseTagMaybe)
.settings(artifactProductionSettings)
.settings(
name := "content-api-models-typescript",
scroogeTypescriptNpmPackageName := "@guardian/content-api-models",
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.9.6
sbt.version=1.9.8
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0")
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
addSbtPlugin("ch.epfl.scala" % "sbt-version-policy" % "3.2.0")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.10")
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.5")

Expand Down
1 change: 1 addition & 0 deletions version.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ThisBuild / version := "18.0.1-SNAPSHOT"

0 comments on commit 1e82bec

Please sign in to comment.