Skip to content

refactor(ci): unify build and release workflows#1313

Open
TimeToBuildBob wants to merge 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:bob/unify-release-ci-5696
Open

refactor(ci): unify build and release workflows#1313
TimeToBuildBob wants to merge 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:bob/unify-release-ci-5696

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Summary

  • replace the split dev-release.yml, build.yml, and build-tauri.yml workflows with a single release.yml
  • keep the current dev prerelease preflight/tagging logic, including exact-SHA tagging and self-exclusion of the current workflow run
  • build Qt and Tauri artifacts from one workflow file and publish one combined draft GitHub release on tag pushes

Testing

  • parsed .github/workflows/release.yml with python3 + yaml.safe_load
  • ran git diff --check
  • verified current release assets already use distinct activitywatch-... and activitywatch-tauri-... names, so the combined release upload set is collision-safe

Refs #1219

@TimeToBuildBob TimeToBuildBob force-pushed the bob/unify-release-ci-5696 branch from 6664f21 to 503830d Compare June 1, 2026 11:51
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Rebased this draft PR on bf66fa6 and force-pushed 503830d.

Conflict resolution: the three old workflow files are still intentionally deleted, and I ported the new upstream workflow fixes into .github/workflows/release.yml instead: higher prerelease-line continuation, auxiliary-check filtering, version diagnostics, WebKit pin / Tauri Linux artifacts, macOS artifact naming, and the action version bumps.

Local validation: yaml.safe_load on release.yml passes, and git diff --check upstream/master...HEAD is clean. GitHub now reports the PR as mergeable; CI is pending on the new head.

@greptile-apps

greptile-apps Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR consolidates three separate GitHub Actions workflow files (build.yml, build-tauri.yml, dev-release.yml) into a single release.yml. Job-level if guards gate each logical phase: preflight/create-tag on schedule/workflow_dispatch, build-qt/build-tauri on push/pull_request, and release-notes/release on tag pushes only.

  • The previously duplicated release-notes jobs (one in each build workflow) are unified into a single job, and the .output.is_stable typo (missing s) from the old files is fixed to .outputs.is_stable.
  • Workflow-level concurrency (concurrency: group: dev-release) is replaced with identical job-level concurrency groups on preflight and create-tag, preserving serialization semantics for the dev-release path.
  • The unified release job gates on needs: [build-qt, build-tauri, release-notes] with a combined artifact glob, producing one draft GitHub release per tag instead of two separate ones.

Confidence Score: 5/5

Safe to merge; the refactor faithfully preserves all build, test, package, and release logic from the three deleted files.

All build and release phases use correct if guards that fire on the right event types; the dev-release tag-creation path is logically equivalent to the old standalone workflow; the DMG naming collision raised earlier is resolved in the actual rename commands; the .output.is_stable typo from the old files is fixed. The only notable change is that build jobs now inherit a broader GITHUB_TOKEN scope than before, which is a hardening concern but not a functional defect.

.github/workflows/release.yml — specifically the top-level permissions block and whether per-job scoping is desired.

Important Files Changed

Filename Overview
.github/workflows/release.yml New unified workflow; logic is structurally correct but workflow-level contents: write now grants GITHUB_TOKEN write access to build jobs that don't need it.
.github/workflows/build.yml Deleted; logic migrated to release.yml build-qt job with no regressions observed.
.github/workflows/build-tauri.yml Deleted; logic migrated to release.yml build-tauri job with no regressions observed.
.github/workflows/dev-release.yml Deleted; preflight/create-tag logic migrated to release.yml with equivalent correctness; concurrency moved from workflow-level to job-level.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    trigger([Workflow trigger]) --> schedCheck{schedule or\nworkflow_dispatch?}
    trigger --> pushCheck{push or\npull_request?}

    schedCheck -- yes --> preflight[preflight\nPre-flight checks]
    preflight -- should_release=true --> createTag[create-tag\nCreate dev release tag]
    createTag -- pushes tag --> tagPush([Tag push triggers\nnew workflow run])

    schedCheck -- no --> skip1([skip preflight/create-tag])

    pushCheck -- yes, tag push --> buildQt[build-qt\nQt build matrix\nubuntu / windows / macos]
    pushCheck -- yes, tag push --> buildTauri[build-tauri\nTauri build matrix\nubuntu / ubuntu-arm / windows / macos]
    pushCheck -- yes, tag push --> relNotes[release-notes\nGenerate changelog]
    pushCheck -- yes, non-tag push/PR --> buildQt2[build-qt + build-tauri\nCI only, no release]
    pushCheck -- no --> skip2([skip build jobs])

    buildQt --> release[release\nPublish draft release\non softprops/action-gh-release]
    buildTauri --> release
    relNotes --> release

    tagPush --> trigger
Loading

Reviews (2): Last reviewed commit: "refactor(ci): unify release workflows" | Re-trigger Greptile

