Skip to content

Commit

Permalink
Merge pull request #162 from guardian/github-release
Browse files Browse the repository at this point in the history
Release via GitHub actions
  • Loading branch information
tonytw1 authored Nov 9, 2023
2 parents c334e99 + a2122bd commit 90835a8
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 144 deletions.
70 changes: 70 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Release Sonatype

on:
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
- name: Release Snapshot (prerelease) 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 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"
yes | sbt -DRELEASE_TYPE=snapshot "clean" "release cross release-version $VERSION with-defaults"
env:
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
- 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 -DRELEASE_TYPE=production "clean" "release cross release-version $VERSION with-defaults"
env:
PGP_SECRET: ${{ secrets.PGP_SECRET }}
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
83 changes: 46 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,40 +27,49 @@ Prior to releasing, you will need to ensure that:
- you have the followed the [guide](https://docs.google.com/document/d/1rNXjoZDqZMsQblOVXPAIIOMWuwUKe3KzTCttuqS7AcY/edit)
for publishing to Maven and Sonatype

### Releasing

To release to Maven Central:
```sbtshell
release cross
```
This will release these artifacts:
- `content-atom-model-thrift-$version.jar` contains only the Thrift files
- `content-atom-model_2.13-$version.jar` contains the Thrift files and Scrooge-generated Scala 2.13 classes
- `content-atom-model_2.12-$version.jar` contains the Thrift files and Scrooge-generated Scala 2.12 classes

Note that support for scala 2.11 ended with scrooge 21.3, so we won't output
- `content-atom-model_2.11-$version.jar`
any more.

To release to NPM:
```sbtshell
project typescriptClasses
releaseNpm <version released to Maven>
```

If you need to make a beta release build available for testing elsewhere, start sbt with
```
$ sbt -DRELEASE_TYPE=beta
```
then follow the above release steps as usual. You'll be prompted that this is a BETA release
and for a version number that looks like 1.2.3-beta.n where n is the beta version number
you'll specify. This isn't really tracked so make sure it's a new build by checking Maven and NPM first.

When releasing the typescript classes to NPM, you'll manually type the version number to match what you
released to Sonatype/Maven for Scala. Our `sbt-scrooge-typescript` sbt plugin takes care of applying a `--tag beta`
to the NPM release when the `RELEASE_TYPE=beta` system property is available.

To cross release locally use
```
$ sbt '+publishLocal'
```

#### Non-production releases:

The easiest way to release a snapshot version is via the github UI.
[This](https://github.com/guardian/content-api-firehose-client/pull/28/373) PR introduced the ability to use a github action to trigger the release.

The steps you should take are:
- Push the branch with the changes you want to release to Github.
- [Click here](https://github.com/guardian/content-api-firehose-client/releases/new?prerelease=true) to create prerelease using Github releases.

- You must then:
- Set the Target to your branch.
- Create a tag for the snapshot release (the tag can be created from this same UI if it doesn't already exist).
- The tag should ideally have format "vX.X.X-SNAPSHOT".
- Double-check that the "Set as pre-release" box is ticket.
- To automatically release the snapshot to sonatype then click the "Publish release" button.

And then manually release the npm module:
`npm i -g typescript && sbt 'project typescriptClasses; releaseNpm X.X.X-SNAPSHOT'`


#### Production releases:

When your changes are done and tested and you're ready to release a new production version, edit the `version.sbt` file to reflect the version you are about to release.

Typically this should just require the removal of the -SNAPSHOT part, but check in [maven](https://repo1.maven.org/maven2/com/gu/content-api-firehose-client_2.13/) to make sure nobody else has released this version before you.

Open a PR.

When your PR is approved, merge it to `main` and ensure the build actions complete successfully.

Then, on the [releases](https://github.com/guardian/content-api-firehose-client/releases) page:
- Choose `Draft a new release`
- Create a new tag of the version number e.g. `v1.0.10`
- Set the target to the `main` branch
- Add a release title (the version number again is fine)
- Add an optional description
- Ensure that `Set as pre-release` is **unchecked**
- Click the `Publish release` button

When the release process has finished, pull the updated `main` branch locally and update the `version.sbt` file to reflect the next build number, e.g. `1.0.11-SNAPSHOT` and commit that directly back to `main` - there's no need to open a PR for that.

When your release shows up on [maven](https://repo1.maven.org/maven2/com/gu/content-api-firehose-client_2.13/) the updated version can be referenced in client code.

And then manually release the npm module:
`npm i -g typescript && sbt 'project typescriptClasses; releaseNpm X.X.X'`
126 changes: 24 additions & 102 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,123 +5,54 @@ val contentEntityVersion = "2.2.1"
val scroogeVersion = "22.1.0" // remember to also update plugins.sbt if the scrooge version changes
val thriftVersion = "0.15.0" // remember to also update package.json if the thrift version changes

val betaReleaseType = "beta"
val betaReleaseSuffix = "-beta.0"

lazy val versionSettingsMaybe = {
sys.props.get("RELEASE_TYPE").map {
case v if v == betaReleaseType => betaReleaseSuffix
}.map { suffix =>
releaseVersion := {
ver => Version(ver).map(_.withoutQualifier.string).map(_.concat(suffix)).getOrElse(versionFormatError(ver))
}
}.toSeq
}
//https://github.com/xerial/sbt-sonatype/issues/103
publishTo := sonatypePublishToBundle.value

lazy val mavenSettings = Seq(
pomExtra := (
<url>https://github.com/guardian/content-atom</url>
<developers>
<developer>
<id>paulmr</id>
<name>Paul Roberts</name>
<url>https://github.com/paulmr</url>
</developer>
<developer>
<id>LATaylor-guardian</id>
<name>Luke Taylor</name>
<url>https://github.com/LATaylor-guardian</url>
</developer>
<developer>
<id>mchv</id>
<name>Mariot Chauvin</name>
<url>https://github.com/mchv</url>
</developer>
<developer>
<id>tomrf1</id>
<name>Tom Forbes</name>
<url>https://github.com/tomrf1</url>
</developer>
<developer>
<id>annebyrne</id>
<name>Anne Byrne</name>
<url>https://github.com/annebyrne</url>
</developer>
<developer>
<id>regiskuckaertz</id>
<name>Regis Kuckaertz</name>
<url>https://github.com/regiskuckaertz</url>
</developer>
<developer>
<id>justinpinner</id>
<name>Justin Pinner</name>
<url>https://github.com/justinpinner</url>
</developer>
</developers>
),
licenses := Seq("Apache V2" -> url("http://www.apache.org/licenses/LICENSE-2.0.html")),
publishTo := sonatypePublishToBundle.value,
publishConfiguration := publishConfiguration.value.withOverwrite(true)
)

lazy val checkReleaseType: ReleaseStep = ReleaseStep({ st: State =>
val releaseType = sys.props.get("RELEASE_TYPE").map {
case v if v == betaReleaseType => betaReleaseType.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
})
val snapshotReleaseType = "snapshot"

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

val prodSteps: Seq[ReleaseStep] = Seq(
setReleaseVersion,
val localExtraSteps:Seq[ReleaseStep] = Seq(
commitReleaseVersion,
tagRelease,
publishArtifacts,
releaseStepCommandAndRemaining("+publishSigned"),
releaseStepCommand("sonatypeBundleRelease"),
setNextVersion,
commitNextVersion,
pushChanges
commitNextVersion
)

/*
Beta assemblies can be published to Sonatype and Maven.
To make this work, start SBT with the beta RELEASE_TYPE variable set;
sbt -DRELEASE_TYPE=beta
This gets around the "problem" of sbt-sonatype assuming that a -SNAPSHOT build should not be delivered to Maven.
val snapshotSteps:Seq[ReleaseStep] = Seq(
publishArtifacts,
releaseStepCommand("sonatypeReleaseAll")
)

In this mode, the version number will be presented as e.g. 1.2.3-beta.n, but the git tagging and version-updating
steps are not triggered, so it's up to the developer to keep track of what was released and manipulate subsequent
release and next versions appropriately.
*/
val betaSteps: Seq[ReleaseStep] = Seq(
setReleaseVersion,
val prodSteps:Seq[ReleaseStep] = Seq(
releaseStepCommandAndRemaining("+publishSigned"),
releaseStepCommand("sonatypeBundleRelease"),
setNextVersion
releaseStepCommand("sonatypeBundleRelease")
)

commonSteps ++ (sys.props.get("RELEASE_TYPE") match {
case Some(v) if v == betaReleaseType => betaSteps // this enables a release candidate build to sonatype and Maven
case None => prodSteps // our normal deploy route
})
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
}
}

val commonSettings = Seq(
Expand All @@ -135,7 +66,7 @@ val commonSettings = Seq(
scmInfo := Some(ScmInfo(url("https://github.com/guardian/content-atom"),
"scm:git:[email protected]:guardian/content-atom.git")),
releasePublishArtifactsAction := PgpKeys.publishSigned.value,
) ++ mavenSettings ++ versionSettingsMaybe
) ++ mavenSettings

lazy val root = Project(id = "root", base = file("."))
.settings(commonSettings)
Expand Down Expand Up @@ -175,19 +106,10 @@ lazy val scalaClasses = Project(id = "content-atom-model", base = file("scala"))
Compile / scroogePublishThrift := true
)

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"
}.toSeq

lazy val typescriptClasses = (project in file("ts"))
.enablePlugins(ScroogeTypescriptGen)
.settings(commonSettings)
.settings(npmBetaReleaseTagMaybe)
.settings(
name := "content-atom-typescript",
scroogeTypescriptNpmPackageName := "@guardian/content-atom-model",
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.5.7
sbt.version=1.9.7
7 changes: 3 additions & 4 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0")

addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.1")

addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.10")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0")
addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0")

addSbtPlugin("com.twitter" % "scrooge-sbt-plugin" % "22.1.0")

Expand Down

0 comments on commit 90835a8

Please sign in to comment.