Reject empty min_release_age, self-age the e2e fixtures, run self-tests in CI

An empty min_release_age string now maps to unparseable rather than absent,
so "min_release_age": "" fails validation instead of silently running
with a zero-second quarantine. The end-to-end fixtures extend the
checked-in pkgver (.90/.91) so the test keeps working at any future mise
version. A Tests workflow runs bin/sync-upstream self-test and
bin/omarchy-pkgs self-test on every PR in the Arch container, making the
proof machine-checked instead of author-supplied. The README package
metadata field list documents upstream and min_release_age.
This commit is contained in:
Ryan Hughes
2026-08-24 20:22:33 -04:00
parent 83bdfb5fa1
commit fd03757f22
4 changed files with 55 additions and 11 deletions
+31
View File
@@ -0,0 +1,31 @@
name: Tests
on:
pull_request:
push:
branches: [master]
workflow_dispatch:
jobs:
self-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
# An Arch container for vercmp: version ordering has to be decided by
# the same comparator pacman uses on users' machines.
- name: Run self-tests
run: |
docker run --rm \
-v "$PWD:/workspace:ro" \
-w /workspace \
archlinux:base-devel bash -lc '
set -euo pipefail
pacman -Syu --noconfirm jq
./bin/sync-upstream self-test
./bin/omarchy-pkgs self-test
'
+3 -1
View File
@@ -499,7 +499,9 @@ Minimal examples:
Fields:
- `source`: `aur` or `local`. A `local` package can still follow an upstream release with an `.omarchy/upstream.sh` hook.
- `source`: `aur` or `local`. A `local` package can still follow an upstream release, either declaratively via `upstream` or with an `.omarchy/upstream.sh` hook.
- `upstream`: optional for `local` packages whose vendor ships tagged GitHub releases with a checksum manifest asset. `{ "github": "owner/repo", "checksums": "SHASUMS256.txt", "assets": { "<arch>": "name-{tag}.tar.xz" } }` — see [Sync Upstream Releases](#sync-upstream-releases). Mutually exclusive with `.omarchy/upstream.sh`.
- `min_release_age`: optional quarantine for upstream releases (`"24h"`, `"2d"`, or bare seconds). The newest release older than the window ships; anything younger waits, and a release whose age cannot be proven fails the sync. Bypass deliberately with `BYPASS_MIN_RELEASE_AGE=1 bin/sync-upstream <package>`.
- `sync`: optional for AUR packages; defaults to `true`. Set `false` for AUR-origin packages that Omarchy maintains manually.
- `aur`: optional AUR package name when it differs from the local package directory, usually for split packages.
- `release_ring`: optional. `fast` means the package is built directly for stable as well as edge. Packages without a ring build in edge and reach stable through tested artifact promotion (`bin/repo migrate`).
+14 -7
View File
@@ -592,6 +592,7 @@ EOF
check_age '"abc"' "<reject>"
check_age '"24hh"' "<reject>"
check_age 'false' "<reject>"
check_age '""' "<reject>"
check_age '"9999999999"' "<reject>"
echo "Manifest validation:"
@@ -616,22 +617,28 @@ EOF
mkdir -p "$e2e_root"
cp -a "$BUILD_ROOT/pkgbuilds/mise-bin" "$e2e_root/mise-bin"
local mise_x64 mise_a64
# Fixture versions extend the checked-in pkgver so they stay newer no
# matter what version the real package is at when the test runs.
local mise_current mise_aged mise_fresh mise_x64 mise_a64
mise_current=$(grep -m1 '^pkgver=' "$e2e_root/mise-bin/PKGBUILD" | cut -d= -f2- | tr -d "\"'")
mise_aged="${mise_current}.90"
mise_fresh="${mise_current}.91"
mise_x64=$(printf 'e%.0s' {1..64})
mise_a64=$(printf 'f%.0s' {1..64})
FIXTURE_RELEASES=$(jq -n --arg young "$young" --arg old2 "$old2d" '[
{tag_name: "v2026.9.1", published_at: $young, draft: false, prerelease: false},
{tag_name: "v2026.9.0", published_at: $old2, draft: false, prerelease: false}
FIXTURE_RELEASES=$(jq -n --arg young "$young" --arg old2 "$old2d" \
--arg aged "v$mise_aged" --arg fresh "v$mise_fresh" '[
{tag_name: $fresh, published_at: $young, draft: false, prerelease: false},
{tag_name: $aged, published_at: $old2, draft: false, prerelease: false}
]')
FIXTURE_CHECKSUMS=$(printf '%s\n' \
"$mise_x64 ./mise-v2026.9.0-linux-x64.tar.xz" \
"$mise_a64 ./mise-v2026.9.0-linux-arm64.tar.xz")
"$mise_x64 ./mise-v$mise_aged-linux-x64.tar.xz" \
"$mise_a64 ./mise-v$mise_aged-linux-arm64.tar.xz")
local prev_updated=$UPDATED prev_failed=$FAILED
PKGBUILDS_DIR="$e2e_root" sync_package mise-bin >/dev/null 2>&1 || true
check "sync_package updates without failures" "updated=1 failed=0" \
"updated=$((UPDATED - prev_updated)) failed=$((FAILED - prev_failed))"
check "the 24h manifest policy holds v2026.9.1 and ships v2026.9.0" "2026.9.0" \
check "the 24h manifest policy holds v$mise_fresh and ships v$mise_aged" "$mise_aged" \
"$(grep -m1 '^pkgver=' "$e2e_root/mise-bin/PKGBUILD" | cut -d= -f2-)"
check "pkgrel resets to 1" "1" \
"$(grep -m1 '^pkgrel=' "$e2e_root/mise-bin/PKGBUILD" | cut -d= -f2-)"
+7 -3
View File
@@ -93,10 +93,14 @@ package_min_release_age_seconds() {
echo 0
return 0
fi
# A present-but-empty value maps to "unparseable", not to "absent": only a
# missing key means no hold, so '"min_release_age": ""' cannot silently
# disable the quarantine.
raw=$(jq -r '
if has("min_release_age") then
.min_release_age | if type == "string" or type == "number" then tostring else "unparseable" end
else "" end
if has("min_release_age") | not then ""
elif (.min_release_age | type) == "string" or (.min_release_age | type) == "number" then
.min_release_age | tostring | if . == "" then "unparseable" else . end
else "unparseable" end
' "$metadata")
if [[ -z "$raw" ]]; then
echo 0