Add a Gitea Actions pipeline that publishes the image as a release
Builds the image on a self-hosted runner and publishes it, with the checksum and
a corresponding-source offer, as a Gitea release.
The schedule is daily but the build is conditional. Proxmox does not ship daily,
so an unconditional daily build would produce roughly 45 GB a month of
near-identical artifacts; instead the job compares the newest pve-manager in the
configured repository against the last published release and stops early when
they match. A manual trigger with `force` rebuilds anyway. Releases are tagged
after the version they contain (`pve-9.2.11`) rather than the date, so the tag
says something useful, and older ones are pruned to keep three.
The logic lives in scripts/ci/ rather than inline in the workflow. Shell inside a
YAML block scalar cannot carry an indented heredoc terminator, and the release
body needs several; scripts also mean the pieces can be run and tested by hand.
A `print-var` target exposes single Makefile variables to them.
Two constraints shaped this:
* The runner is registered in host mode, so steps run directly on the build
machine as root. The build needs /dev/kvm, qemu-nbd, FUSE and root, which a
container would have to be given anyway. The consequence — anything able to
dispatch a workflow gets root on that machine — is stated in the workflow
header rather than left implicit.
* Checkout is a plain git clone. actions/checkout is a JavaScript action and
the host-mode runner has no Node.js runtime.
The artifact is named maas-image-pve-<version>-amd64.tar.gz, not
proxmox-ve-*.tar.gz, and the release body says the build is unofficial and
unaffiliated. Proxmox permits redistribution under the AGPLv3 but asks that the
trademark not be used in product names.
SOURCES.md is generated per release: the image is an unmodified installation of
Debian and Proxmox packages, so it points at those archives for the
corresponding source, and records that the firmware licence texts ship inside the
image at /usr/share/doc/pve-firmware/licenses/ and must not be stripped.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
124
.gitea/workflows/build-image.yml
Normal file
124
.gitea/workflows/build-image.yml
Normal file
@@ -0,0 +1,124 @@
|
||||
# Copyright (C) 2026 Ilker Manap
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Builds the MAAS image and publishes it as a Gitea release.
|
||||
#
|
||||
# Runs daily, but only *builds* when the Proxmox repository actually carries a
|
||||
# newer pve-manager than the last published release. Proxmox does not ship daily,
|
||||
# so an unconditional daily build would produce ~45 GB a month of near-identical
|
||||
# artifacts for nothing. Trigger manually with `force` to rebuild anyway.
|
||||
#
|
||||
# The runner is registered in host mode: steps run directly on the build machine
|
||||
# as root, because the build needs /dev/kvm, qemu-nbd, FUSE and root privileges.
|
||||
# Anything that can dispatch a workflow here therefore has root on that machine.
|
||||
|
||||
name: build-image
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
force:
|
||||
description: 'Build even if the version has not changed'
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: build-image
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: maas-builder
|
||||
timeout-minutes: 120
|
||||
|
||||
env:
|
||||
GITEA_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
KEEP_RELEASES: '3'
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
# A plain clone rather than actions/checkout: the runner is in host mode
|
||||
# and has no Node.js runtime for JavaScript actions.
|
||||
run: |
|
||||
set -eux
|
||||
rm -rf "$GITHUB_WORKSPACE"
|
||||
git clone --depth 1 --branch "$GITHUB_REF_NAME" \
|
||||
"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git" "$GITHUB_WORKSPACE"
|
||||
cd "$GITHUB_WORKSPACE" && git log --oneline -1
|
||||
|
||||
- name: Decide whether to build
|
||||
id: decide
|
||||
run: |
|
||||
set -eu
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
|
||||
UPSTREAM=$(./scripts/ci/upstream-version.sh)
|
||||
TAG="pve-${UPSTREAM}"
|
||||
echo "upstream pve-manager: ${UPSTREAM}"
|
||||
|
||||
PUBLISHED=$(curl -fsS -H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${GITEA_API}/releases?limit=1" \
|
||||
| python3 -c 'import json,sys; r=json.load(sys.stdin); print(r[0]["tag_name"] if r else "")')
|
||||
echo "latest release: ${PUBLISHED:-<none>}"
|
||||
|
||||
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
||||
echo "version=${UPSTREAM}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
if [ "${{ inputs.force }}" = "true" ]; then
|
||||
echo "forced by manual trigger"
|
||||
echo "build=yes" >> "$GITHUB_OUTPUT"
|
||||
elif [ "$PUBLISHED" = "$TAG" ]; then
|
||||
echo "${TAG} is already published — nothing to do"
|
||||
echo "build=no" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "new version — building"
|
||||
echo "build=yes" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
if: steps.decide.outputs.build == 'yes'
|
||||
run: |
|
||||
set -eux
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
make image
|
||||
|
||||
- name: Verify
|
||||
if: steps.decide.outputs.build == 'yes'
|
||||
run: |
|
||||
set -eux
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
make verify
|
||||
|
||||
- name: Assemble release artifacts
|
||||
if: steps.decide.outputs.build == 'yes'
|
||||
run: |
|
||||
set -eu
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
./scripts/ci/assemble-artifacts.sh "${{ steps.decide.outputs.version }}"
|
||||
|
||||
- name: Publish
|
||||
if: steps.decide.outputs.build == 'yes'
|
||||
run: |
|
||||
set -eu
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
./scripts/ci/publish-release.sh \
|
||||
"${{ steps.decide.outputs.tag }}" \
|
||||
"${{ steps.decide.outputs.version }}" \
|
||||
dist
|
||||
|
||||
- name: Prune old releases
|
||||
if: steps.decide.outputs.build == 'yes'
|
||||
run: |
|
||||
set -eu
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
./scripts/ci/prune-releases.sh "$KEEP_RELEASES"
|
||||
|
||||
- name: Clean up
|
||||
if: always()
|
||||
run: |
|
||||
# A 1.5 GB artifact per run would fill the builder otherwise.
|
||||
rm -rf "$GITHUB_WORKSPACE/dist" "$GITHUB_WORKSPACE/build" || true
|
||||
df -h / | tail -1
|
||||
Reference in New Issue
Block a user