Skip to content

feat(release): auto-set versionName from tag on release builds#168

Merged
ErikBjare merged 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:bob/release-automation
Jul 1, 2026
Merged

feat(release): auto-set versionName from tag on release builds#168
ErikBjare merged 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:bob/release-automation

Conversation

@TimeToBuildBob

@TimeToBuildBob TimeToBuildBob commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Automate the release process via workflow_dispatch so the full release — version bump, commit, tag, and build trigger — happens in one atomic step.

Problem with the previous approach (tag-push patching):

  • The sed regex had a bug: it matched up to but not including the closing quote of the existing versionName, leaving a dangling " after substitution → Groovy syntax error, Gradle build fails
  • F-Droid builds from tagged source directly, so patching after checkout never helped F-Droid anyway — the committed source still had the old version

New approach:

  • Added .github/workflows/release.yml (workflow_dispatch) that:
    1. Validates version format and checks the tag doesn't exist
    2. Updates versionName in mobile/build.gradle with a correct sed (matches both surrounding quotes, no trailing characters)
    3. Commits to master and pushes an annotated tag
    4. Tag push via RELEASE_PAT triggers the Build workflow
  • Reverted the broken "Set versionName from tag" step back to "Verify versionName matches tag" from fix(release): require committed versionName for tag builds #155

F-Droid compatibility: The tag now always points to a commit where versionName is correct in the source — because the Release workflow commits it before tagging.

Usage: Actions → Release → Run workflow → enter version (e.g. 0.12.2)

One-time setup: Add a RELEASE_PAT secret (repo-scoped GitHub PAT). Required so the tag push triggers the Build workflow (GitHub restricts GITHUB_TOKEN pushes from triggering other workflows). Documented in release.yml and README.

@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown

Greptile Summary

This PR automates versionName stamping at release time: instead of requiring a manual build.gradle edit before tagging, a new CI step patches the file in-place from the tag name and the README is updated accordingly.

  • The sed substitution regex does not consume the closing quote of the existing versionName value, so the patched line becomes versionName '0.x.y'" — a Groovy syntax error that breaks the Gradle build on every tag push. The grep verification step produces a false positive and does not catch this.
  • F-Droid, which builds directly from the tagged commit source without running CI, will continue to see the stale committed versionName; the now-incorrect comment in mobile/build.gradle that documents the old contract also needs updating.

Confidence Score: 2/5

The sed regex in the new Set versionName from tag step would corrupt build.gradle on every tag push, making the release pipeline fail at the Gradle parse step — the very scenario this PR is designed to automate.

The sed command omits the closing quote from its match, leaving a dangling " on the versionName line after substitution. Gradle will fail to parse the file, so no APK or AAB is produced on any tagged release. The downstream grep check passes anyway because it only tests for the presence of the new version string and doesn't assert the line ends cleanly.

.github/workflows/build.yml — specifically the sed substitution and verification logic in the Set versionName from tag step. mobile/build.gradle (outside the diff) has a stale comment that contradicts the new approach.

Important Files Changed

Filename Overview
.github/workflows/build.yml Replaces version-verification step with a sed-based in-place patch of build.gradle; contains a regex bug that leaves a dangling closing quote and would cause every tagged release build to fail with a Gradle syntax error.
README.md Updates release instructions to reflect the new tag-and-push workflow; prose change is accurate and clearly written.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Dev as Developer
    participant GH as GitHub
    participant CI as GitHub Actions (build-apk)
    participant BG as build.gradle (CI checkout)
    participant Rel as Release artifacts

    Dev->>GH: git push tag v0.x.y
    GH->>CI: "Trigger workflow (refs/tags/v*)"
    CI->>BG: sed patch versionName → 0.x.y
    Note over BG: ⚠️ closing quote not consumed,<br/>line becomes: versionName '0.x.y'"
    CI->>CI: grep verify (passes — false positive)
    CI->>BG: sed patch versionCode (fastlane value)
    CI->>CI: ./gradlew assemble
    Note over CI: ❌ Gradle parse error on<br/>malformed versionName line
    CI-->>Rel: Build fails — no APK/AAB produced
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Dev as Developer
    participant GH as GitHub
    participant CI as GitHub Actions (build-apk)
    participant BG as build.gradle (CI checkout)
    participant Rel as Release artifacts

    Dev->>GH: git push tag v0.x.y
    GH->>CI: "Trigger workflow (refs/tags/v*)"
    CI->>BG: sed patch versionName → 0.x.y
    Note over BG: ⚠️ closing quote not consumed,<br/>line becomes: versionName '0.x.y'"
    CI->>CI: grep verify (passes — false positive)
    CI->>BG: sed patch versionCode (fastlane value)
    CI->>CI: ./gradlew assemble
    Note over CI: ❌ Gradle parse error on<br/>malformed versionName line
    CI-->>Rel: Build fails — no APK/AAB produced
