Nightly: its decisions are scripts, with tests
Which channels a run makes and where they go, and what is laid out and what latest.json then says, were shell inside the workflow file, tried only by hand. A green run published a latest.json with the Omarchy version in it twice, and nothing noticed. Both are scripts now, test/vm-image/nightly-plan and nightly-layout, and test/unit/nightly-test.sh tries them without a runner: a first run, a run started again, a release already published, a tag that is not a version; every field of latest.json for each channel, the checksums against the files, the version a consumer reads from the ISO's name. nightly-layout also refuses to describe an image it cannot describe fully, and checks its own latest.json before anything is published. The same test covers two things the install test decides: which Omarchy packages an ISO installs, and when an install is over.
This commit is contained in:
1 parent
ff30b7f558
commit
0abcbb0b97
5 files changed
+312
-64
No files matched your search
Executable
+98
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
# Lays out what one channel of a nightly run publishes and writes the
|
||||
# latest.json that describes it.
|
||||
#
|
||||
# nightly-layout <channel> <version> <release> <iso> <sealed_dir> <vm_packages> <out_dir>
|
||||
#
|
||||
# release the path under the site, from nightly-plan
|
||||
# iso the ISO that was installed
|
||||
# sealed_dir what vm-seal made
|
||||
# vm_packages what the sealed image answered to: pacman -Q of its Omarchy
|
||||
# package, pacman -Qo of its kernel's pkgbase, uname -r
|
||||
#
|
||||
# Env: SITE (https://nightly.omarchy.org), ISO_SITE (https://iso.omarchy.org),
|
||||
# ISO_COMMIT (the omarchy-iso commit, default: HEAD of this checkout).
|
||||
#
|
||||
# out_dir gets <release>/vm/ with the image, its checksums and vm-boot, and
|
||||
# <channel>/latest.json. The edge ISO is published too, next to the image.
|
||||
# The released one already has its place: latest.json points there and the
|
||||
# ISO stays where it is.
|
||||
#
|
||||
# The ISO and the image are moved, not copied: they are gigabytes.
|
||||
set -euo pipefail
|
||||
[[ $# -eq 7 ]] || { sed -n '2,13p' "$0" >&2; exit 2; }
|
||||
channel=$1 version=$2 release=$3 iso_file=$4 sealed=$5 packages=$6 out=$7
|
||||
here=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
site=${SITE:-https://nightly.omarchy.org}
|
||||
iso_site=${ISO_SITE:-https://iso.omarchy.org}
|
||||
iso_commit=${ISO_COMMIT:-$(git -C "$here" rev-parse HEAD)}
|
||||
fail() { echo "nightly-layout: $*" >&2; exit 1; }
|
||||
|
||||
[[ $channel == edge || $channel == stable ]] || fail "'$channel' is not a channel"
|
||||
[[ -f $iso_file ]] || fail "no ISO at $iso_file"
|
||||
files=(base.qcow2 OVMF_VARS.4m.fd vmlinuz initrd cmdline)
|
||||
for file in "${files[@]}"; do
|
||||
[[ -s $sealed/$file ]] || fail "the sealed image has no $file"
|
||||
done
|
||||
|
||||
omarchy=$(awk '$1 == "omarchy" || $1 == "omarchy-dev" { print $2; exit }' "$packages")
|
||||
kernel=$(tail -n 1 "$packages")
|
||||
[[ -n $omarchy ]] || fail "$packages names no omarchy package"
|
||||
[[ $kernel =~ ^[0-9]+\.[0-9] ]] || fail "$packages does not end with a kernel release"
|
||||
# An edge package's version carries the commit it was built from.
|
||||
omarchy_commit=$(sed -nE 's/.*\.g([0-9a-f]+)-.*/\1/p' <<<"$omarchy")
|
||||
|
||||
dir=$out/$release
|
||||
mkdir -p "$dir/vm" "$out/$channel"
|
||||
if [[ $channel == edge ]]; then
|
||||
iso=omarchy-$channel-$version.iso
|
||||
iso_url=$site/$release/$iso
|
||||
mv "$iso_file" "$dir/$iso"
|
||||
(cd "$dir" && sha256sum "$iso" >"$iso.sha256")
|
||||
iso_sha256=$(cut -d' ' -f1 "$dir/$iso.sha256") iso_size=$(stat -c %s "$dir/$iso")
|
||||
else
|
||||
iso=omarchy-$version.iso
|
||||
[[ ${iso_file##*/} == "$iso" ]] || fail "the released ISO is $iso, not ${iso_file##*/}"
|
||||
iso_url=$iso_site/$iso
|
||||
iso_sha256=$(sha256sum "$iso_file" | cut -d' ' -f1) iso_size=$(stat -c %s "$iso_file")
|
||||
fi
|
||||
|
||||
for file in "${files[@]}"; do mv "$sealed/$file" "$dir/vm/$file"; done
|
||||
cp "$here/vm-boot" "$dir/vm/vm-boot"
|
||||
files+=(vm-boot)
|
||||
(cd "$dir/vm" && sha256sum "${files[@]}" >SHA256SUMS)
|
||||
|
||||
latest=$out/$channel/latest.json
|
||||
jq -n \
|
||||
--arg version "$version" --arg channel "$channel" --arg vm "$site/$release/vm" \
|
||||
--arg built_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
--arg url "$iso_url" --arg sha256 "$iso_sha256" --argjson size "$iso_size" \
|
||||
--arg iso_commit "$iso_commit" --arg omarchy_version "$omarchy" --arg omarchy_commit "$omarchy_commit" \
|
||||
--arg kernel "$kernel" \
|
||||
--arg disk_sha256 "$(awk '$2 == "base.qcow2" { print $1 }' "$dir/vm/SHA256SUMS")" \
|
||||
--argjson disk_size "$(stat -c %s "$dir/vm/base.qcow2")" \
|
||||
--args '{
|
||||
version: $version, channel: $channel, built_at: $built_at,
|
||||
url: $url, sha256: $sha256, size: $size,
|
||||
iso_commit: $iso_commit, omarchy_version: $omarchy_version, omarchy_commit: $omarchy_commit,
|
||||
kernel: $kernel,
|
||||
vm: {
|
||||
url: "\($vm)/", disk: "\($vm)/base.qcow2", disk_sha256: $disk_sha256, disk_size: $disk_size,
|
||||
files: ($ARGS.positional + ["SHA256SUMS"]),
|
||||
user: "omarchy", password: "omarchy",
|
||||
ssh: "keys only; vm-boot makes one for each boot"
|
||||
}
|
||||
}' "${files[@]}" >"$latest"
|
||||
|
||||
# What is about to be published has to say what it should: one value in every
|
||||
# field, and checksums that are checksums.
|
||||
jq -e --arg channel "$channel" '
|
||||
def one_line: type == "string" and test("^[^\n]+$");
|
||||
def sha: type == "string" and test("^[0-9a-f]{64}$");
|
||||
(.version | one_line) and .channel == $channel
|
||||
and (.url | test("^https://[^\n ]+\\.iso$")) and (.sha256 | sha) and .size > 0
|
||||
and (.iso_commit | test("^[0-9a-f]{40}$"))
|
||||
and (.omarchy_version | one_line) and (.omarchy_commit | test("^[0-9a-f]*$")) and (.kernel | one_line)
|
||||
and (.vm.disk | test("^https://[^\n ]+/vm/base\\.qcow2$")) and (.vm.disk_sha256 | sha) and .vm.disk_size > 0
|
||||
' "$latest" >/dev/null || { cat "$latest" >&2; fail "latest.json does not say what it should"; }
|
||||
cat "$latest"
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# Says which channels a nightly run makes, under which version, and where
|
||||
# each one is published. It decides; the workflow fetches what it needs to
|
||||
# know and passes it in, so every case can be tried without a runner.
|
||||
#
|
||||
# nightly-plan <date> <run_number> <run_attempt> <event> <release_tag> [published_stable]
|
||||
#
|
||||
# date today, as YYYY.MM.DD
|
||||
# event what started the run: schedule, workflow_dispatch
|
||||
# release_tag omacom/omarchy's latest release, such as v4.0.4
|
||||
# published_stable the version stable/latest.json names now, if any
|
||||
#
|
||||
# Prints a JSON list of {channel, version, release}; release is the path
|
||||
# under the site.
|
||||
#
|
||||
# An edge version is the date and the run number. A stable version is the
|
||||
# release's own, and on a scheduled run a release already published is left
|
||||
# out: it is done once. Two builds are never the same bytes and a published
|
||||
# file is never replaced, so no path is used twice: a stable image has the run
|
||||
# number in its path, and a run started again adds its attempt to the number.
|
||||
set -euo pipefail
|
||||
[[ $# -eq 5 || $# -eq 6 ]] || { sed -n '2,12p' "$0" >&2; exit 2; }
|
||||
date=$1 run=$2 attempt=$3 event=$4 tag=$5 published=${6:-}
|
||||
fail() { echo "nightly-plan: $*" >&2; exit 1; }
|
||||
|
||||
[[ $date =~ ^[0-9]{4}\.[0-9]{2}\.[0-9]{2}$ ]] || fail "'$date' is not a date like 2026.10.09"
|
||||
[[ $run =~ ^[1-9][0-9]*$ ]] || fail "'$run' is not a run number"
|
||||
[[ $attempt =~ ^[1-9][0-9]*$ ]] || fail "'$attempt' is not a run attempt"
|
||||
stable=${tag#v}
|
||||
[[ $stable =~ ^[0-9]+(\.[0-9]+)+$ ]] || fail "the latest release is '$tag', not a version"
|
||||
|
||||
build=$run
|
||||
[[ $attempt == 1 ]] || build+=.$attempt
|
||||
|
||||
channels=$(jq -cn --arg v "$date.$build" '[{channel: "edge", version: $v, release: "edge/\($v)"}]')
|
||||
if [[ $event == schedule && $published == "$stable" ]]; then
|
||||
echo "nightly-plan: stable $stable is already published" >&2
|
||||
else
|
||||
channels=$(jq -c --arg v "$stable" --arg build "$build" \
|
||||
'. + [{channel: "stable", version: $v, release: "stable/\($v)/\($build)"}]' <<<"$channels")
|
||||
fi
|
||||
echo "$channels"
|
||||
Reference in new issue
Block a user