Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 65 additions & 13 deletions .github/workflows/release-draft.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,24 @@ on:
workflow_dispatch: # checkov:skip=CKV_GHA_7
inputs:
bump-type:
description: "Specify if the version should be bumped as patch, minor, or major"
description: |
How to bump the base version (X.Y.Z). Use `none` to keep the base unchanged
and only re-qualify an existing pre-release (e.g. rc1 -> rc2).
required: true
type: choice
options:
- patch
- minor
- major
- none
qualifier:
description: |
Optional pre-release qualifier to append, without the leading hyphen
(e.g. `rc1`, `alpha2`, `beta`). Leave blank for a stable release.
Allowed characters: alphanumerics, dot, hyphen.
required: false
type: string
default: ""

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand All @@ -32,6 +43,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{ github.ref_name }}
fetch-depth: 0

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

- name: Validate qualifier input
env:
QUALIFIER: ${{ github.event.inputs.qualifier }}
run: |
if [ -n "$QUALIFIER" ] && ! [[ "$QUALIFIER" =~ ^[A-Za-z0-9][A-Za-z0-9.-]*$ ]]; then
echo "::error::qualifier '$QUALIFIER' is invalid. It must start with an alphanumeric character and may only contain alphanumerics, dot, and hyphen."
exit 1
fi

- name: Get current version
id: version-file
run: |
version_from_file=$(head -n 1 VERSION)
echo "release-version=$version_from_file" >> $GITHUB_OUTPUT
base_version="${version_from_file%%-*}"
echo "base-version=$base_version" >> $GITHUB_OUTPUT

- name: Bump version
- name: Bump base version
id: bump-version
if: ${{ github.event.inputs.bump-type != 'none' }}
uses: actions-ecosystem/action-bump-semver@34e334551143a5301f38c830e44a22273c6ff5c5 # v1.0.0
with:
current_version: ${{ steps.version-file.outputs.release-version }}
level: ${{ github.event.inputs.bump-type || 'patch' }}
current_version: ${{ steps.version-file.outputs.base-version }}
level: ${{ github.event.inputs.bump-type }}

- name: Compose new version
id: compose-version
env:
CURRENT: ${{ steps.version-file.outputs.release-version }}
BUMPED: ${{ steps.bump-version.outputs.new_version }}
BASE: ${{ steps.version-file.outputs.base-version }}
BUMP_TYPE: ${{ github.event.inputs.bump-type }}
QUALIFIER: ${{ github.event.inputs.qualifier }}
run: |
if [ "$BUMP_TYPE" = "none" ]; then
new_base="$BASE"
else
new_base="$BUMPED"
fi

if [ -n "$QUALIFIER" ]; then
new_version="${new_base}-${QUALIFIER}"
else
new_version="$new_base"
fi

if [ "$new_version" = "$CURRENT" ]; then
echo "::error::Computed version '$new_version' is identical to the current VERSION. Pick a different bump-type or qualifier."
exit 1
fi

echo "new-version=$new_version" >> $GITHUB_OUTPUT

- name: Save bumped version to file
run: |
echo "${{ steps.bump-version.outputs.new_version }}" > VERSION
echo "${{ steps.compose-version.outputs.new-version }}" > VERSION

- name: Publish to Maven local (smoke test)
run: ./gradlew publishMavenPublicationToMavenLocal -PVERSION=${{ steps.bump-version.outputs.new_version }}
run: ./gradlew publishMavenPublicationToMavenLocal -PVERSION=${{ steps.compose-version.outputs.new-version }}

