Skip to content

Commit 165a3af

Browse files
authored
ci: support alpha beta and release candidate versions (#708)
* ci(release): support alpha beta and release candidate versions Add qualified release version handling to the draft workflow so alpha, beta, and release candidate versions can be prepared from the selected branch. Publish workflow releases now run from workstation branches and mark qualified versions as GitHub pre-releases instead of latest stable releases. Document the new release flow and record the workflow capability in the changelog. * fix: support older Kotlin in publish helper * ci: use SDK Gradle wrapper for cross-platform tests * ci: patch cross-platform Gradle settings * ci: update cross-platform javadoc patch * ci: align cross-platform Android plugin version * ci: relax cross-platform JVM target validation * ci: patch cross-platform SDK API usage * ci: normalize cross-platform user attribute lists * ci: remove cross-platform compatibility workarounds * ci: use release-prep branch for draft releases
1 parent bf388f9 commit 165a3af

4 files changed

Lines changed: 135 additions & 72 deletions

File tree

.github/workflows/release-draft.yml

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,24 @@ on:
44
workflow_dispatch: # checkov:skip=CKV_GHA_7
55
inputs:
66
bump-type:
7-
description: "Specify if the version should be bumped as patch, minor, or major"
7+
description: |
8+
How to bump the base version (X.Y.Z). Use `none` to keep the base unchanged
9+
and only re-qualify an existing pre-release (e.g. rc1 -> rc2).
810
required: true
911
type: choice
1012
options:
1113
- patch
1214
- minor
1315
- major
16+
- none
17+
qualifier:
18+
description: |
19+
Optional pre-release qualifier to append, without the leading hyphen
20+
(e.g. `rc1`, `alpha2`, `beta`). Leave blank for a stable release.
21+
Allowed characters: alphanumerics, dot, hyphen.
22+
required: false
23+
type: string
24+
default: ""
1425

1526
concurrency:
1627
group: ${{ github.workflow }}-${{ github.ref }}
@@ -32,6 +43,7 @@ jobs:
3243
- name: Checkout repository
3344
uses: actions/checkout@v6
3445
with:
46+
ref: ${{ github.ref_name }}
3547
fetch-depth: 0
3648

3749
- name: Install JDK 17
@@ -43,32 +55,72 @@ jobs:
4355
- name: Setup Gradle
4456
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2
4557

58+
- name: Validate qualifier input
59+
env:
60+
QUALIFIER: ${{ github.event.inputs.qualifier }}
61+
run: |
62+
if [ -n "$QUALIFIER" ] && ! [[ "$QUALIFIER" =~ ^[A-Za-z0-9][A-Za-z0-9.-]*$ ]]; then
63+
echo "::error::qualifier '$QUALIFIER' is invalid. It must start with an alphanumeric character and may only contain alphanumerics, dot, and hyphen."
64+
exit 1
65+
fi
66+
4667
- name: Get current version
4768
id: version-file
4869
run: |
4970
version_from_file=$(head -n 1 VERSION)
5071
echo "release-version=$version_from_file" >> $GITHUB_OUTPUT
72+
base_version="${version_from_file%%-*}"
73+
echo "base-version=$base_version" >> $GITHUB_OUTPUT
5174
52-
- name: Bump version
75+
- name: Bump base version
5376
id: bump-version
77+
if: ${{ github.event.inputs.bump-type != 'none' }}
5478
uses: actions-ecosystem/action-bump-semver@34e334551143a5301f38c830e44a22273c6ff5c5 # v1.0.0
5579
with:
56-
current_version: ${{ steps.version-file.outputs.release-version }}
57-
level: ${{ github.event.inputs.bump-type || 'patch' }}
80+
current_version: ${{ steps.version-file.outputs.base-version }}
81+
level: ${{ github.event.inputs.bump-type }}
82+
83+
- name: Compose new version
84+
id: compose-version
85+
env:
86+
CURRENT: ${{ steps.version-file.outputs.release-version }}
87+
BUMPED: ${{ steps.bump-version.outputs.new_version }}
88+
BASE: ${{ steps.version-file.outputs.base-version }}
89+
BUMP_TYPE: ${{ github.event.inputs.bump-type }}
90+
QUALIFIER: ${{ github.event.inputs.qualifier }}
91+
run: |
92+
if [ "$BUMP_TYPE" = "none" ]; then
93+
new_base="$BASE"
94+
else
95+
new_base="$BUMPED"
96+
fi
97+
98+
if [ -n "$QUALIFIER" ]; then
99+
new_version="${new_base}-${QUALIFIER}"
100+
else
101+
new_version="$new_base"
102+
fi
103+
104+
if [ "$new_version" = "$CURRENT" ]; then
105+
echo "::error::Computed version '$new_version' is identical to the current VERSION. Pick a different bump-type or qualifier."
106+
exit 1
107+
fi
108+
109+
echo "new-version=$new_version" >> $GITHUB_OUTPUT
58110
59111
- name: Save bumped version to file
60112
run: |
61-
echo "${{ steps.bump-version.outputs.new_version }}" > VERSION
113+
echo "${{ steps.compose-version.outputs.new-version }}" > VERSION
62114
63115
- name: Publish to Maven local (smoke test)
64-
run: ./gradlew publishMavenPublicationToMavenLocal -PVERSION=${{ steps.bump-version.outputs.new_version }}
116+
run: ./gradlew publishMavenPublicationToMavenLocal -PVERSION=${{ steps.compose-version.outputs.new-version }}
65117

66118
- name: Generate changelog entry
67119
id: changelog
68120
# Pinned SHA for Semgrep (no mutable @main); bump when upgrading the action.
69121
uses: ROKT/rokt-workflows/actions/generate-changelog@c5c93e92107c520fb8b8cf71070995abdf4c403f
70122
with:
71-
version: ${{ steps.bump-version.outputs.new_version }}
123+
version: ${{ steps.compose-version.outputs.new-version }}
72124
repo-url: https://github.com/${{ github.repository }}
73125
changelog-path: CHANGELOG.md
74126
exclude-types: chore,ci,test,build
@@ -78,10 +130,10 @@ jobs:
78130
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
79131
with:
80132
token: ${{ secrets.MP_SEMANTIC_RELEASE_BOT }}
81-
commit-message: "chore: prepare release ${{ steps.bump-version.outputs.new_version }}"
82-
branch: release/${{ steps.bump-version.outputs.new_version }}
83-
title: "Prepare release ${{ steps.bump-version.outputs.new_version }}"
84-
base: main
133+
commit-message: "chore: prepare release ${{ steps.compose-version.outputs.new-version }}"
134+
branch: release-prep/${{ steps.compose-version.outputs.new-version }}
135+
title: "Prepare release ${{ steps.compose-version.outputs.new-version }}"
136+
base: ${{ github.ref_name }}
85137
body: |
86-
Preparing for release ${{ steps.bump-version.outputs.new_version }}
87-
- Bumped version to ${{ steps.bump-version.outputs.new_version }}
138+
Preparing for release ${{ steps.compose-version.outputs.new-version }} from `${{ github.ref_name }}`.
139+
- Bumped version to ${{ steps.compose-version.outputs.new-version }}

.github/workflows/release-publish.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches:
66
- main
7+
- workstation/*
78
paths:
89
- VERSION
910

@@ -15,6 +16,7 @@ jobs:
1516
runs-on: ubuntu-latest
1617
outputs:
1718
final_version: ${{ steps.version-file.outputs.release-version }}
19+
is_prerelease: ${{ steps.version-file.outputs.is-prerelease }}
1820
steps:
1921
- name: Checkout repository
2022
uses: actions/checkout@v6
@@ -24,6 +26,11 @@ jobs:
2426
run: |
2527
version_from_file=$(head -n 1 VERSION)
2628
echo "release-version=$version_from_file" >> $GITHUB_OUTPUT
29+
if [[ "$version_from_file" == *"-"* ]]; then
30+
echo "is-prerelease=true" >> $GITHUB_OUTPUT
31+
else
32+
echo "is-prerelease=false" >> $GITHUB_OUTPUT
33+
fi
2734
2835
build-and-release:
2936
needs: setup-and-version
@@ -58,7 +65,8 @@ jobs:
5865
- name: Create GitHub release
5966
uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0
6067
with:
61-
makeLatest: true
68+
makeLatest: ${{ needs.setup-and-version.outputs.is_prerelease != 'true' }}
69+
prerelease: ${{ needs.setup-and-version.outputs.is_prerelease == 'true' }}
6270
tag: ${{ needs.setup-and-version.outputs.final_version }}
6371
body: |
6472
Release ${{ needs.setup-and-version.outputs.final_version }}

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## [Unreleased]
22

3+
### Changed
4+
5+
- Add support for qualified alpha, beta, and release candidate versions in release workflows.
6+
37
### Removed
48

59
- Remove deprecated `KitIntegration.getAllUserAttributes()`. Custom kits must use `getCurrentUser().getUserAttributes()` (or other `FilteredMParticleUser` APIs) and `AttributeListener` callbacks instead ([#682](https://github.com/mParticle/mparticle-android-sdk/pull/682))

RELEASE.md

Lines changed: 57 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,82 +2,81 @@
22

33
This document outlines the process for releasing the mParticle Android SDK and its kits.
44

5-
## Step 1: Preparing the SDK for Release
5+
The Android SDK and kits are released together from this monorepo using GitHub Actions.
66

7-
The Android SDK and kits are released using GitHub Actions. The SDK and kits are currently coupled together in the release process.
7+
## Release workflows
88

9-
### Pre-release Checklist
9+
### Release - Draft
1010

11-
- Ensure all commits are in the public main branch
12-
- Review `release.yml` in the repo for specific workflow details
13-
- The release job deploys the most current snapshot of main branch release tag to main branch
11+
Use `Release - Draft` to prepare a release PR. The workflow:
1412

15-
## Step 2: Release via GitHub Actions
13+
1. Reads the current version from `VERSION`.
14+
2. Computes the next release version from `bump-type` and optional `qualifier`.
15+
3. Writes the computed version back to `VERSION`.
16+
4. Publishes to Maven local as a smoke test.
17+
5. Generates the changelog entry.
18+
6. Opens a PR back into the branch selected in the workflow dispatch UI.
1619

17-
### What the GitHub Release Job Does
20+
Generated release PR branches use `release/prep-<version>`, for example `release/prep-6.0.0-rc1`.
1821

19-
1. **Initial Setup**
20-
- Verifies job is running from public repo and on main branch
21-
- Creates temporary `release/{run_number}` branch
22+
### Release - Publish
2223

23-
2. **Testing Phase**
24-
- Runs unit and instrumented tests in parallel
25-
- Instrumented tests require an emulator
26-
- Unit tests run independently
27-
- Updates kits and runs additional tests
24+
`Release - Publish` runs when `VERSION` changes on:
2825

29-
3. **Version Management**
30-
- Runs semantic version action
31-
- Automatically bumps `build.gradle` version based on commit messages
32-
- No version bump if no new commits (e.g., feat/fix)
33-
- Generates release notes automatically
34-
- Requires linear history between development and main branches
26+
- `main`
27+
- `workstation/*`
3528

36-
4. **Artifact Publishing**
37-
- Uploads artifacts to Sonatype (core and kits)
38-
- Builds and signs the core SDK and all kit artifacts
39-
- Uploads to Sonatype Nexus (staging area)
40-
- Syncs artifacts to Maven Central
41-
> Note: This step will be moved before version bump during semantic release
29+
The workflow publishes the SDK and kits to Maven Central using the exact version in `VERSION`, then creates a GitHub release with the same tag.
4230

43-
5. **Branch Synchronization**
44-
- Pushes release branch to:
45-
- Public main branch
46-
- Public development branch
47-
- Internal repo main branch
48-
- Deletes release branch on success (preserved on failure for debugging)
31+
## Stable releases
4932

50-
### How to Release
33+
1. Run `Release - Draft` from the target branch.
34+
2. Choose `patch`, `minor`, or `major` for `bump-type`.
35+
3. Leave `qualifier` empty.
36+
4. Review, approve, and merge the generated release PR.
37+
5. Confirm `Release - Publish` succeeds.
5138

52-
1. Navigate to the Actions tab
53-
2. Select "release SDK"
54-
3. Run the workflow from main branch with "true" first to perform a dry run
55-
> Important: Always start with a dry run to validate the release process. This will perform all steps up to semantic release without actually publishing, helping catch potential issues early.
56-
4. If the dry run succeeds, run the workflow again with "false" option to perform the actual release
57-
> Note: Only proceed with the actual release after confirming a successful dry run
39+
Stable releases are marked as the latest GitHub release.
5840

59-
### Important Notes
41+
## Alpha, beta, and RC releases
6042

61-
- **Release Duration**: Expect ~20 minutes due to comprehensive test suite
62-
- **Emulator Issues**:
63-
- Sometimes GitHub Actions emulators fail
64-
- We have a custom script to install and start the emulator `scripts/install-start-emulator.sh`
65-
- OS version is hardcoded to avoid issues with new releases
66-
- **Code Reusability**:
67-
- Reusable GitHub Actions are defined in the [mparticle-workflows repo](https://github.com/mParticle/mparticle-workflows)
68-
- This enables other platforms to reuse similar jobs
43+
Use a qualified release when a partner or internal validation flow needs a fixed Maven Central version before the stable release, for example `6.0.0-alpha1`, `6.0.0-beta1`, or `6.0.0-rc1`.
6944

70-
## Post-Release Verification
45+
1. Run `Release - Draft` from the target branch, such as `workstation/6.0-Release`.
46+
2. Choose the base `bump-type`:
47+
- `patch`, `minor`, or `major` to bump the base version.
48+
- `none` to keep the base version unchanged and only change or remove the qualifier.
49+
3. Set `qualifier` to the pre-release identifier without the leading hyphen, for example `alpha1`, `beta1`, or `rc1`.
50+
4. Review, approve, and merge the generated release PR.
51+
5. Confirm `Release - Publish` succeeds.
7152

72-
After a successful build through GitHub Actions, verify:
53+
Qualified releases are published to Maven Central with the exact qualified version. Their GitHub releases are marked as pre-releases and are not marked as latest.
7354

74-
1. Public repo has a new semantic release tag
75-
2. New artifact is present in [Sonatype](https://central.sonatype.com/publishing)
55+
The qualifier must start with an alphanumeric character and may only contain alphanumerics, dots, and hyphens.
56+
57+
## Version examples
58+
59+
- `5.78.2` with `bump-type=minor` and `qualifier=alpha1` produces `5.79.0-alpha1`.
60+
- `5.79.0-alpha1` with `bump-type=none` and `qualifier=beta1` produces `5.79.0-beta1`.
61+
- `5.79.0-beta1` with `bump-type=none` and `qualifier=rc1` produces `5.79.0-rc1`.
62+
- `5.79.0-rc1` with `bump-type=none` and an empty `qualifier` produces `5.79.0`.
63+
64+
The draft workflow rejects any input combination that would produce the same version already stored in `VERSION`.
65+
66+
## Post-release verification
67+
68+
After a successful publish workflow, verify:
69+
70+
1. The GitHub release exists with the expected tag.
71+
2. The SDK artifact is present in [Sonatype](https://central.sonatype.com/publishing).
72+
3. The kit artifacts are present in [Sonatype](https://central.sonatype.com/publishing).
73+
4. Pre-release tags are marked as pre-releases and stable tags are marked as latest.
7674

7775
## Troubleshooting
7876

79-
If you encounter emulator issues during testing, check:
77+
If release validation fails:
8078

81-
- [Emulator setup script](https://github.com/mParticle/mparticle-android-sdk/blob/main/scripts/install-start-emulator.sh)
82-
- Current OS version compatibility
83-
- GitHub Actions logs for specific error messages
79+
- Check the generated release PR for the computed `VERSION` and changelog changes.
80+
- Check the Maven local smoke-test step in `Release - Draft`.
81+
- Check the Maven Central publish steps in `Release - Publish`.
82+
- For emulator-related validation issues, check `scripts/install-start-emulator.sh` and the GitHub Actions logs.

0 commit comments

Comments
 (0)