From 75376706d3253439b20e56260996b922c5e56927 Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 1 Jul 2026 10:23:40 +0000 Subject: [PATCH 1/2] feat(release): auto-set versionName from tag on release builds --- .github/workflows/build.yml | 20 +++++++++----------- README.md | 10 ++++------ 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 364ada1d..73743bdf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -219,21 +219,19 @@ jobs: run: | test -e mobile/src/main/jniLibs/x86_64/libaw_server.so - - name: Verify versionName matches tag + - name: Set versionName from tag if: startsWith(github.ref, 'refs/tags/v') # only on runs triggered from tag run: | SHORT_VERSION="${GITHUB_REF_NAME#v}" - COMMITTED_VERSION=$(sed -n -E "s/^[[:space:]]*versionName[[:space:]]+['\"]([^'\"]+)['\"].*/\\1/p" mobile/build.gradle) - if [ -z "$COMMITTED_VERSION" ]; then - echo "Failed to parse versionName from mobile/build.gradle." + echo "Setting versionName to ${SHORT_VERSION} from tag ${GITHUB_REF_NAME}" + # Update versionName in mobile/build.gradle to match the tag + sed -i -E "s/^([[:space:]]*)versionName[[:space:]]+[\"']([^\"']+)/\1versionName '${SHORT_VERSION}'/" mobile/build.gradle + # Verify the update + grep -qE "^[[:space:]]*versionName[[:space:]]+[\"']${SHORT_VERSION}[\"']" mobile/build.gradle || { + echo "Failed to update versionName in mobile/build.gradle." exit 1 - fi - if [ "$COMMITTED_VERSION" != "$SHORT_VERSION" ]; then - echo "mobile/build.gradle versionName must match the release tag." - echo "tag=$SHORT_VERSION committed=$COMMITTED_VERSION" - exit 1 - fi - + } + echo "versionName set to ${SHORT_VERSION}" - name: Set versionCode run: | # Sets versionCode diff --git a/README.md b/README.md index 6b19f9b4..723093ad 100644 --- a/README.md +++ b/README.md @@ -57,12 +57,10 @@ Once both aw-server-rust and aw-webui is built, you can build the Android app as ### Making a release -Before tagging, update `mobile/build.gradle` so `versionName` matches the -release you are about to cut. The release workflow verifies the committed -`versionName` instead of patching it after checkout, which keeps tagged source, -GitHub release builds, and F-Droid builds on the same version. - -Then make a signed tag and push it to GitHub: +Push a signed tag matching the version you want to release. The release +workflow will automatically set `versionName` in `mobile/build.gradle` to +match the tag before building, so there is no need to manually update it +beforehand. ```sh git tag -s v0.1.0 From ac07957d9767bae6696ca5693a976967e2370b9a Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 1 Jul 2026 18:53:58 +0000 Subject: [PATCH 2/2] fix(release): replace broken sed with workflow_dispatch release flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'Set versionName from tag' sed regex introduced in this PR had a bug: the substitution matched up to but not including the closing quote of the existing versionName, so after substitution the line became versionName '0.x.y'" (dangling closing quote), a Groovy syntax error that breaks Gradle. F-Droid also requires the correct versionName in the committed source that the tag points to, so patching it post-checkout never helped there. Fix: revert the verify-before-tag step from #155, and add a new .github/workflows/release.yml with a workflow_dispatch trigger that does the whole release atomically: 1. Validates the version format and that the tag does not exist yet 2. Updates versionName in mobile/build.gradle with a correct sed that consumes both surrounding quotes (no dangling characters) 3. Commits the change and pushes a signed annotated tag 4. The tag push (via RELEASE_PAT) triggers the Build workflow This satisfies F-Droid: the tag now always points to a commit where the versionName matches. Requires a RELEASE_PAT secret (repo-scoped GitHub PAT) — documented in README and release.yml. --- .github/workflows/build.yml | 21 ++++++----- .github/workflows/release.yml | 71 +++++++++++++++++++++++++++++++++++ README.md | 26 ++++++++----- 3 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73743bdf..f490dd0f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -219,19 +219,22 @@ jobs: run: | test -e mobile/src/main/jniLibs/x86_64/libaw_server.so - - name: Set versionName from tag + - name: Verify versionName matches tag if: startsWith(github.ref, 'refs/tags/v') # only on runs triggered from tag run: | SHORT_VERSION="${GITHUB_REF_NAME#v}" - echo "Setting versionName to ${SHORT_VERSION} from tag ${GITHUB_REF_NAME}" - # Update versionName in mobile/build.gradle to match the tag - sed -i -E "s/^([[:space:]]*)versionName[[:space:]]+[\"']([^\"']+)/\1versionName '${SHORT_VERSION}'/" mobile/build.gradle - # Verify the update - grep -qE "^[[:space:]]*versionName[[:space:]]+[\"']${SHORT_VERSION}[\"']" mobile/build.gradle || { - echo "Failed to update versionName in mobile/build.gradle." + COMMITTED_VERSION=$(sed -n -E "s/^[[:space:]]*versionName[[:space:]]+['\"]([^'\"]+)['\"].*/\1/p" mobile/build.gradle) + if [ -z "$COMMITTED_VERSION" ]; then + echo "Failed to parse versionName from mobile/build.gradle." exit 1 - } - echo "versionName set to ${SHORT_VERSION}" + fi + if [ "$COMMITTED_VERSION" != "$SHORT_VERSION" ]; then + echo "mobile/build.gradle versionName must match the release tag." + echo "Use the Release workflow (workflow_dispatch) to bump, commit, and tag in one step." + echo "tag=$SHORT_VERSION committed=$COMMITTED_VERSION" + exit 1 + fi + echo "versionName ${COMMITTED_VERSION} matches tag ${GITHUB_REF_NAME}" - name: Set versionCode run: | # Sets versionCode diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..e1724026 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,71 @@ +name: Release + +# Full release workflow: bumps versionName in source, commits, tags, and pushes. +# The tag push (via RELEASE_PAT) triggers the Build workflow automatically. +# +# Prerequisites: +# - Add a RELEASE_PAT secret: a GitHub PAT with `repo` scope. +# Using a PAT instead of GITHUB_TOKEN ensures the tag push triggers Build. +# +# Usage: Actions → Release → Run workflow → enter version (e.g. 0.12.2) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version to release, without v prefix (e.g. 0.12.2)' + required: true + type: string + +jobs: + release: + name: Bump versionName, commit, and tag + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + with: + # RELEASE_PAT is a repo-scoped PAT; its pushes trigger the Build workflow. + # Falls back to GITHUB_TOKEN (build won't auto-trigger, but tag is still created). + token: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Validate version format + run: | + VERSION="${{ inputs.version }}" + if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::Version must be X.Y.Z (e.g. 0.12.2). Got: ${VERSION}" + exit 1 + fi + if git rev-parse "refs/tags/v${VERSION}" >/dev/null 2>&1; then + echo "::error::Tag v${VERSION} already exists." + exit 1 + fi + + - name: Bump versionName in mobile/build.gradle + run: | + VERSION="${{ inputs.version }}" + # Replace quoted versionName value; works for both single and double quotes. + sed -i -E "s/^([[:space:]]*versionName[[:space:]]+)[\"'][^\"']+[\"']/\1'${VERSION}'/" \ + mobile/build.gradle + # Verify: the line must end with the closing quote (no dangling chars). + grep -qE "^[[:space:]]*versionName[[:space:]]+'${VERSION}'[[:space:]]*$" \ + mobile/build.gradle || { + echo "::error::versionName update failed. Current state:" + grep "versionName" mobile/build.gradle + exit 1 + } + echo "Updated versionName to '${VERSION}'" + + - name: Commit and tag + run: | + VERSION="${{ inputs.version }}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add mobile/build.gradle + git commit -m "chore: bump versionName to ${VERSION}" + git tag -a "v${VERSION}" -m "Release v${VERSION}" + git push origin HEAD:master + git push origin "v${VERSION}" diff --git a/README.md b/README.md index 723093ad..2ad2d726 100644 --- a/README.md +++ b/README.md @@ -57,18 +57,26 @@ Once both aw-server-rust and aw-webui is built, you can build the Android app as ### Making a release -Push a signed tag matching the version you want to release. The release -workflow will automatically set `versionName` in `mobile/build.gradle` to -match the tag before building, so there is no need to manually update it -beforehand. - -```sh -git tag -s v0.1.0 -git push origin refs/tags/v0.1.0 -``` +Use the **Release** workflow to bump the version, commit it, and create the +tag in one atomic step. This ensures the committed `versionName` matches the +tag (required for F-Droid, which builds from tagged source). + +1. Go to **Actions → Release → Run workflow** +2. Enter the version number (e.g. `0.12.2`, without the `v` prefix) +3. Click **Run workflow** + +The workflow will: +- Update `versionName` in `mobile/build.gradle` +- Commit the change to master +- Create and push tag `v{version}` +- Trigger the Build workflow (requires a `RELEASE_PAT` secret — a GitHub PAT with `repo` scope) This will trigger a GitHub Actions workflow which will build the app and upload it to GitHub releases, and deploy it to the Play Store (including the metadata in `./fastlane/metadata/android`). +> **Note for maintainers:** Add a `RELEASE_PAT` secret (repo-scoped GitHub PAT) so +> the tag push from the Release workflow triggers the Build workflow. Without it, +> the Build workflow must be triggered manually after the tag is pushed. + ## More info For more info, check out the main [ActivityWatch repo](https://github.com/ActivityWatch/activitywatch).