Loading

Reviews (1): Last reviewed commit: "feat(release): auto-set versionName from..." | Re-trigger Greptile

Comment thread .github/workflows/build.yml Outdated
Comment on lines +228 to +233
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

}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 sed pattern omits the closing quote, corrupting build.gradle

The regex ends after the version digits ([^\"']+) without consuming the original closing quote, so the substitution replaces only versionName "0.12.1 and leaves the trailing " in place. The resulting line becomes versionName '0.13.0'", which is a Groovy syntax error that will crash the Gradle parse step. The subsequent grep verification still passes because it only checks for versionName '${SHORT_VERSION}' and doesn't assert that nothing follows — so the broken file silently slips through.

Fix: extend the pattern to also match and discard the closing quote:

sed -i -E "s/^([[:space:]]*)versionName[[:space:]]+[\"'][^\"']+[\"']/\1versionName '${SHORT_VERSION}'/" mobile/build.gradle

Comment thread .github/workflows/build.yml Outdated
Comment on lines +222 to +234
- 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}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 F-Droid compatibility broken by patching-in-CI approach

mobile/build.gradle still carries a comment explaining that versionName is kept committed in source precisely so "tagged builds and F-Droid agree" — F-Droid builds directly from the tagged commit without running the CI workflow, so it reads whatever versionName value was committed. Under the previous workflow the committed value was forced to match the tag, keeping both in sync. After this change the committed value is never updated, so F-Droid will always report the stale pre-tag version. The stale // Tag workflows verify it matches… comment in mobile/build.gradle also needs updating to reflect the new behaviour.

@ErikBjare

Copy link
Copy Markdown
Member

@TimeToBuildBob Not sure this is what I had in mind, as Greptile noticed. Need to figure out a way to make this work with e.g. F-Droid without having the tag point to a commit with the wrong versionName. Maybe skipping tag-pushes to release is a good idea, and instead do it all from a workflow_trigger which can run pre-release checks, commit, tag, and then trigger the build and deploy on that tagged release commit.

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 ActivityWatch#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.
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Redesigned per your feedback. The new approach:

What changed (commit ac07957):

  • Reverted the broken sed step back to "Verify versionName matches tag" (from fix(release): require committed versionName for tag builds #155)
  • Added .github/workflows/release.yml — a workflow_dispatch workflow that does the full release atomically:
    1. Validates version format + checks the tag doesn't already exist
    2. Updates versionName in mobile/build.gradle with a correct sed (matches both surrounding quotes, no dangling characters)
    3. Commits to master + pushes an annotated tag
    4. The tag push (via RELEASE_PAT) triggers the existing Build workflow

For F-Droid: the tag now always points to a commit where versionName is already correct in the source, since the Release workflow commits it before tagging.

To release: Actions → Release → Run workflow → enter version (e.g. 0.12.2)

One-time setup needed: Add a RELEASE_PAT secret (repo-scoped GitHub PAT). Without it, the GITHUB_TOKEN push won't trigger the Build workflow automatically (GitHub restriction). Documented in the new release.yml header and README.

@ErikBjare ErikBjare merged commit 1ca0268 into ActivityWatch:master Jul 1, 2026
7 checks passed
@ErikBjare

Copy link
Copy Markdown
Member

@TimeToBuildBob merged, chase me to set the PAT

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Noted. RELEASE_PAT is the only post-merge setup item now.

I created a local follow-up task to chase this: aw-android-release-pat-secret. Until that secret exists, the new Release workflow can update/commit/tag, but the tag push will not reliably trigger the Build workflow.

Concrete ask when you have a minute: add a repo-scoped PAT as the RELEASE_PAT secret in ActivityWatch/aw-android, then run one release workflow dry pass / next release to confirm the tag-triggered Build starts.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Tracked in ErikBjare/bob#1020 — will chase you on setting the PAT once the queue clears.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants