Skip to content

Commit

Permalink
ci: release to maven on merge (#1423)
Browse files Browse the repository at this point in the history
Creates a new github action pipeline that runs on merge to `master`. The
pipeline will:
1. Create a new commit with an updated CHANGELOG.md
2. Tag that commit and push it to `master`
3. Make a clean checkout of that commit
4. Build, sign, and release all java artefacts to maven

Depends on #1422 to set up the secrets in github
  • Loading branch information
calumcalder authored Feb 5, 2025
1 parent 55fd706 commit ade2893
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 22 deletions.
10 changes: 10 additions & 0 deletions .cz.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[tool.commitizen]
name = "cz_conventional_commits"
tag_format = "v$version"
version_scheme = "semver"
version_provider = "scm"
update_changelog_on_bump = true
version_files = [
"gradle.properties:projectVersion="
]
changelog_start_rev = "v1.0.0"
2 changes: 1 addition & 1 deletion .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ jobs:
- name: "Lint the PR title"
env:
TITLE: ${{ github.event.pull_request.title }}
run: echo "${TITLE}" | cz check
run: cz check --message "${TITLE}" || { echo "see https://github.com/dtinit/data-transfer-project/blob/master/Documentation/Publishing.md#semantic-versioning-and-conventional-commits" >&2; exit 1; }
52 changes: 52 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Release

permissions:
# The commitizen action pushes a new commit to the main
# branch to generate the changelog + tag, so needs write
# permission
contents: write

on:
push:
branches:
- 'master'

jobs:
bump_version:
if: "!startsWith(github.event.head_commit.message, 'bump:')"
runs-on: ubuntu-latest
name: "Bump version"
outputs:
version: ${{ steps.cz.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch tags, which are required to calculate the new version
token: "${{ secrets.GITHUB_TOKEN }}"
- id: cz
name: "Generate Changelog and Tag"
uses: commitizen-tools/commitizen-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
release:
needs: bump_version
runs-on: ubuntu-latest
name: "Release"
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.bump_version.outputs.version }}
- name: "Set up JDK"
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'adopt'
cache: gradle
- name: "Sign and Release"
env:
GRADLE_SIGNING_KEY: "${{ secrets.GRADLE_SIGNING_KEY }}"
GRADLE_SIGNING_PASSWORD: "${{ secrets.GRADLE_SIGNING_PASSWORD }}"
OSSRH_USERNAME: "${{ secrets.OSSRH_USERNAME }}"
OSSRH_PASSWORD: "${{ secrets.OSSRH_PASSWORD }}"
# Exclude client-rest as it's not part of the java release
run: ./gradlew clean build sign uploadArchives --exclude-task :client-rest:uploadArchives
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ use GitHub pull requests for this purpose.
To automate releases we require that PRs are titled according to
[conventional commits](https://conventionalcommits.org); i.e. that they
are tagged like `fix: handle exception XYZ correctly`, or
`feat: implement new video exporter`. See the conventional commits documentation
for more details.
`feat: implement new video exporter`. See our
[Publishing documentation](https://github.com/dtinit/data-transfer-project/blob/master/Documentation/Publishing.md#semantic-versioning-and-conventional-commits)
and the conventional commits documentation for more details.
54 changes: 38 additions & 16 deletions Documentation/Publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,52 @@

Artifacts are signed and published to Maven Central. You can see the latest version at the maven central website https://search.maven.org/search?q=g:org.datatransferproject.

The publication process is mostly automated through Gradle plugins as documented below.
The publication process is mostly automated through Gradle and Github Actions; when you merge a commit to the `master` branch, a new version will be created in the Maven Central staging repository. You can then release the packages to the public Central Repository following the steps in the [Sonatype documentation](https://central.sonatype.org/publish/release/). \
We are on the legacy host so make sure to use https://oss.sonatype.org/. Only attempt to Close the staging repository once the Github action has finished.

## 0. Versioning
## Automated Process

We don't have strict rules on versioning just yet, but we are trying to stick
to [Semantic Versioning](https://semver.org/). Until the moment we have
a clear guidance on versioning, please discuss future releases in the
#maintainers chat.
DTP's publication automation is done through a Github action in `.github/workflows/release.yml`. \
The action contains two jobs; one to bump the version number of the DTP packages and publish a git tag, and one to build, sign, and upload the artifacts to Maven Central.

## 1. Setting properties
### Semantic Versioning and Conventional Commits

DTP uses [Semantic Versioning](https://semver.org/) for published packages. We also enforce [Conventional Commits](https://conventionalcommits.org/) on the `master` branch through the `.github/workflows/commitlint.yml` Github action, which lets us automatically calculate version numbers.

Commitizen is a tool that supports automatically incrementing SemVer version numbers based on git commit history. Our usage of Commitizen is configured in `.cz.toml`, and uses the `commitizen-tools/commitizen-action` Github action to automatically bump the package version number and to tag the new version in git.

### Automated Publishing

Using the `maven` and `signing` gradle plugins adds the `sign` and `uploadArchives` targets, which together automate the process of publishing to Maven Central based on our configuration in `build.gradle`. \
The `release` job in the Github action runs these targets, using environment variables to inject secret values like GPG keys and the OSSRH User Token required for publishing.

### Release to the public repository

The only part of the process that isn't automated is promoting packages from the staging repository to the public repository in Maven Central.

This process is documented in [Sonatype's documentation](https://central.sonatype.org/publish/release/). The summary is:
1. Log in to https://oss.sonatype.org/
2. Go to 'Staging Repositories' under 'Build Promotion' in the nav panel
3. Select the repository (version) to promote
4. 'Close' the repository to freeze it - only do this once the Github action has finished
5. 'Release' the repository, which promotes the packages to the public repository

## Manual Process

If for some reason you need to publish manually, the steps are detailed below.

### 1. Setting properties
First you must set the necessary properties in [gradle.properties](../gradle.properties). These are:
- `projectVersion` - this is the new version you wish to publish.
- `ossrhUsername` & `ossrhPassword` - These are your Sonatype Jira credentials. Your account must have been granted publishing permissions. These are managed from a [JIRA ticket](https://issues.sonatype.org/browse/OSSRH-44189).
- `ossrhUsername` & `ossrhPassword` - These are your Sonatype [User Token](https://central.sonatype.org/publish/generate-token/#generate-a-token-on-ossrh-sonatype-nexus-repository-manager-servers) credentials. Your account must have been granted publishing permissions. Permissions are managed manually by Sonatype - see [Sonatype's documentation](https://central.sonatype.org/register/legacy/) for details.
- `signing.keyId` - The GPG key being used for signing the artifacts. (More information about setting up GPG keys can be found [here](https://central.sonatype.org/publish/requirements/gpg/))
- `signing.password` - The password for that GPG private key.
- `signing.secretKeyRingFile` - The path to the file containing the GPG private key.

## 2. Sanity check
### 2. Sanity check
Make sure that the artifacts are building and running correctly. For example run the worker in the Docker container, see [Running Locally](RunningLocally.md) for instructions.

## 3. Sign and upload
### 3. Sign and upload
To sign and publish the artifacts run the following Gradle command:

```
Expand All @@ -31,17 +56,14 @@ To sign and publish the artifacts run the following Gradle command:

We exclude the client-rest archives as these are not a Java package.

## 4. Release
You can then release the deployment to the Central Repository following the steps on the Sonatype website [here](https://central.sonatype.org/publish/release/). We are on the legacy host so make sure to use https://oss.sonatype.org/. Only attempt to Close the staging repository once the upload has finished.


## 5. Create github release and tag
### 4. Create github release and tag

1. Go to [/releases](https://github.com/google/data-transfer-project/releases);
2. Click 'Draft a new release';
3. Fill in the title and create a tag (the tag must have a `v` prefix, the title mustn't);
4. Click 'Generate release notes';
5. Publish release.

## 6. Update the project version
### 5. Update the project version

Go to `properties.gradle` and update the version, create a PR.
18 changes: 16 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,17 @@ def configurePublication(Project project) {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2") {
authentication(userName: project.hasProperty('ossrhUsername') ? ossrhUsername : '', password: project.hasProperty('ossrhPassword') ? ossrhPassword : '')
authentication(
userName: project.hasProperty('ossrhUsername') ? ossrhUsername : System.getenv('OSSRH_USERNAME'),
password: project.hasProperty('ossrhPassword') ? ossrhPassword : System.getenv('OSSRH_PASSWORD')
)
}

snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots") {
authentication(userName: project.hasProperty('ossrhUsername') ? ossrhUsername : '', password: project.hasProperty('ossrhPassword') ? ossrhPassword : '')
authentication(
userName: project.hasProperty('ossrhUsername') ? ossrhUsername : System.getenv('OSSRH_USERNAME'),
password: project.hasProperty('ossrhPassword') ? ossrhPassword : System.getenv('OSSRH_PASSWORD')
)
}

pom.project {
Expand Down Expand Up @@ -208,6 +214,14 @@ def configurePublication(Project project) {
project.signing {
sign project.configurations.archives
}
} else if (System.getenv("GRADLE_SIGNING_KEY")) {
// For use in CI
project.signing {
def signingKey = System.getenv('GRADLE_SIGNING_KEY')
def signingPassword = System.getenv('GRADLE_SIGNING_PASSWORD')
useInMemoryPgpKeys(signingKey, signingPassword)
sign project.configurations.archives
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
projectGroup=org.datatransferproject
projectVersion=1.0.3-SNAPSHOT
projectVersion=1.0.4
annotationApiVersion=1.2
autoValueVersion=1.9
commonsLangVersion=3.4
Expand Down

0 comments on commit ade2893

Please sign in to comment.