Skip to content

Commit

Permalink
Merge pull request #232 from guardian/adopt-GHA-Scala-Library-Release…
Browse files Browse the repository at this point in the history
…-Workflow

Adopt GHA-Scala-Library-Release-Workflow
  • Loading branch information
rtyley authored Jan 25, 2024
2 parents d892745 + d037761 commit 553a91d
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 240 deletions.
90 changes: 17 additions & 73 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,91 +1,35 @@
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 }}
scala-maven-release:
name: Maven 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 }}

release_production_sonatype:
#if: "!github.event.release.prerelease"
typescript-npm-release:
name: NPM Release
needs: scala-maven-release
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
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: corretto
java-version: 11
cache: sbt
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
registry-url: https://registry.npmjs.org
- name: Release Production to Sonatype
- name: Release Typescript to 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 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"
sbt "project typescript" "releaseNpm ${{ needs.scala-maven-release.outputs.RELEASE_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_TYPE: ${{ needs.scala-maven-release.outputs.RELEASE_TYPE }}
15 changes: 4 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[![content-api-models-scala Scala version support](https://index.scala-lang.org/guardian/content-api-models/content-api-models-scala/latest-by-scala-version.svg?platform=jvm)](https://index.scala-lang.org/guardian/content-api-models/content-api-models-scala)
[![content-api-models-json Scala version support](https://index.scala-lang.org/guardian/content-api-models/content-api-models-json/latest-by-scala-version.svg?platform=jvm)](https://index.scala-lang.org/guardian/content-api-models/content-api-models-json)
[![CI](https://github.com/guardian/content-api-models/actions/workflows/ci.yml/badge.svg)](https://github.com/guardian/content-api-models/actions/workflows/ci.yml)
[![Release](https://github.com/guardian/content-api-models/actions/workflows/release.yml/badge.svg)](https://github.com/guardian/content-api-models/actions/workflows/release.yml)

## Version Info

Expand All @@ -11,18 +12,10 @@

# Publishing a new release

This repository has a Github Action that will create new releases for Sonatype and NPM when a new release is created in Github.
This repo uses [`gha-scala-library-release-workflow`](https://github.com/guardian/gha-scala-library-release-workflow)
to automate publishing releases (both full & preview releases) - see
[**Making a Release**](https://github.com/guardian/gha-scala-library-release-workflow/blob/main/docs/making-a-release.md).

- Push the branch with the changes you want to release to Github.
- Begin creating a new release (here's a [quick link.](https://github.com/guardian/flexible-model/releases/new))
- Set the `Target` to your branch.
- Create a tag:
- - For a production release, the tag should be the new version number, e.g. `vX.X.X`. Beta releases are production releases – for example `v1.0.0-beta.0`.
- - For a snapshot release, the tag should ideally have the format `vX.X.X-SNAPSHOT`.
- **If you are intending to release a snapshot,** double-check that the "Set as pre-release" box is ticked.
- Click the "Publish release" button. The action will trigger, and your release should be on its way.

To release a package from your local machine, follow the instructions for [publishing a new version to Maven Central via Sonatype](https://docs.google.com/document/d/1rNXjoZDqZMsQblOVXPAIIOMWuwUKe3KzTCttuqS7AcY/edit#).

## Information about built bundles

Expand Down
184 changes: 30 additions & 154 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,22 @@ 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 npmPreviewReleaseTagMaybe = if (sys.env.get("RELEASE_TYPE").contains("PREVIEW_FEATURE_BRANCH")) {
Seq(scroogeTypescriptPublishTag := "preview")
} else Seq.empty

lazy val typescript = (project in file("ts"))
.enablePlugins(ScroogeTypescriptGen)
.settings(commonSettings)
.settings(npmBetaReleaseTagMaybe)
.settings(artifactProductionSettings)
.settings(npmPreviewReleaseTagMaybe)
.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 553a91d

Please sign in to comment.