Comment on lines +332 to +352
libxrender-dev

- name: Install dependencies
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
choco install innosetup
fi
pip3 install poetry==1.4.2

- name: Build
run: |
python3 -m venv venv
source venv/bin/activate || source venv/Scripts/activate
poetry install
make build SKIP_WEBUI=${{ matrix.skip_webui }} SKIP_SERVER_RUST=${{ matrix.skip_rust }}
pip freeze

- name: Run tests
run: |
source venv/bin/activate || source venv/Scripts/activate
make test SKIP_SERVER_RUST=${{ matrix.skip_rust }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 macOS DMG filename collision in unified release

Both build-qt (line 352) and build-tauri (line 532) rename their macOS output to the identical pattern activitywatch-${VERSION_TAG:-...}-macos-x86_64.dmg. They are uploaded to different artifact containers (builds-macos-14-py3.9 vs builds-tauri-macos-14-py3.9), but when the release job's dist/*/activitywatch-*.* glob collects them both, softprops/action-gh-release@v2 will attempt to upload two assets with the same basename to a single GitHub release, which will either error out or silently overwrite one. The PR description claims distinctness via a activitywatch-tauri-… prefix, but the actual mv command in build-tauri's "Package dmg" step (line 532) produces the same name as build-qt's. If the Makefile or Tauri packaging path never actually creates dist/ActivityWatch.dmg when TAURI_BUILD=true, the step is dead code and the collision never occurs — but that assumption is invisible from the workflow file alone and should be made explicit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The DMG names are already distinct at the actual command. Qt produces activitywatch-${VERSION_WITH_V}-macos-$(uname -m).dmg (line 385) and Tauri produces activitywatch-tauri-${VERSION_WITH_V}-macos-$(uname -m).dmg (line 603). The tauri- prefix is present in the final rename — so when the release job's glob collects both artifact sets, the basenames are distinct and softprops/action-gh-release won't see a collision.

Two other corrections on the review's framing: the variable is VERSION_WITH_V (not VERSION_TAG), and the architecture suffix is dynamic ($(uname -m)) rather than hardcoded to x86_64.

Comment on lines +590 to +593

source venv/bin/activate
make dist/ActivityWatch.dmg

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Single platform failure in either matrix blocks the entire combined release

In the old split design, build.yml and build-tauri.yml each had independent release jobs, so a flaky Tauri build on one platform only blocked the Tauri release while Qt artifacts were still published. With needs: [build-qt, build-tauri, release-notes], a single flaky matrix run in either of the 9 total build jobs (4 Qt + 5 Tauri) now blocks publishing any artifacts at all. If build-tauri's ubuntu-24.04-arm job is unstable, the combined release will never be published. Consider whether continue-on-error at the matrix level or a separate release step per build group better matches the desired failure semantics.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Acknowledged — this is an intentional trade-off. The old split design did mean a flaky Tauri platform left Qt artifacts publishable independently, so the combined needs: [build-qt, build-tauri, release-notes] gate does tighten the coupling.

The rationale for accepting it: real tag releases are rare, manual, and happen on a stable commit — transient flakiness is less likely to bite there than on the dev-prerelease path (which this workflow also handles). If the arm64 or other Tauri job proves unstable in practice, adding continue-on-error: true at the matrix level or splitting into per-group release steps is a straightforward follow-up. Leaving this note here so the trade-off is visible to reviewers.

@TimeToBuildBob TimeToBuildBob marked this pull request as ready for review June 4, 2026 16:08
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Marking ready for review — this has been sitting as a draft but it's complete and CI-green.

Additional verification this round (beyond the original PR-body testing):

  • All build jobs pass on this PR: Qt artifacts (ubuntu/windows/macos) + Tauri artifacts (ubuntu x2, windows, macos). The release-publish jobs (release-notes, release, preflight, create-tag) correctly show SKIPPED on a PR since they're gated on schedule/workflow_dispatch/refs/tags/v*.
  • bash -n on every embedded run: script — 0 syntax errors (the dev-release/preflight logic can't execute on a PR, so this is the cheapest guard against shell typos in the uncoverable path).
  • Verified the dev-release linkage: preflight always computes next_tag as v${base}b${N} (v-prefixed), and create-tag pushes it with AWBOT_GH_TOKEN (a PAT, not GITHUB_TOKEN) — required so the tag push actually re-triggers the workflow's tag-gated release-notes/release jobs.

What can't be CI-tested here (and is worth a careful read): the scheduled dev-release path (preflightcreate-tag → tag-triggered build+release) only runs on schedule/workflow_dispatch. I reviewed it by inspection and it preserves the prior dev-release.yml semantics (biweekly cadence gate, prerelease-line continuation, HEAD-CI-health gate, exact-SHA tagging). Suggest a one-off workflow_dispatch run on a branch to smoke-test it before relying on the nightly cadence.

Refs #1219

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.

1 participant