Skip to content

Automate releases so Omarchy can package Elsewhen - #2

Merged
spencerbull merged 6 commits into
mainfrom
release-automation
Sep 17, 2026
Merged

spencerbull merged 6 commits into
mainfrom
release-automation

Conversation

@spencerbull

@spencerbull spencerbull commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Elsewhen is moving from a git checkout under ~/.config/omarchy/plugins to a pacman package, elsewhen, built by omarchy-pkgs from this repository's GitHub releases and installed by Omarchy by default. That gives the plugin its own lifecycle: releases are cut here, the package tracks them, and omarchy update carries them to users. This PR is the elsewhen side: automated release publishing, and the version set to 0.1.0 for the first release.

Companion PRs: omarchy-pkgs omacom/omarchy-pkgs#483 (the package, draft until v0.1.0 exists) and omarchy omacom/omarchy#12157 (default package, bar placement, and migration; stacked on omacom/omarchy#12051, which adds the packaged plugin root).

Release automation

  • .github/workflows/release.yml has two entry points. Run workflow with a version input runs cut on main: it refuses any other branch, an existing tag, and a version that is not above every existing v* tag and at least the manifest's own (scripts/check-version-bump.sh); writes the version with scripts/set-version.sh; runs scripts/check-manifest.sh and tests/run --offline; commits Release vX.Y.Z as github-actions[bot] only if that changed anything (main already carries 0.1.0, so the first run tags the existing head); creates an annotated tag; and pushes commit and tag atomically. publish runs in the same run (a push made with the workflow token cannot start another) or on a direct v* tag push: it requires the tag to be on main and equal to v plus the manifest version, re-runs the checks, refuses an existing release, and runs gh release create --verify-tag --generate-notes (--prerelease for - versions).
  • No assets. omarchy-pkgs builds from the tag's source archive, so the tag is the artifact and the release is the signal that it is ready, or, for a prerelease, the signal to skip it.
  • manifest.json is the only version pin. set-version.sh rewrites that one line surgically and refuses a manifest with more than one version-shaped line. check-manifest.sh is the CI validation step moved into a script so cut and publish run exactly what CI runs, plus a SemVer shape check on the version. The version guard orders prereleases below their release (SemVer order, which sort -V alone gets backwards). Actions are pinned by SHA, the same pins as atreyu#35.
  • CI gains the set-version round trip and the version-guard test; both work on a disposable copy of the tree with tags of their own making.
  • manifest.json goes from 1.0.0 to 0.1.0, matching where the plugin stands; the first tag will be v0.1.0.
  • README: Installing names the package and keeps the git route for an older Omarchy or for hacking on it; a Releasing section describes the workflow, the prerelease rule, and recovery.

Verification

  • actionlint and shellcheck clean. scripts/check-manifest.sh, tests/test-set-version.sh, tests/test-check-version-bump.sh, and tests/run --offline (node checks, currency check, qmltestrunner 6 of 6) pass.
  • Dry run of cut in scratch clones: at 0.1.0 no commit and the tag on HEAD; at 0.2.0 a Release v0.2.0 bot commit, then the tag.
  • Mutation checks: removing the uniqueness guard from set-version.sh fails its test. The version-guard test covers releases, prereleases, a manifest ahead of the tags, numeric ordering, and non-version v* tags.
  • An independent review found no high findings. Its three findings, a missing monotonic-version guard, the uniqueness gap in the test, and the README's present tense about a package that does not exist yet, are addressed in the last three commits. Left as is: the Qt apt list is repeated in ci.yml, cut, and publish.

Proved on a VM

This PR

  • The cut, replayed against this branch. For 0.1.0, check-version-bump reports the first release, set-version reports already at 0.1.0, no commit is made, and the annotated tag lands on the existing head. For 0.1.1 it makes a Release v0.1.1 commit as github-actions[bot] that touches only manifest.json, then tags. Asking for 0.1.0 again is refused: version 0.1.0 is not above the latest tag v0.1.1.
  • This repository's tests on a real Omarchy (node 26, Qt 6 qmltestrunner): scripts/check-manifest.sh, tests/test-set-version.sh, tests/test-check-version-bump.sh, and tests/run --offline with 14 checks and the QML suite at 6 of 6, all passing.
  • The plugin runs from a root-owned tree. Installed at 0644 under /usr/share, the panel opens with live clocks and weather, the helper's only write goes to ~/.cache/omacom-elsewhen/data.json, and pacman -Qkk elsewhen reports 0 altered files after use.
  • The README's claim about an existing checkout holds. With the package installed the shell serves the packaged copy, and a pristine clone made by omarchy plugin add is retired by the Omarchy migration.
  • Not covered here: the Actions run itself, which needs the workflow on main.

Combined

