every.channel/.forgejo/workflows/deploy-runner-images.yml
every.channel be26313225
Some checks failed
ci-gates / checks (push) Has been cancelled
deploy-cloudflare / checks (push) Has been cancelled
deploy-cloudflare / deploy (push) Has been cancelled
ops: add CI boot-image releases and Unifi PXE rollout
2026-02-28 22:53:59 -08:00

276 lines
9.8 KiB
YAML

name: deploy-runner-images
on:
push:
tags: [boot-v*]
workflow_dispatch:
inputs:
release_tag:
description: "Release tag override (manual runs only)"
required: false
default: ""
publish_release:
description: "Publish artifacts to Forgejo release (true/false)"
required: false
default: "true"
build_x86_64_netboot:
description: "Build x86_64 netboot tarball (true/false)"
required: false
default: "true"
build_x86_64_iso:
description: "Build x86_64 installer ISO (true/false)"
required: false
default: "true"
concurrency:
group: runner-image-deploy-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-release:
if: ${{ github.server_url != 'https://codeberg.org' }}
runs-on: codeberg-medium-lazy
steps:
- name: Fetch source (no git required)
env:
GITHUB_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
if [[ -z "${GITHUB_TOKEN:-}" ]]; then
echo "error: missing github.token"
exit 2
fi
if ! command -v curl >/dev/null 2>&1; then
echo "error: curl is required"
exit 2
fi
if ! command -v tar >/dev/null 2>&1; then
echo "error: tar is required"
exit 2
fi
if [[ -z "${GITHUB_SHA:-}" ]]; then
echo "error: missing GITHUB_SHA"
exit 2
fi
if [[ -z "${GITHUB_SERVER_URL:-}" ]]; then
echo "error: missing GITHUB_SERVER_URL"
exit 2
fi
if [[ -z "${GITHUB_REPOSITORY:-}" ]]; then
echo "error: missing GITHUB_REPOSITORY"
exit 2
fi
rm -rf .repo
mkdir -p .repo
curl -fsSL -H "Authorization: token ${GITHUB_TOKEN}" \
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz?rev=${GITHUB_SHA}" \
-o .repo/src.tgz
tar -xzf .repo/src.tgz -C .repo --strip-components=1
rm -f .repo/src.tgz
- name: Bootstrap Nix
shell: bash
run: |
set -euo pipefail
if ! command -v nix >/dev/null 2>&1; then
curl -fsSL https://nixos.org/nix/install -o /tmp/install-nix.sh
sh /tmp/install-nix.sh --no-daemon --yes
fi
if [[ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]]; then
# shellcheck disable=SC1091
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
fi
if [[ -d "$HOME/.nix-profile/bin" ]]; then
echo "PATH=$HOME/.nix-profile/bin:$PATH" >> "$GITHUB_ENV"
export PATH="$HOME/.nix-profile/bin:$PATH"
fi
nix --version
- name: Resolve build plan
id: plan
env:
INPUT_RELEASE_TAG: ${{ github.event.inputs.release_tag }}
INPUT_PUBLISH_RELEASE: ${{ github.event.inputs.publish_release }}
INPUT_BUILD_X86_64_NETBOOT: ${{ github.event.inputs.build_x86_64_netboot }}
INPUT_BUILD_X86_64_ISO: ${{ github.event.inputs.build_x86_64_iso }}
shell: bash
run: |
set -euo pipefail
bool_norm() {
local raw
raw="$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')"
case "${raw}" in
''|true|1|yes|y|on) echo "true" ;;
false|0|no|n|off) echo "false" ;;
*)
echo "error: invalid boolean value '${1}'" >&2
exit 2
;;
esac
}
short_sha="${GITHUB_SHA:0:12}"
if [[ "${GITHUB_REF:-}" == refs/tags/* ]]; then
release_tag="${GITHUB_REF#refs/tags/}"
else
release_tag="${INPUT_RELEASE_TAG:-}"
if [[ -z "${release_tag}" ]]; then
release_tag="boot-${short_sha}"
fi
fi
if [[ ! "${release_tag}" =~ ^[A-Za-z0-9._-]+$ ]]; then
echo "error: release tag contains unsupported characters: ${release_tag}" >&2
exit 2
fi
publish_release="$(bool_norm "${INPUT_PUBLISH_RELEASE:-true}")"
build_x86_64_netboot="$(bool_norm "${INPUT_BUILD_X86_64_NETBOOT:-true}")"
build_x86_64_iso="$(bool_norm "${INPUT_BUILD_X86_64_ISO:-true}")"
if [[ "${build_x86_64_netboot}" != "true" && "${build_x86_64_iso}" != "true" ]]; then
echo "error: at least one image build must be enabled" >&2
exit 2
fi
artifact_suffix="${short_sha}-${GITHUB_RUN_NUMBER:-0}-${GITHUB_RUN_ATTEMPT:-1}"
echo "release_tag=${release_tag}" >> "$GITHUB_OUTPUT"
echo "publish_release=${publish_release}" >> "$GITHUB_OUTPUT"
echo "build_x86_64_netboot=${build_x86_64_netboot}" >> "$GITHUB_OUTPUT"
echo "build_x86_64_iso=${build_x86_64_iso}" >> "$GITHUB_OUTPUT"
echo "artifact_suffix=${artifact_suffix}" >> "$GITHUB_OUTPUT"
- name: Build runner boot images
env:
BUILD_X86_64_NETBOOT: ${{ steps.plan.outputs.build_x86_64_netboot }}
BUILD_X86_64_ISO: ${{ steps.plan.outputs.build_x86_64_iso }}
ARTIFACT_SUFFIX: ${{ steps.plan.outputs.artifact_suffix }}
shell: bash
run: |
set -euo pipefail
cd .repo
if [[ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]]; then
# shellcheck disable=SC1091
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
fi
export PATH="$HOME/.nix-profile/bin:$PATH"
artifacts_dir="$PWD/.artifacts"
rm -rf "${artifacts_dir}"
mkdir -p "${artifacts_dir}"
nix_args=(--accept-flake-config --extra-experimental-features "nix-command flakes")
if [[ "${BUILD_X86_64_NETBOOT}" == "true" ]]; then
nix build "${nix_args[@]}" \
.#nixosConfigurations.ec-runner-x86_64-netboot.config.system.build.netboot \
-o result-netboot-x86_64
tar -C result-netboot-x86_64 \
-czf "${artifacts_dir}/ec-runner-x86_64-netboot-${ARTIFACT_SUFFIX}.tar.gz" \
kernel initrd netboot.ipxe
fi
if [[ "${BUILD_X86_64_ISO}" == "true" ]]; then
nix build "${nix_args[@]}" \
.#nixosConfigurations.ec-runner-x86_64-iso.config.system.build.isoImage \
-o result-iso-x86_64
iso_source=""
if [[ -f result-iso-x86_64 ]]; then
iso_source="result-iso-x86_64"
else
iso_source="$(find -L result-iso-x86_64 -type f -name '*.iso' | head -n 1 || true)"
fi
if [[ -z "${iso_source}" ]]; then
echo "error: could not locate ISO output from result-iso-x86_64" >&2
exit 2
fi
cp -f "${iso_source}" "${artifacts_dir}/ec-runner-x86_64-iso-${ARTIFACT_SUFFIX}.iso"
fi
if ! find "${artifacts_dir}" -maxdepth 1 -type f | grep -q .; then
echo "error: no image artifacts were produced" >&2
exit 2
fi
(
cd "${artifacts_dir}"
sha256sum -- * > SHA256SUMS.txt
ls -lh
)
- name: Publish artifacts to Forgejo release
if: ${{ steps.plan.outputs.publish_release == 'true' }}
env:
GITHUB_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ steps.plan.outputs.release_tag }}
shell: bash
run: |
set -euo pipefail
cd .repo
if [[ -z "${GITHUB_TOKEN:-}" ]]; then
echo "error: missing github.token"
exit 2
fi
if [[ -z "${GITHUB_SERVER_URL:-}" ]]; then
echo "error: missing GITHUB_SERVER_URL"
exit 2
fi
if [[ -z "${GITHUB_REPOSITORY:-}" ]]; then
echo "error: missing GITHUB_REPOSITORY"
exit 2
fi
api_base="${GITHUB_SERVER_URL%/}/api/v1/repos/${GITHUB_REPOSITORY}"
release_json="$(curl -fsSL \
-H "Authorization: token ${GITHUB_TOKEN}" \
"${api_base}/releases/tags/${RELEASE_TAG}" 2>/dev/null || true)"
if [[ -z "${release_json}" ]]; then
payload="$(cat <<JSON
{
"tag_name": "${RELEASE_TAG}",
"name": "Boot images ${RELEASE_TAG}",
"body": "Automated runner boot image build from ${GITHUB_SHA}.",
"draft": false,
"prerelease": false
}
JSON
)"
release_json="$(curl -fsSL -X POST \
-H "Authorization: token ${GITHUB_TOKEN}" \
-H "content-type: application/json" \
"${api_base}/releases" \
-d "${payload}")"
fi
release_id=""
if command -v python3 >/dev/null 2>&1; then
release_id="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' <<<"${release_json}" 2>/dev/null || true)"
fi
if [[ -z "${release_id}" ]]; then
release_id="$(printf '%s' "${release_json}" \
| sed -nE 's/.*"id"[[:space:]]*:[[:space:]]*([0-9]+).*/\1/p' \
| head -n 1)"
fi
if [[ -z "${release_id}" ]]; then
echo "error: failed to resolve release id for ${RELEASE_TAG}" >&2
exit 2
fi
for asset_path in .artifacts/*; do
[[ -f "${asset_path}" ]] || continue
asset_name="$(basename "${asset_path}")"
curl -fsSL -X POST \
-H "Authorization: token ${GITHUB_TOKEN}" \
-H "content-type: application/octet-stream" \
--data-binary @"${asset_path}" \
"${api_base}/releases/${release_id}/assets?name=${asset_name}" >/dev/null
echo "uploaded: ${asset_name}"
done