Skip to content

feat(ci): automate upstream stable/+N releases and consolidate release logic - #163

Open
psadi wants to merge 8 commits into
mainfrom
feature/release-on-merge
Open

psadi wants to merge 8 commits into
mainfrom
feature/release-on-merge

Conversation

@psadi

@psadi psadi commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fully automates the stable release flow and consolidates all release logic into bin/repo-management.sh. The only manual action is merging the release PR.

Flow

  1. Daily schedule detects a new upstream Ghostty stable tag → opens a release/<version> PR that bumps VERSION and pushes the v<version> tag.
  2. PR build is skipped (**/VERSION stays in paths-ignore) — no duplicate run.
  3. Merge to main → a push run scoped to VERSION: build_appimage builds the stable version once, release_stable publishes the GitHub Release (generated notes + both AppImages) if the tag exists.

+N releases and manual override

  • release: published is restored: publishing v<version>+N builds and uploads assets via the existing flow (preserves the release body).
  • workflow_dispatch inputs tag and publish allow manual overrides. The tag is strictly validated against ^v<major>.<minor>.<patch>(\+<n>)?$ (the pattern used by all existing release tags); invalid input fails.

Consolidation

All release/adhoc logic moved to bin/repo-management.sh verbs: tip-version, lint, validate-appimage, detect, validate-tag, resolve-tag, open-pr, publish, publish-tip, tag-tip. ci.yaml is orchestration only. Dropped softprops/action-gh-release and svenstaro/upload-release-action in favor of gh.

Lint / POSIX

  • shellcheck now runs at --severity=warning --shell=sh, so POSIX violations (bashisms) fail the hook.
  • New lint job in ci.yaml, gated to pull_request (inherits paths-ignore, so schedule and VERSION-only PRs are excluded). Runs in parallel with the build.
  • Fixed SC2155 in the build scripts.

Local build parity / UPINFO

  • setup-env.sh installs get-debloated-pkgs / quick-sharun if missing (previously only provided by anylinux-setup-action).
  • build-ghostty.sh / bundle-appimage.sh default GITHUB_REPOSITORY to pkgforge-dev/ghostty-appimage, so local builds embed a valid UPINFO.
  • bundle-appimage.sh picks the update tag per channel: latest for stable (clean X.Y.Z in VERSION) and tip for nightly (X.Y.Z-main-+hash). Previously nightly embedded latest, so it tracked stable and never offered nightly updates.

Post-build validation (audit)

  • New Validate AppImage step in the build job runs repo-management.sh validate-appimage after bundling. It logs and asserts:
    • the embedded update info matches the expected channel tag, and
    • the zsync SHA-1: matches sha1sum of the AppImage.
  • The nightly run exercises the tip branch end-to-end, so the audit is visible in each Actions run.

Validation

  • Stable AppImage built locally: --appimage-updateinfo prints gh-releases-zsync|pkgforge-dev|ghostty-appimage|latest|Ghostty-*x86_64.AppImage.zsync; zsync SHA-1 matches.
  • validate-appimage tested positive (stable, exit 0) and negative (tip VERSION vs latest-embedded, exit 1).
  • actionlint, zizmor, shellcheck, shfmt pass.

Merging a release PR now triggers a push run scoped to VERSION: the
AppImage is built once and a publish_release job creates the GitHub
Release (auto notes + assets) when the v<version> tag exists. The PR
build stays skipped to avoid a duplicate run. Publishing in-run avoids
relying on the release: published event, which GITHUB_TOKEN does not
emit.
Stable releases are only produced by the merge-triggered push run, so
remove the release: published trigger, the event-gated release_stable
job, and the svenstaro upload action. The single release_stable job now
publishes via softprops/action-gh-release.
Restore the release: published trigger so manually published v<version>+N
releases build and attach assets via the existing flow, and add
workflow_dispatch inputs (tag, publish) for manual overrides. A single
release_stable job resolves the tag from the event: push uses v<VERSION>
(requires the tag), release uses the published tag, and dispatch uses the
optional tag input. Publishing uses softprops for create and asset
upload, preserving the release body on the +1 path.
Resolve release tag now normalizes an optional 'v' prefix and fails unless
the tag matches ^v<major>.<minor>.<patch>(\+<n>)?$, the same pattern used
by all existing vX.Y.Z / vX.Y.Z+N release tags. Applies to the
workflow_dispatch tag input and the event-derived tags.
- daily schedule detects upstream stable tags and opens release/<v> PRs;
  merge publishes the release with assets, no manual step
- +N releases via release: published; workflow_dispatch tag/publish
  override with strict vX.Y.Z(+N) validation
- move all release logic into bin/repo-management.sh verbs; ci.yaml is
  orchestration only, dropping softprops/svenstaro in favor of gh
- enforce POSIX sh via shellcheck --severity=warning and add a PR-only
  lint job to ci.yaml
- setup-env installs get-debloated-pkgs/quick-sharun when missing so
  local builds work
- default GITHUB_REPOSITORY so local builds embed a valid UPINFO
@psadi psadi changed the title feat(ci): publish stable release on VERSION merge feat(ci): automate upstream stable/+N releases and consolidate release logic Sep 16, 2026
bundle-appimage.sh unconditionally embedded 'latest', so nightly
AppImages tracked the newest stable release and never offered nightly
updates. Pick the tag from the channel: 'latest' for a clean X.Y.Z
VERSION (stable) and 'tip' for a snapshot version (X.Y.Z-main-+hash).
Drop the dead 'tip' UPINFO from build-ghostty.sh, which ran in a
separate step and was overwritten.
Add a validate-appimage verb and run it in the build job right after
bundling. It asserts the embedded update info matches the expected
channel tag (latest for stable X.Y.Z, tip for snapshot versions) and
that the zsync SHA-1 matches the AppImage, logging both for auditing.
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