- name: Generate changelog entry
id: changelog
# Pinned SHA for Semgrep (no mutable @main); bump when upgrading the action.
uses: ROKT/rokt-workflows/actions/generate-changelog@c5c93e92107c520fb8b8cf71070995abdf4c403f
with:
version: ${{ steps.bump-version.outputs.new_version }}
version: ${{ steps.compose-version.outputs.new-version }}
repo-url: https://github.com/${{ github.repository }}
changelog-path: CHANGELOG.md
exclude-types: chore,ci,test,build
Expand All @@ -78,10 +130,10 @@ jobs:
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
with:
token: ${{ secrets.MP_SEMANTIC_RELEASE_BOT }}
commit-message: "chore: prepare release ${{ steps.bump-version.outputs.new_version }}"
branch: release/${{ steps.bump-version.outputs.new_version }}
title: "Prepare release ${{ steps.bump-version.outputs.new_version }}"
base: main
commit-message: "chore: prepare release ${{ steps.compose-version.outputs.new-version }}"
branch: release-prep/${{ steps.compose-version.outputs.new-version }}
title: "Prepare release ${{ steps.compose-version.outputs.new-version }}"
base: ${{ github.ref_name }}
body: |
Preparing for release ${{ steps.bump-version.outputs.new_version }}
- Bumped version to ${{ steps.bump-version.outputs.new_version }}
Preparing for release ${{ steps.compose-version.outputs.new-version }} from `${{ github.ref_name }}`.
- Bumped version to ${{ steps.compose-version.outputs.new-version }}
10 changes: 9 additions & 1 deletion .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- main
- workstation/*
paths:
- VERSION

Expand All @@ -15,6 +16,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
final_version: ${{ steps.version-file.outputs.release-version }}
is_prerelease: ${{ steps.version-file.outputs.is-prerelease }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
Expand All @@ -24,6 +26,11 @@ jobs:
run: |
version_from_file=$(head -n 1 VERSION)
echo "release-version=$version_from_file" >> $GITHUB_OUTPUT
if [[ "$version_from_file" == *"-"* ]]; then
echo "is-prerelease=true" >> $GITHUB_OUTPUT
else
echo "is-prerelease=false" >> $GITHUB_OUTPUT
fi

build-and-release:
needs: setup-and-version
Expand Down Expand Up @@ -58,7 +65,8 @@ jobs:
- name: Create GitHub release
uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0
with:
makeLatest: true
makeLatest: ${{ needs.setup-and-version.outputs.is_prerelease != 'true' }}
prerelease: ${{ needs.setup-and-version.outputs.is_prerelease == 'true' }}
tag: ${{ needs.setup-and-version.outputs.final_version }}
body: |
Release ${{ needs.setup-and-version.outputs.final_version }}
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## [Unreleased]

### Changed

- Add support for qualified alpha, beta, and release candidate versions in release workflows.

### Removed

- 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))
Expand Down
115 changes: 57 additions & 58 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,82 +2,81 @@

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

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

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

### Pre-release Checklist
### Release - Draft

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

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

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

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

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

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

4. **Artifact Publishing**
- Uploads artifacts to Sonatype (core and kits)
- Builds and signs the core SDK and all kit artifacts
- Uploads to Sonatype Nexus (staging area)
- Syncs artifacts to Maven Central
> Note: This step will be moved before version bump during semantic release
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.

5. **Branch Synchronization**
- Pushes release branch to:
- Public main branch
- Public development branch
- Internal repo main branch
- Deletes release branch on success (preserved on failure for debugging)
## Stable releases

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

1. Navigate to the Actions tab
2. Select "release SDK"
3. Run the workflow from main branch with "true" first to perform a dry run
> 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.
4. If the dry run succeeds, run the workflow again with "false" option to perform the actual release
> Note: Only proceed with the actual release after confirming a successful dry run
Stable releases are marked as the latest GitHub release.

### Important Notes
## Alpha, beta, and RC releases

- **Release Duration**: Expect ~20 minutes due to comprehensive test suite
- **Emulator Issues**:
- Sometimes GitHub Actions emulators fail
- We have a custom script to install and start the emulator `scripts/install-start-emulator.sh`
- OS version is hardcoded to avoid issues with new releases
- **Code Reusability**:
- Reusable GitHub Actions are defined in the [mparticle-workflows repo](https://github.com/mParticle/mparticle-workflows)
- This enables other platforms to reuse similar jobs
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`.

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

After a successful build through GitHub Actions, verify:
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.

1. Public repo has a new semantic release tag
2. New artifact is present in [Sonatype](https://central.sonatype.com/publishing)
The qualifier must start with an alphanumeric character and may only contain alphanumerics, dots, and hyphens.

## Version examples

- `5.78.2` with `bump-type=minor` and `qualifier=alpha1` produces `5.79.0-alpha1`.
- `5.79.0-alpha1` with `bump-type=none` and `qualifier=beta1` produces `5.79.0-beta1`.
- `5.79.0-beta1` with `bump-type=none` and `qualifier=rc1` produces `5.79.0-rc1`.
- `5.79.0-rc1` with `bump-type=none` and an empty `qualifier` produces `5.79.0`.

The draft workflow rejects any input combination that would produce the same version already stored in `VERSION`.

## Post-release verification

After a successful publish workflow, verify:

1. The GitHub release exists with the expected tag.
2. The SDK artifact is present in [Sonatype](https://central.sonatype.com/publishing).
3. The kit artifacts are present in [Sonatype](https://central.sonatype.com/publishing).
4. Pre-release tags are marked as pre-releases and stable tags are marked as latest.

## Troubleshooting

If you encounter emulator issues during testing, check:
If release validation fails:

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