The three PR heads were run together as the final state on an omabot worker, a linked clone of the Omarchy 4.0.1 ISO template whose shell predates the packaged plugin root: this PR at 84288b1, the package from omacom/omarchy-pkgs#483 at 56eced5, and the Omarchy change from omacom/omarchy#12157 at d681b16a on top of omacom/omarchy#12051 at baf85c34. Each step below is the part one PR owns, fed by the one before it.

  1. Release, this PR. The cut steps run against that branch produce the v0.1.0 tag on the existing head, and git archive --prefix=elsewhen-0.1.0/ gives the archive in the layout of GitHub's tag archive.
  2. Package, Add elsewhen, the Omarchy shell world clock plugin omarchy-pkgs#483. makepkg on the worker turns that archive into elsewhen 0.1.0-1 with the PR's PKGBUILD, only source and sha256sums pointed at the local archive. A local pacman repository serves it in place of the Omarchy mirror.
  3. Update, Install Elsewhen, the world clock plugin, by default omarchy#12157. An existing user is set up first: a pristine clone with the README's origin under ~/.config/omarchy/plugins, enabled on the old shell. The Omarchy tree is then replaced in place under that running shell, which is what the omarchy package upgrade does to /usr/share/omarchy. The real omarchy-migrate installs the package, retires the clone, and leaves the user's placement alone; omarchy-restart-shell brings up a shell that lists omacom.elsewhen enabled packaged from /usr/share/omarchy/plugins/omacom.elsewhen, and the panel opens with live clocks and weather.
  4. The next release, all three. Cutting v0.1.1 makes a Release v0.1.1 bot commit and tag; the rebuilt package shows up as 0.1.0-1 -> 0.1.1-1 in pacman -Qu; after the upgrade and a shell restart the packaged manifest reads 0.1.1 with the widget still enabled and shell.json untouched. pacman -Rns elsewhen then leaves nothing under the packaged root.

No defect surfaced in any of the three. The one visible effect is the transient the migration documents: between the migration and the shell restart the stale shell shows an empty slot where the widget was, and the rest of the desktop is unaffected.

Two things stood in for the real thing. Nothing was downloaded from GitHub, because the elsewhen repository is private and has no release yet. The other 37 migrations pending between the template's tree and the Omarchy head, Atreyu's among them since no atreyu package exists, were marked done so the runner executed only this one.

The bar's right section across the stages (stock, the clone on the old shell, the stale shell after the migration, after the restart, inserted by the migration, fresh defaults, after the 0.1.1 upgrade, after removal), and the panel served from the packaged tree:

bar across stages

panel from the packaged tree

Not covered by the combined run: a full omarchy update, which would pull three weeks of unrelated upgrades onto the template; an ISO install with elsewhen in the base package list; the GitHub Actions run itself; and makepkg or the upstream sync fetching from GitHub.

Before the first release

  • Make the repository public: makepkg and the omarchy-pkgs upstream sync fetch the tag archive and the Releases feed anonymously.
  • Order: merge this PR, run Release with version 0.1.0, fill the archive digest in the omarchy-pkgs PR and mark it ready, merge it, then merge the Omarchy PR after omarchy#12051. The Omarchy migration hard-fails if the package is not in the repo yet.

@spencerbull

Copy link
Copy Markdown
Collaborator Author

Proved end to end on an omabot worker (a real Omarchy from the 4.0.1 ISO), together with omacom/omarchy-pkgs#483 and omacom/omarchy#12157.

  • The cut, replayed. The cut job's steps run in a scratch clone of this branch: for 0.1.0 check-version-bump reports the first release, set-version reports already at 0.1.0, no commit is made, and the annotated tag goes on the existing head. For 0.1.1 it makes a Release v0.1.1 commit as github-actions[bot] touching only manifest.json, then tags. Asking for 0.1.0 again afterwards is refused: version 0.1.0 is not above the latest tag v0.1.1.
  • From tag to desktop. The v0.1.0 and v0.1.1 tag archives (git archive --prefix=elsewhen-<version>/, the layout of GitHub's tag archive) were built into pacman packages with #483's PKGBUILD on the worker, served from a local repository, installed by the Omarchy migration, and loaded by the shell from /usr/share/omarchy/plugins/omacom.elsewhen. The panel opens with live clocks and weather from the root-owned tree, and the helper's cache lands in ~/.cache/omacom-elsewhen/. Upgrading to the 0.1.1 package and restarting the shell shows manifest version 0.1.1 with the widget still in place.
  • The existing checkout. A pristine clone with the README's origin, enabled before the update, is retired by the Omarchy migration once the package is installed, and the widget carries on from the package after the shell restart.
  • This repository's tests on a real Omarchy. scripts/check-manifest.sh, tests/test-set-version.sh, tests/test-check-version-bump.sh, and tests/run --offline (14 checks, qmltestrunner 6 of 6) all pass on the worker.

panel from the packaged tree

bar across stages

Not covered: the Actions run itself, which needs the workflow on main, and anything fetched from GitHub, which needs the repository public.

@spencerbull
spencerbull merged commit f547cdc into main Sep 17, 2026
2 checks passed
@spencerbull
spencerbull deleted the release-automation branch September 17, 2026 04:39
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