feat(ci): add independent manylinux_2_28 Qt build target (glibc 2.28 ABI floor) - #1409
Conversation
Adds a new `build-qt-manylinux-2-28` CI job that builds ActivityWatch inside `quay.io/pypa/manylinux_2_28_x86_64`, producing Linux binaries compatible with glibc 2.28 (RHEL/CentOS/AlmaLinux/Rocky 8 and older). The change is purely additive: the existing `build-qt` and `build-tauri` platform matrices are untouched. Key decisions: - `git config safe.directory` is set immediately after checkout, before the first version probe, so the version string is correct throughout the build. - Artifacts are renamed with a `-manylinux_2_28` suffix to avoid any name collision with the standard Ubuntu build. - An offline ABI gate (`scripts/package/abi-gate.sh`) scans every ELF in both the ZIP and AppImage payload and fails if any symbol requires a GLIBC version above 2.28. - The release job's `needs` list now includes `build-qt-manylinux-2-28` so the manylinux artifacts are included in every tagged release. Closes ActivityWatch#1390
Greptile SummaryThe PR adds an independent manylinux_2_28 Qt build that produces and ABI-checks Linux artifacts for glibc 2.28 systems.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
Tag[Tag or source revision] --> Build[Build Qt in manylinux_2_28 container]
Build --> Package[Create ZIP and AppImage]
Package --> Rename[Add manylinux_2_28 suffix]
Rename --> Gate[Scan bundled ELFs for GLIBC above 2.28]
Gate --> Upload[Upload build artifacts]
Upload --> Release[Attach artifacts to draft tagged release]
Reviews (2): Last reviewed commit: "fix(ci): add server version guard and ha..." | Re-trigger Greptile |
| - name: Set up Node | ||
| uses: actions/setup-node@v6 |
There was a problem hiding this comment.
Missing bundled-server version guard
When a release tag is built with an aw-server-rust submodule from another major or minor release line, this job proceeds directly from version detection to building and publishing the server inside its manylinux assets. Unlike the standard Qt and Tauri jobs, it never rejects the mismatch, causing the release to ship an incompatible or stale server binary.
Knowledge Base Used:
| ;; | ||
| esac | ||
| done |
There was a problem hiding this comment.
When both AppImage extraction methods fail, this branch only prints a warning and the script later exits successfully from an empty violation log. The release can therefore publish an unscanned AppImage containing GLIBC references above 2.28; extraction failure must make the gate fail.
Knowledge Base Used: Build and distribution
| if: github.event_name == 'push' || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' | ||
| runs-on: ubuntu-22.04 | ||
| container: | ||
| image: quay.io/pypa/manylinux_2_28_x86_64 |
There was a problem hiding this comment.
Mutable release build dependencies
This release-producing job selects its container by an unpinned tag and also uses mutable major-version tags for checkout, Node setup, caching, and artifact upload. Repointing any of these upstream tags changes the code producing published manylinux binaries without a repository change or an artifact-integrity check, so pin the container digest and action SHAs. How this was verified: The job uploads these assets, and the release job downloads all artifacts and attaches them without a checksum or provenance guard.
Knowledge Base Used: Automation and maintenance
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
The glob 'mv aw-qt-tmp/*' skips dotfiles, leaving aw-qt-tmp non-empty and causing 'rmdir: failed to remove aw-qt-tmp: Directory not empty' in the manylinux_2_28 container. Switch to cp -a dir/. which copies all files (including hidden) then rm -rf the source directory.
|
CI investigation: two failures, different root causes. manylinux_2_28 job (mine to fix) — fixed in 25617da: The macOS job — pre-existing, not caused by this PR:
|
Two P1 issues from Greptile review: 1. Manylinux job lacked the aw-server-rust version guard that build-qt and build-qt-tauri already have. Without it a tagged release could ship a manylinux bundle containing an aw-server binary from a mismatched release line. The new step is identical to the guard in those jobs. 2. abi-gate.sh failed open when AppImage extraction failed — it warned and exited 0, so a release could publish an unscanned AppImage containing GLIBC refs above 2.28. Extraction failure now exits 2 (script error).
|
@greptileai review |
|
Fixed the two P1 findings from the Greptile review (commit a270596): 1. Missing aw-server-rust version guard in the manylinux job — Added the same 2. AppImage ABI scan fails open on extraction failure — Changed Greptile re-review triggered. |
cp -a dist/activitywatch/aw-qt/. dist/activitywatch/ fails because the aw-qt binary inside the dir has the same name as the source directory — cp can't overwrite the directory with the non-directory. Move to a temp name first, then copy contents, then remove.
|
All CI checks now pass. PR is ready for maintainer review. |
Summary
Closes #1390.
Adds a new, independent
build-qt-manylinux-2-28job that produces ActivityWatch Linux binaries compatible with glibc 2.28 (RHEL 8, CentOS 8, AlmaLinux 8, Rocky Linux 8, and similar enterprise distributions that currently seeGLIBC_2.29 not founderrors with the standard build).The existing
build-qtandbuild-tauriplatform matrices are completely untouched.What changed
.github/workflows/release.ymlbuild-qt-manylinux-2-28that runs onubuntu-22.04inside thequay.io/pypa/manylinux_2_28_x86_64container.dnfto install Qt 5 and build dependencies (EPEL-backed, compatible with the container's AlmaLinux 8 base)./opt/python/cp39-cp39/bin/python3(the manylinux CPython 3.9 with a sharedlibpython, required by PyInstaller).APPIMAGE_EXTRACT_AND_RUN=1so linuxdeploy/appimagetool work without FUSE.OPENSSL_NO_VENDOR=1to use the container'sopenssl-develinstead of building OpenSSL from source.git config safe.directoryis the first step after checkout, so the version probe never falls back tov0.0.0.dev-unknown.-manylinux_2_28suffix (both the ZIP and the AppImage) to avoid collisions with the standard build:activitywatch-<version>-linux-x86_64-manylinux_2_28.zipactivitywatch-linux-x86_64-manylinux_2_28.AppImageGLIBC_2.28.releasejob'sneedslist now includesbuild-qt-manylinux-2-28, so the manylinux artifacts appear in every tagged release alongside the existing assets.scripts/package/abi-gate.sh(new)Offline ABI verifier:
.zip/.AppImagefiles.unzip(ZIP) orunsquashfs/--appimage-extract(AppImage).readelf --version-info.GLIBC_2.28is found.Compatibility evidence
The premise was verified against the contributor's proven artifact (Actions run 30827174168):
GLIBC_2.28, zero above.GLIBC_2.28, zero above.The fork workflow that produced that artifact is not directly upstreamable — it replaces the Qt matrix and removes Tauri/DEB jobs. This PR ports only the proven container method, rebuilt surgically from current upstream
master.What this PR does NOT do
build-qtorbuild-taurijobs.