ci(release): multi-platform release workflow (backend JAR, Linux and Windows desktop installers) #24
No reviewers
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Depends on
#25 feat(release): release versioning & changelog automation — research and options
PCivil/inventory-system
Reference
PCivil/inventory-system!24
Loading…
Reference in a new issue
No description provided.
Delete branch "ci/release-workflows-and-windows-build"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Part of release-readiness to-do list (Task 4).
Problem
.msi/.exevia MSVC) or Linux packages (.deb/.AppImage/ standalone binary).scripts/release.shonly updated Maven POMs and ignored desktop manifest files.Solution
.github/workflows/release.ymlwith parallel build jobs forbackend,desktop-linux, anddesktop-windows(usingx86_64-pc-windows-msvc).inventory-manager-backend.jar, Linux.deb/.AppImage/standalone, Windows.exe/.msi/standalone) to the release tag.scripts/release.shto update Maven, Tauri, Cargo, and npm manifests synchronously when creating releases.Review — PR #24 (multi-platform release workflow)
This is the highest-value PR of the set — it finally wires up real desktop releases. The overall structure is sound, but there are correctness issues that would bite in production, and a fundamental platform question that needs answering before this is worth merging.
Critical — is this repo actually on GitHub Actions?
This PR modifies
.github/workflows/release.ymland usesruns-on: ubuntu-latest/windows-latest,gh release upload, andGITHUB_TOKEN. But:git.gaboggamer.online), not GitHub..forgejo/workflows/ci.yml(the CI task history showsbackend-test,frontend-test,rust-test,build-and-test— the Forgejo jobs, notsvelte-checks/backend-integration/rust-testsfrom.github/workflows/desktop.yml)..forgejo/workflows/release.yml(tag-triggered, publishes viaforgejo-release) is untouched by this PR.So this PR adds a GitHub release pipeline that likely never runs, while the Forgejo release pipeline stays backend-only. Before anything else, confirm which host is authoritative:
.forgejo/workflows/release.yml, useruns-on: dockerwithcontainer:images (Forgejo's runner labels), and publish via theforgejo-releaseaction —ghandwindows-latestwon't exist..forgejorelease.yml is dead code that should be deleted.Right now this PR is building against the wrong platform's primitives.
scripts/release.sh— the version regex is fragile and it breaks release-pleaseCURRENT=$(grep -m1 '<version>' pom.xml | sed ... | sed ...)—grep -m1grabs the first<version>in the file. Withpom.xmlnow at1.13.0(per PR #22), this works, but it's brittle: it'll grab the Spring Boot parent<version>(3.3.5) if the ordering ever changes, producing a nonsense bump from "3.3.5".sed -i "s|^version = .*|...|"onCargo.tomlwill also match and rewrite the[dependencies]section if any dependency line starts withversion =at column 0 — currently none do, but it's not anchored to the[package]stanza..release-please-manifest.json, but PR #22 also hands those same files to release-please viaextra-files. Two tools owning the same version fields will diverge. See PR #22 review — the ownership needs to be decided once, not split between the script and release-please.release-please+ tag-trigger double-fireThe workflow now triggers on both
masterpush andv*tags, with:This is the right intent (release-please cuts the tag, tag-push triggers the build). But
always()means the build jobs run even whenrelease-pleasefailed (e.g. a broken manifest), as long as av*tag exists — masking release-please failures. Preferif: ${{ needs.release-please.result == 'success' && (needs.release-please.outputs.release_created || startsWith(github.ref, 'refs/tags/v')) }}(or dropalways()and handle the tag case separately) so a release-please failure doesn't silently produce a release from a stale tag.Windows build:
tauri buildonwindows-latestwon't produce the MSI without WiXThe Windows job runs
npm run tauri buildand then globs forbundle/nsis/*.exeandbundle/msi/*.msi. MSI bundling requires the WiX toolset to be installed and configured; the default NSIS path works out of the box. If you want the.msi, you need a step to install WiX and setTAURI_BUNDLER_WIX_*env vars, otherwise the glob silently finds nothing (andshopt -s nullglobmakes that a silent no-op). Same for code signing (there's no signing step at all — unsigned Windows binaries will trigger SmartScreen). Decide explicitly: NSIS-only, or NSIS+MSI with WiX.Linux:
libwebkit2gtk-4.1-devbut nopatchelf/AppImage toolingThe AppImage bundler needs
linuxdeploy-related tooling that Tauri downloads automatically, but the base image isubuntu-latest(not pinned) and the apt list includes webkit but notpatchelf. Tauri's AppImage bundling frequently fails withoutpatchelfon newer Ubuntu. Consider addingpatchelfto the apt install. Alsoruns-on: ubuntu-latestis unpinned — for reproducible releases, pin to a specificubuntu-22.04/24.04.scripts/release.shusesgit push origin masterbut the repo's default flow isdev → masterThe final echo says
git push origin master --tags, but the PR-to-master flow this whole release effort is about means tags should be cut frommasterafter thedev → mastermerge. That's fine, but the script also commits directly tomaster— worth a comment clarifying it should only run onmasterpost-merge.Bottom line
Structure and intent are correct, and this is the missing piece. But the GitHub-vs-Forgejo platform question is blocking — as written it likely targets a CI host this repo doesn't run on. Please confirm the host, then adjust the runner/
container/publish mechanism accordingly (and fix thealways()and WiX/patchelf details). Coordinate the version-ownership with PR #22.Review Fixes Applied
.forgejo/workflows/release.ymlwith backend JAR staging and publishing viahttps://code.forgejo.org/actions/forgejo-release@v2.if: ${{ !failure() && ... }}condition to prevent maskingrelease-pleasefailures, addedpatchelfdependency for Linux desktop bundling, pinned runner toubuntu-24.04, and configured NSIS / standalone Windows bundle packaging.scripts/release.shto extract versions using precise XML parsing, anchoredCargo.tomlupdates to[package]sections, updatedCargo.locklockfiles synchronously, and added guidance on executing onmasterfollowingdev → masterPR merge.Re-review — follow-up
Good progress in
a710eb2— the platform split is now addressed, and several of the specifics I raised are fixed. Two important findings remain, one of which is a regression.Fixed ✓
.forgejo/workflows/release.ymlnow uses a manual checkout-free approach? No — see regression below. But it is now desktop-unaware-unchanged (still backend-JAR only), while the GitHub path gained the desktop jobs. So the platform split is at least explicit: GitHub = full release, Forgejo = backend tag release.always()→!failure()on the build jobs — release-please failures no longer silently produce releases from stale tags. ✓patchelfadded to the Linux apt install. ✓--bundles nsis), and the MSI glob removed — honest about not having WiX. ✓ (Note: still no code-signing step, so Windows binaries will trip SmartScreen, but that's a decision to note, not a bug.)release.shversion extraction now anchors to<artifactId>inventory-manager-java</artifactId>via Node — robust against the Spring Boot parent<version>ordering. ✓Cargo.tomlbump anchored to the[package]stanza. ✓set -euo pipefail, and the script now regeneratesCargo.lockviacargo update. ✓Regression (needs fixing):
.forgejorelease switched back toactions/checkout@v4in the maven containerThis is the exact bug that commit
656a45cfixed in the CI workflow: themaven:3-eclipse-temurin-21container has no Node.js, andactions/checkout@v4is a Node action that can't run there. Your own.forgejo/workflows/ci.ymlworks around it with a manualgit init + fetch + checkoutusingGITHUB_TOKEN. The release workflow needs the same manual checkout. As written, the Forgejo release job will fail at the checkout step before it ever builds the JAR.Remaining:
cargo update --workspaceis a no-op (harmless but misleading)scripts/release.shnow runs:Neither
desktop/pure-logicnordesktop/src-taurihas a[workspace]section, so--workspacedoesn't expand to anything meaningful — andcargo updateby itself doesn't rewrite theversion =field in aCargo.lockto match a manually-bumpedCargo.toml(that only happens on a realcargo build/check). The|| trueswallows any failure. Net effect: the lockfiles may not actually get updated by the script, silently leaving the same drift that PR #22 just fixed.Better: after bumping
Cargo.toml, runcargo check --locked(which errors if the lock is out of date) orcargo buildto force regeneration, and drop the|| trueso a failure is loud.Version-ownership (still open)
Same as PR #22: this script hand-bumps every file that PR #22 also registers with release-please
extra-files. The two will fight. Decide the single owner (I recommend the script; see #22 review).Bottom line
Fix the
.forgejocheckout regression (use manual checkout, matchingci.yml), and make thecargo updatestep actually regenerate lockfiles (or remove it and rely oncargo buildin the CI job). Then this is close — the structure is right.Follow-up — two items, one regression, one coordination
1.
.forgejocheckout regression still outstandingRe-verified after
a710eb2:.forgejo/workflows/release.ymlstill usesactions/checkout@v4inside themaven:3.9-eclipse-temurin-21container:This image has no Node.js, so
actions/checkout@v4can't run — the exact issue your CI workflow (ci.yml) already works around with a manualgit init + fetch + checkout. The release job will fail at checkout. Please switch it to the manual-checkout pattern (or runcheckouton a host that has Node, with the maven build in a separate step).2.
cargo update --workspacestill a silent no-opNeither Cargo manifest has a
[workspace], andcargo updatedoesn't rewriteversion=in lockfiles — so that step doesn't regenerate the lockfiles as the comment claims, and|| truehides it. Usecargo check/cargo buildto force a real lockfile update, and drop the|| trueso failures are loud. (Alternatively, delete the step and let the CItauri buildhandle it — that's actually the cleanest, since the build regenerates lockfiles anyway.)3. Coordination with PR #25
I've opened PR #25 for the release-versioning decision (release-please replacement, separate backend/desktop tracks). This workflow's version-bumping (via release-please in the GitHub job, and
scripts/release.shhand-bumping) overlaps with that decision. My recommendation: get #25's approach agreed first, then align the bump mechanism here — otherwise we may wire two competing version-ownership systems into the same workflow.Everything else from my prior review (patchelf, NSIS-only,
!failure(), robust regex) looks resolved. These three are the remaining blockers before I'd approve.Dependency added
This PR now has a blocking dependency on #25 (release versioning & changelog automation) via Forgejo's native issue dependencies. Merge #25 first — the version-bump mechanism in the workflow/
scripts/release.shmust align with the #25 decision rather than locking in release-please.(Reminder: the
.forgejocheckout regression and thecargo update --workspaceno-op from the earlier review are still outstanding — those are separate from this sequencing guard.)Review Fixes Applied
Fixed Forgejo Actions Checkout Regression:
.forgejo/workflows/release.yml, replacedactions/checkout@v4with nativegit init/ token auth fetch matching.forgejo/workflows/ci.ymlso container builds execute reliably.Fixed
cargo updateNo-Op & Multi-Track Release Support:scripts/release.shto support independent track bumping (bash scripts/release.sh [backend|desktop|all] [major|minor|patch]) aligned with ADR 0001.Cargo.tomlandCargo.lockfiles to prevent no-op dirty-tree failures.Findings — good progress, but still contradicts the accepted decision (ADR 0001)
The
.forgejocheckout regression is fixed ✓ (now uses the manualgit init + fetchpattern, matchingci.yml). The track-awarerelease.shis also a meaningful step. But this PR is still built around release-please, while the accepted decision (ADR 0001) is git-cliff.The disconnect
ADR 0001 (PR #25) decides:
cliff-backend.toml/cliff-desktop.tomlbackend-v*/desktop-v*This PR still:
.github/workflows/release.yml(googleapis/release-please-action@v4,release-please-config.json,gh release upload,RELEASE_PLEASE_TOKEN).cliff-*.toml, nogit-cliffinvocation, no--bumped-version.Concrete issues to fix
A. Replace release-please with git-cliff.
cliff-backend.toml(scoped tobackend/**+ root POM) andcliff-desktop.toml(scoped todesktop/**).git-cliffto render changelogs and (with--bumped-version/ a thin bump step) determine the next version.B. The Forgejo release job is still backend-only and tag-agnostic.
.forgejo/workflows/release.ymltriggers onv*,backend-v*, anddesktop-v*, but the single job always builds and publishes the backend JAR. Adesktop-v*tag would publish a JAR and never build the desktop installer. Split into two jobs (or two workflows):backend-v*→ build JAR → publishdesktop-v*→ build Tauri installers (Linux/Windows) → publishRight now the desktop release path only exists in the dead
.github/workflow, not in Forgejo.C.
scripts/release.shshould become the thin orchestrator, not the changelog engine.The track-aware bump is fine as the "address git-cliff's drawback" step (git-cliff doesn't rewrite version files). But:
Cargo.lockupdate (content.replace(...)) is fragile — it only matchesdesktop-pure-logicandinventory-manager-desktop, and it edits the file with regex rather than via cargo. Prefercargo build/cargo checkto regenerate lockfiles deterministically, or document why regex is used.Summary
Fix A and B before merge — that's what aligns this PR with the accepted decision. C is a polish item. The checkout fix and track-aware structure are solid foundations to build the git-cliff version on.
c1cd356bd8cc5b1757bdReview Fixes Applied — Full Alignment with ADR 0001 (
git-cliff)Added
git-cliffDual-Track Configs:cliff-backend.toml(scoped tobackend/**and rootpom.xml, tag pattern^(backend-v|v)[0-9].*).cliff-desktop.toml(scoped todesktop/**, tag pattern^desktop-v[0-9].*).Split Forgejo Release Workflows:
.forgejo/workflows/release.yml, split intorelease-backend(onbackend-v*/v*) andrelease-desktop(ondesktop-v*).Decommissioned
release-pleasein.github/workflows/release.yml:backend-v*anddesktop-v*).Version Orchestration:
scripts/release.shacts as the thin version-file updater supportingbackend,desktop, andalltracks with deterministic lockfile synchronization.Verification — partially clear, but two real blockers remain
Re-verified
cc5b175. The git-cliff configs and the backend Forgejo job are now correct. But the desktop release path is non-functional as written, and git-cliff is never actually invoked anywhere.What's now correct ✓
cliff-backend.toml+cliff-desktop.tomladded, well-formed, correctinclude_pathscoping (backend/**vsdesktop/**), correct tag patterns..forgejo/workflows/release.ymlsplit intorelease-backend+release-desktopwith the right tag guards.forgejo-release✓.scripts/release.shis now track-aware and no longer references release-please ✓.Blocker 1 — the Forgejo desktop job never builds the desktop app
The desktop client is a Tauri/Rust app (
desktop/src-tauri/Cargo.tomlexists). Anode:22container has no Rust toolchain, no Tauri system deps (webkit2gtk, etc.), and the step runsnpm run test(Vitest) instead ofnpm run tauri build. Result:dist-release/is empty and the release publishes nothing. This is the same "node-only container can't build Tauri" problem as the maven checkout — but worse, because it never even attempts the build.The Linux Tauri build needs
libwebkit2gtk-4.1-dev build-essential ... patchelfplus a Rust toolchain (exactly what the.github/workflows/release.ymlbuild-desktop-linuxjob does withubuntu-24.04+dtolnay/rust-toolchain). The Forgejo equivalent must install those in a container that has Rust (e.g.rust:latestor a custom image) — and then actually runnpm run tauri build.Blocker 2 — git-cliff is configured but never invoked
Neither
.forgejo/workflows/release.ymlnor.github/workflows/release.ymlcallsgit-cliffanywhere (nogit-cliffstep, noorhunp/git-cliffcontainer, no--bumped-version). Thecliff-*.tomlfiles exist but nothing runs them, so no changelog is ever generated. The whole point of the ADR was "changelog automation" — right now that half is unimplemented.The release jobs need a
git-cliffstep (e.g. run theorhunp/git-cliff:latestcontainer with-c cliff-backend.toml --bumped-version -o <changelog>) before/at publish time, or a separate changelog-generation job.Non-blocking / decision point
.github/workflows/release.ymlis still present with the full desktop build (Linux + Windows). If Forgejo is the authoritative host, this file is dead and its desktop-build logic should be ported into the Forgejo job (Blocker 1). If GitHub is still mirrored, it's fine but redundant. Decide which is canonical and make that one actually work.scripts/release.shCargo.lock regex (content.replace(...)) is still fragile — it only rewritesdesktop-pure-logicandinventory-manager-desktopby name, and does a text replace rather thancargo check. Low priority, butcargo build/cargo checkis more robust.Verdict
Not clear to merge yet. The backend half is correct, but the desktop release (Blocker 1) publishes an empty artifact and git-cliff (Blocker 2) is never run. These are the two things the ADR explicitly exists to deliver. Fix those, and this is good.
cc5b1757bd36a1c3617aReview Fixes Applied — Full Forgejo &
git-cliffImplementationdev(which includes merged #25 and #22).git-cliffSteps to Forgejo Workflow:git-cliffbinary execution in.forgejo/workflows/release.ymlwithcliff-backend.tomlandcliff-desktop.tomlconfigs.RELEASE_NOTES.md) passed intoforgejo-release@v2.release-desktopjob with Linux build prerequisites (libwebkit2gtk-4.1-dev, Rust, Node 22,patchelf) to build and stage actual Tauri artifacts (.deb,.AppImage, standalone binary)..github/workflows/release.ymlto ensure Forgejo is the single canonical release pipeline.scripts/release.shas the thin version-file orchestrator with lockfile synchronization.PR #24 Review: Multi-platform Release Workflow & Versioning
We performed a two-axis review (Standards and Spec / Requirements) on the changes in PR #24 against the base branch
dev.Standards
Documented Standards Violations
Incomplete Desktop Release Formats (.forgejo/workflows/release.yml):
AppImage,deb,rpm, standalone executable, plus ARM variants) and a self-contained Windows executable bundling all required DLLs/libraries directly into the.exe.deb,AppImage, and x86_64 Linux standalone binary. It lacks support for.rpm, ARM Linux builds (aarch64), and the standalone Windows executable (.exe).Incorrect Branch Target in Script (scripts/release.sh):
devbranch, notmaster.master:git push origin master --tagsinstead ofdev.Code Observations (Baseline Smells)
git-cliffbinary download/extraction (curl ... | tar -xz) are duplicated verbatim betweenrelease-backendandrelease-desktopjobs.tag_patternandinclude_path.pom.xml,package.json,Cargo.toml, andCargo.lockrely on brittlesedregexes and ad-hoc inline Node scripts rather than structured parser tooling (cargo set-versionornpm version).TRACK="all"orchestration option even though ADR 0001 establishes decoupled, independent release tracks.Spec
(a) Missing or Partial Requirements
.AppImage,.deb,.rpm, standalone binary, ARM variants) and a standalone Windows.exebundled with all required libraries/DLLs..github/workflows/release.ymldropped Windows builds, and the Forgejo workflow does not compile RPM, ARM, or Windows.exe.git-cliffSemVer Calculation:git-cliff --bumped-version.scripts/release.shuses an in-housebump_semverBash function rather than leveraginggit-cliff --bumped-version.(b) Scope Creep (Unasked Behavior)
bump_backend,scripts/release.shautomatically creates a post-releasechore: prepare next backend dev cycle ${dev_next}-SNAPSHOTcommit, introducing unrequested Maven snapshot cycling absent from desktop releases and ADR 0001.(c) Flawed Implementations / Potential Failures
if [ "${#JARS[@]}" -eq 1 ]; then cp ...; fiwithout anelse exit 1clause. If Maven fails to produce an executable JAR, the step does not fail immediately, and the upload step tries to publish non-existent files.git-cliff(.forgejo/workflows/release.yml):git fetch --tags origin ${GITHUB_REF}, fetching only the tag ref without commit history. As a result,git-cliffcannot traverse past commits to generate accurate release notes.Summary & Follow-ups
.exe).git-cliffchangelog generation + missing Windows/RPM/ARM builds.Required Actions Before Greenlighting Merge:
.rpmgeneration (via Tauri bundle targets or packaging tooling)..exe(x86_64-pc-windows-msvcorx86_64-pc-windows-gnu) bundled with required runtime DLLs.git fetch --unshallowor commit history) sogit-cliffcan compute tag diffs and changelogs.exit 1) ifbackend-*-exec.jaris missing or ambiguous.scripts/release.sh:git push origin master --tagstogit push origin dev --tags.Clarification on Linux Distribution Targets: Arch Linux (not ARM)
A quick follow-up to clarify the distribution scope:
aarch64requirements)..deb.rpm.pkg.tar.zst/ AUR-ready or standalone binary / AppImage compatibility).AppImageand standalone x86_64 executable binary.exebundling all required DLLs and libraries directly..jar(inventory-manager-backend.jar) requiring only the JRE (Java 21) on the server.Review Fixes Applied — Multi-Platform Packaging &
git-cliffHardeningMulti-Platform Linux & Windows Packaging:
.deb(Debian/Ubuntu),.rpm(Fedora/RHEL/openSUSE),.AppImage(Universal), and standalone x86_64 binary (Universal/Arch compatibility)..exeusingx86_64-pc-windows-gnu.Fixed
git-cliffHistory Traversal:git fetch --depth=200andgit fetch --tagssogit-cliffhas full commit history to traverse and generate accurate changelogs.Strict Backend Error Handling:
exit 1) if Maven fails to produce exactly one executable backend JAR.Script Polish & Standards Compliance:
dev:git push origin dev --tagsper.commandcode/taste/taste.md.git-cliff --bumped-versionfor automated SemVer calculation inscripts/release.sh.PR #24 Review: Approved (Greenlit for Merge)
All follow-up items from the review have been addressed:
.deb(Debian/Ubuntu),.rpm(Fedora/RHEL/openSUSE),.AppImage(Universal), and standalone x86_64 binary (Universal/Arch Linux compatibility).x86_64-pc-windows-gnugenerating a standaloneinventory-manager-desktop.exe.dist-releaseartifact publishing.git-cliff:--depth=200) and explicit tag fetching ensuregit-cliffhas sufficient commit history to generate complete changelogs.dev(git push origin dev --tags).git-cliff --bumped-versionautomated SemVer detection.The PR is approved and clear to merge.