Skip to content

Commit

Permalink
chore: Rework release workflow (#535)
Browse files Browse the repository at this point in the history
* chore: Rework release workflow

- add/update documentation
- disable release-published.yml

* Add maven central urls
  • Loading branch information
adangel authored Dec 19, 2024
1 parent 6801439 commit b8b47f4
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 122 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/release-published.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ name: Release Extension to Sonatype

on:
workflow_dispatch:
release:
types: [published]
# disabled on purpose, see RELEASE.md
#release:
# types: [published]

jobs:
release:
Expand Down
226 changes: 106 additions & 120 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,132 +1,118 @@
# Release Workflow

The release automation is designed to quickly release updates to liquibase extensions. This routinely happens
when there is a new release of liquibase core.

The release process is semi-automated so that you still have control over e.g. the release notes and
when the release is happening and you have the ability to merge other PRs as well before the release.

The update of liquibase core is triggered by a pull request by dependabot. This PR is created automatically
and signals: liquibase core is generally available via maven central. You need to manually merge
this PR after you've reviewed the changes and test results.

After that, you can immediately trigger manually the workflow "prepare-release". You could start
this workflow also later when it is more convenient for you and you have time to fix potential issues.

The workflow "prepare-release" will create a draft release on github. By publishing this draft release,
the new extension version is made available via maven central.

## Triggers

### Pull Request Opened

Dependabot checks daily whether there are new updates for your dependencies. One of these
dependencies is `org.liquibase:liquibase-core`. Once a PR for this dependency arrives, you know: It's
time for a new extension release.

This pull request executes the usual build which includes integration tests.
You should verify, that all tests pass before merging the PR.

### Manual workflow "prepare-release"

Once you are satisfied with what's in the release, you can trigger manually the workflow "prepare-release"
via the github web ui: <https://github.com/liquibase/liquibase-percona/actions/workflows/prepare-release.yml>.

This workflow will prepare a release from branch `main` and can be executed at any time. Updates to
liquibase-core or any other release you want to publish for your extension.

You can specify an extensionVersion - that is the "to-be-released" version of your extension. You can leave it
empty, if you create a new release to support a new liquibase-core version. Then the extension will have the
same version as liquibase-core (e.g. 4.5.0). If you create an patch version for your extension, then you
can enter here for example 4.5.0.1.

This workflow will perform the following steps:

* Updates the version to the extension version in the `pom.xml` including the property
`project.build.outputTimestamp` (in order to support reproducible builds)
* Creates a new tag
* Updates the version to the next SNAPSHOT development version
* Pushes these changes to the main branch
* Runs the integration tests
* Creates a draft release on github

The push uses the automatically generated `GITHUB_TOKEN` provided by [Github Actions](https://docs.github.com/en/actions/security-guides/automatic-token-authentication).
So there is no need for an additional token.

All changes for workflow always happen on the branch `main`. This means, releases can currently only
be created from `main`. If there is a patch release needed for an older version, then this release
needs to be done completely manually.

You can now download the extension jar from the draft release and do local testing.
Also don't forget to review the release notes.

If you are satisfied with the release, you can publish it. This will trigger the next step.

### Draft Release is Published

Once the GitHub release is published, the signed artifact is uploaded to Sonatype Nexus.
The `<autoReleaseAfterClose>true</autoReleaseAfterClose>` option is defined in the POM, so for
all releases without the `SNAPSHOT` suffix, they will automatically release after all
the staging test have passed. If everything goes well, no further manual action is required.

Note: This workflow will actually checkout the sources from the extension version tag and
build the extension (without running tests) again, signs the artifacts and uploads it to Sonatype Nexus.
Hence it's good, when the extension allows for reproducible builds. Otherwise the jar file and the
github release would be different from the jar file in Maven Central.

## Tests

Liquibase Percona has extended integration tests. These integration tests start MySQL and MariaDB docker instances
and run the integration tests from `src/it/*`. The integration tests are only executed, if the profile `run-its`
is activated, e.g. `./mvnw verify -Prun-its`.

By default, these tests run automatically for every build from the main branch.
Creating a new release is partly manual, partly automated.
Note that the release workflow of liquibase-percona doesn't follow the workflow of other
extensions, as it simply doesn't work.
See [GitHub Actions, Building, PR, and Releasing Questions #425](https://github.com/liquibase/liquibase-percona/issues/425)
for more detailed information about that. That's why the workflow "release-published.yml" is disabled.

## Step by Step

1. Before a release, make sure, you have merged all open PRs that should be part of the release.
Dependabot creates usually PRs for updating dependencies. If all goes well, these would be merged
automatically, but sometimes some manual fixes need to be made, so some PRs might be left open.

2. Especially check, that `liquibase-core` has been updated to the desired version. Usually, for every
liquibase-core release, the extension is released as well.
Label such a PR with `notableChanges`, so that it appears separately in the release notes.

3. Create a new branch in the main repository (**not** in your fork). This main repository is considered
"internal" and pull requests created from branches from there be correctly merged. External PRs don't
work correctly.

This new branch is called `chore-prepare-release-x.y.z`

Update the following files:
* README.md
* Update the versions in the code snippets for the maven dependency
* Add/Update the version in section "Liquibase version(s) tested against", check/update version of percona toolkit
* CHANGELOG.md
* Go to <https://github.com/liquibase/liquibase-percona/releases> - the release drafter has created a draft
release already
* Copy the draft release into this file
* Make sure to replace `(#123)` with the corresponding links to PRs/issues
* docker/README.md
* Create new version entry
* for the old version, take the commit id of the last "chore: Prepare release ..." commit
* docker/Dockerfile
* Update versions (all versions, if necessary: liquibase-core and percona-toolkit as well...)

Then push this branch and create a new PR with the title "chore: Prepare release x.y.z".
Set the correct milestone for this PR - which is usually "next".

Then update "CHANGELOG.md" once again and manually add this very PR. Push another commit to this PR.

Finally merge this PR.

4. Create the necessary version updates and tags locally and push manually. "developmentVersion" is the next
version, and "newVersion" is the version to be released.

```
./mvnw release:clean release:prepare \
-Dmaven.javadoc.skip=true -Dmaven.test.skipTests=true -Dmaven.test.skip=true -Dmaven.deploy.skip=true" \
-DdevelopmentVersion=x.(y+1).0-SNAPSHOT \
-DnewVersion=x.y.z \
-Dtag=vx.y.z \
-DpushChanges=false
```

5. Now you should have a tag "vx.y.z" created and the version in the pom.xml should be the next SNAPSHOT
version. If this looks correct, you can push:

```
git push origin main
git push origin tag vx.y.z
```

6. Edit the draft release on <https://github.com/liquibase/liquibase-percona/releases>
* Select the just created tag instead of letting github create a new tag: vx.y.z
* Change the name of the release to match the tag name: vx.y.z
* Don't care about the attached assets, they will be removed with the next step and replaced by
a new build.
* Save it as a draft, don't publish yet.

7. Run the action [manual-release-from-tag](https://github.com/liquibase/liquibase-percona/actions/workflows/manual-release-from-tag.yml)
and select the tag "vx.y.z". This action will
* checkout the tag
* build liquibase-percona
* attach the jar files to the draft release
* publish the jar files to maven central. It should eventually be available on
* https://central.sonatype.com/artifact/org.liquibase.ext/liquibase-percona
* https://repo1.maven.org/maven2/org/liquibase/ext/liquibase-percona/

8. If the action ran successfully, then you can finally publish the release on github.

Notes:
* liquibase-percona has reproducible builds, that means, you can rebuild the extension from the same tag
and this should produce the exact same artifacts.
* If anything goes wrong, you can redo the steps 1.-7. as long as the jar files have not been published
to maven central yet. You can remove the tag, push more commits for fixing, create another tag and
run step 7 (manual-release-from-tag) again. However, if the jar files were successfully published into
maven central, there is no way anymore, to change the version. If anything is wrong, you need to
create an entire new release then. And you shouldn't change the tag afterwards (as otherwise, the version
won't be reproducible anymore).

## Repository Configuration

The automation requires the below secrets and configuration in order to run.
The action [manual-release-from-tag](https://github.com/liquibase/liquibase-percona/actions/workflows/manual-release-from-tag.yml)
executes the same commands as the actions from [Liquibase Reusable Workflows](https://github.com/liquibase/build-logic/) do.
The same secrets are reused. This allows to publish to maven central.

### GPG SECRET
Github secret named: `GPG_SECRET`

According to [the advanced java setup docs for github actions](https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#gpg) the GPG key should be exported by: `gpg --armor --export-secret-keys YOUR_ID`. From the datical/build-maven:jdk-8 docker container, this can be export by the following:

```bash
$ docker run -it -u root docker.liquibase.net/build-maven:jdk-8 bash

$ gpg -k
/home/jenkins/.gnupg/pubring.kbx
--------------------------------
pub rsa2048 2020-02-12 [SC] [expires: 2022-02-11]
**** OBFUSCATED ID ****
uid [ultimate] Liquibase <[email protected]>
sub rsa2048 2020-02-12 [E] [expires: 2022-02-11]

$ gpg --armor --export-secret-keys --pinentry-mode loopback **** OBFUSCATED ID ****
Enter passphrase: *** GPG PASSPHRASE ***
-----BEGIN PGP PRIVATE KEY BLOCK-----
******
******
=XCvo
-----END PGP PRIVATE KEY BLOCK-----
```

### GPG PASSPHRASE
Github secret named: `GPG_PASSPHRASE`
The passphrase is the same one used previously for the manual release and is documented elsewhere for the manual release process.

### SONATYPE USERNAME
Github secret named: `SONATYPE_USERNAME`
### LIQUIBOT_PAT
Used to access liquibase maven repository on GitHub (https://github.com/orgs/liquibase/packages)

The username or token for the sonatype account. Current managed and shared via lastpass for the Shared-DevOps group.
### BOT_TOKEN
Used to access GitHub API to query releases, add/remove release assets.

### SONATYPE TOKEN
Github secret named: `SONATYPE_TOKEN`
### GPG_SECRET
According to [the advanced java setup docs for github actions](https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#gpg)
the GPG key should be exported by: `gpg --armor --export-secret-keys YOUR_ID`.

The password or token for the sonatype account. Current managed and shared via lastpass for the Shared-DevOps group.
### GPG_PASSPHRASE

## Useful Links
### SONATYPE_USERNAME
The username or token for the sonatype account. Used for publishing to maven central.

* [Github Actions Documentation](https://docs.github.com/en/actions)
* [Advanced Java Setup for GitHub Actions](https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#gpg)
* [Deploying to Sonatype Nexus with Apache Maven](https://central.sonatype.org/publish/publish-maven/)
### SONATYPE_TOKEN
The password or token for the sonatype account. Used for publishing to maven central.

0 comments on commit b8b47f4

Please sign in to comment.