Ubuntu 26.04
build-and-publish / build (debian:13, NEXUS_PASS_TRIXIE, NEXUS_REPO_TRIXIE, NEXUS_USER_TRIXIE, trixie) (push) Failing after 9s
build-and-publish / build (ubuntu:26.04, NEXUS_PASS_RACCOON, NEXUS_REPO_RACCOON, NEXUS_USER_RACCOON, raccoon) (push) Failing after 9s

This commit is contained in:
root
2026-04-26 04:28:29 +00:00
parent 198d34766c
commit 8b25532d05
+75 -28
View File
@@ -1,3 +1,21 @@
# =============================================================================
# build-and-publish (multi-distro matrix)
#
# Builds twiy as a Debian .deb for each target distro in parallel:
# - trixie (Debian 13) -> uploaded to NEXUS_REPO_TRIXIE
# - raccoon (Ubuntu 26.04 LTS) -> uploaded to NEXUS_REPO_RACCOON
#
# Each matrix job runs DIRECTLY INSIDE a container of the target distro
# (Gitea Actions `container:` directive, not nested docker-in-docker).
# act_runner mounts the workspace into the container, so apt/ldd/dpkg-deb
# all see the target distro's libraries — no host contamination.
#
# Required repository secrets (set up by the API provisioning script):
# NEXUS_URL (shared)
# NEXUS_USER_TRIXIE, NEXUS_PASS_TRIXIE, NEXUS_REPO_TRIXIE
# NEXUS_USER_RACCOON, NEXUS_PASS_RACCOON, NEXUS_REPO_RACCOON
# Each NEXUS_USER_* is a least-privilege user scoped to ONE apt-hosted repo.
# =============================================================================
name: build-and-publish name: build-and-publish
on: on:
@@ -9,6 +27,7 @@ jobs:
build: build:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
strategy: strategy:
# If trixie fails, still finish raccoon (and vice versa) — surface both.
fail-fast: false fail-fast: false
matrix: matrix:
target: [trixie, raccoon] target: [trixie, raccoon]
@@ -16,39 +35,63 @@ jobs:
- target: trixie - target: trixie
image: debian:13 image: debian:13
nexus_repo_secret: NEXUS_REPO_TRIXIE nexus_repo_secret: NEXUS_REPO_TRIXIE
nexus_user_secret: NEXUS_USER_TRIXIE
nexus_pass_secret: NEXUS_PASS_TRIXIE
- target: raccoon - target: raccoon
image: ubuntu:26.04 image: ubuntu:26.04
nexus_repo_secret: NEXUS_REPO_RACCOON nexus_repo_secret: NEXUS_REPO_RACCOON
nexus_user_secret: NEXUS_USER_RACCOON
nexus_pass_secret: NEXUS_PASS_RACCOON
# Run all steps directly inside the target distro's container. Gitea's
# act_runner mounts the workspace and injects node so actions/checkout
# works. No nested docker calls needed.
container:
image: ${{ matrix.image }}
steps: steps:
# The default debian/ubuntu images lack git + ca-certificates, which
# actions/checkout needs. Cheaper to install just those two here than
# to bake a custom image.
- name: Bootstrap checkout deps
run: |
apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
git ca-certificates
- name: Checkout source - name: Checkout source
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Build nginx and assemble .deb inside ${{ matrix.image }} - name: Build nginx and assemble .deb (${{ matrix.target }})
id: pkg id: pkg
env: env:
TARGET: ${{ matrix.target }} TARGET: ${{ matrix.target }}
IMAGE: ${{ matrix.image }}
run: | run: |
set -euo pipefail set -euo pipefail
mkdir -p dist # /.dockerenv tells build/${TARGET}.sh's postfix step to skip systemctl
sudo docker run --rm \
-v "$PWD:/repo" \
-w /repo \
-e TARGET="$TARGET" \
"$IMAGE" \
bash -euxc '
touch /.dockerenv touch /.dockerenv
bash build/${TARGET}.sh new bash build/${TARGET}.sh new
bash build/${TARGET}.sh build bash build/${TARGET}.sh build
bash build/${TARGET}.sh postfix bash build/${TARGET}.sh postfix
PKG_NAME="twiy" PKG_NAME="twiy"
NGINX_VER="$(nginx -v 2>&1 | awk -F/ "{print \$2}")" NGINX_VER="$(nginx -v 2>&1 | awk -F/ '{print $2}')"
# Append CI run number AND target so each rebuild is a strictly-
# greater Debian revision. Without this, `apt upgrade twiy` would
# be a no-op when upstream nginx hasnt moved, so packaging fixes
# wouldnt reach users who already have the package installed.
# The ~target suffix keeps trixie/raccoon versions distinct in
# case any introspection ever compares them.
VERSION="${NGINX_VER}-${GITHUB_RUN_NUMBER:-1}~${TARGET}" VERSION="${NGINX_VER}-${GITHUB_RUN_NUMBER:-1}~${TARGET}"
ARCH="amd64" ARCH="amd64"
PKG_DIR="/opt/${PKG_NAME}_${VERSION}_${ARCH}" PKG_DIR="/opt/${PKG_NAME}_${VERSION}_${ARCH}"
DEB_DIR="${PKG_DIR}/DEBIAN" DEB_DIR="${PKG_DIR}/DEBIAN"
# The *_temp dirs under /usr/local/nginx are nginx's compiled-in
# defaults for client_body / proxy / fastcgi / uwsgi / scgi temp
# storage (no --http-*-temp-path was passed to ./configure). They
# must exist before `nginx -t` runs, so we ship them empty in the
# .deb and the postinst chowns them to the nginx user.
mkdir -p "${PKG_DIR}/usr/sbin" "${PKG_DIR}/nginx" \ mkdir -p "${PKG_DIR}/usr/sbin" "${PKG_DIR}/nginx" \
"${PKG_DIR}/etc/systemd/system" "${PKG_DIR}/var/log/nginx" \ "${PKG_DIR}/etc/systemd/system" "${PKG_DIR}/var/log/nginx" \
"${PKG_DIR}/usr/lib" "${PKG_DIR}/usr/local/lib" \ "${PKG_DIR}/usr/lib" "${PKG_DIR}/usr/local/lib" \
@@ -65,9 +108,14 @@ jobs:
cp /etc/systemd/system/nginx.service "${PKG_DIR}/etc/systemd/system/" cp /etc/systemd/system/nginx.service "${PKG_DIR}/etc/systemd/system/"
cp -R /hostdata/default "${PKG_DIR}/hostdata/" || true cp -R /hostdata/default "${PKG_DIR}/hostdata/" || true
cp -R /usr/nginx_lua "${PKG_DIR}/usr/" || true cp -R /usr/nginx_lua "${PKG_DIR}/usr/" || true
for lib in $(ldd /usr/sbin/nginx | grep "=> /" | awk "{print \$3}"); do
# Bundle every shared library nginx links against. ldd resolves
# against THIS container's libraries (not the runner host) so the
# .deb gets the correct per-distro libs.
for lib in $(ldd /usr/sbin/nginx | grep '=> /' | awk '{print $3}'); do
cp "$lib" "${PKG_DIR}/usr/lib/" || true cp "$lib" "${PKG_DIR}/usr/lib/" || true
done done
# ---- DEBIAN/control -------------------------------------------- # ---- DEBIAN/control --------------------------------------------
mkdir -p "${DEB_DIR}" mkdir -p "${DEB_DIR}"
cat > "${DEB_DIR}/control" <<EOF cat > "${DEB_DIR}/control" <<EOF
@@ -82,7 +130,7 @@ jobs:
EOF EOF
# ---- DEBIAN/postinst ------------------------------------------- # ---- DEBIAN/postinst -------------------------------------------
cat > "${DEB_DIR}/postinst" <<"EOFPOSTINST" cat > "${DEB_DIR}/postinst" <<'EOFPOSTINST'
#!/bin/bash #!/bin/bash
# Idempotent: safe on first install, upgrade, and reinstall. # Idempotent: safe on first install, upgrade, and reinstall.
useradd -r -d /usr/local/nginx -s /bin/false nginx 2>/dev/null || true useradd -r -d /usr/local/nginx -s /bin/false nginx 2>/dev/null || true
@@ -103,21 +151,8 @@ jobs:
chmod 755 "${DEB_DIR}/postinst" chmod 755 "${DEB_DIR}/postinst"
dpkg-deb --build "${PKG_DIR}" dpkg-deb --build "${PKG_DIR}"
cp "${PKG_DIR}.deb" /repo/dist/ DEB_FILE="${PKG_DIR}.deb"
# Hand ownership back to the runner UID so the host job can read.
chown $(stat -c "%u:%g" /repo) /repo/dist/$(basename "${PKG_DIR}.deb")
# Stash version for the publish step.
echo "${PKG_NAME}_${VERSION}_${ARCH}.deb" > /repo/dist/${TARGET}.name
echo "${VERSION}" > /repo/dist/${TARGET}.version
echo "${PKG_NAME}" > /repo/dist/${TARGET}.pkg
'
# Surface the artifact paths for the next step.
DEB_FILE="$PWD/dist/$(cat dist/${TARGET}.name)"
PKG_NAME="$(cat dist/${TARGET}.pkg)"
VERSION="$(cat dist/${TARGET}.version)"
{ {
echo "deb_file=${DEB_FILE}" echo "deb_file=${DEB_FILE}"
echo "version=${VERSION}" echo "version=${VERSION}"
@@ -126,10 +161,15 @@ jobs:
ls -la "${DEB_FILE}" ls -la "${DEB_FILE}"
sha256sum "${DEB_FILE}" sha256sum "${DEB_FILE}"
# Each matrix target uses its own dedicated Nexus user (ci-trixie /
# ci-raccoon) whose role is scoped to that ONE apt-hosted repo.
# Verified at provisioning time: each user gets 403 trying to touch
# the other repo. Admin credentials are NOT used by CI.
- name: Publish to Nexus (${{ matrix.target }}) - name: Publish to Nexus (${{ matrix.target }})
env: env:
NEXUS_USER: ${{ secrets.NEXUS_USER }} NEXUS_USER: ${{ secrets[matrix.nexus_user_secret] }}
NEXUS_PASS: ${{ secrets.NEXUS_PASS }} NEXUS_PASS: ${{ secrets[matrix.nexus_pass_secret] }}
NEXUS_URL: ${{ secrets.NEXUS_URL }} NEXUS_URL: ${{ secrets.NEXUS_URL }}
NEXUS_REPO: ${{ secrets[matrix.nexus_repo_secret] }} NEXUS_REPO: ${{ secrets[matrix.nexus_repo_secret] }}
DEB_FILE: ${{ steps.pkg.outputs.deb_file }} DEB_FILE: ${{ steps.pkg.outputs.deb_file }}
@@ -139,6 +179,11 @@ jobs:
set -euo pipefail set -euo pipefail
umask 077 umask 077
# Need curl + python3 to talk to Nexus REST. python3 came with the
# build deps; curl was installed by `bash build/X.sh new`. Add
# explicitly anyway since this step is independent.
apt-get install -y -q --no-install-recommends curl python3 ca-certificates >/dev/null
SECDIR="$(mktemp -d -p /dev/shm twiy-XXXXXXXX 2>/dev/null \ SECDIR="$(mktemp -d -p /dev/shm twiy-XXXXXXXX 2>/dev/null \
|| mktemp -d -t twiy-XXXXXXXX)" || mktemp -d -t twiy-XXXXXXXX)"
chmod 700 "$SECDIR" chmod 700 "$SECDIR"
@@ -152,6 +197,8 @@ jobs:
printf 'machine %s login %s password %s\n' \ printf 'machine %s login %s password %s\n' \
"$NEXUS_HOST" "$NEXUS_USER" "$NEXUS_PASS" > "$SECDIR/netrc" "$NEXUS_HOST" "$NEXUS_USER" "$NEXUS_PASS" > "$SECDIR/netrc"
unset NEXUS_USER NEXUS_PASS unset NEXUS_USER NEXUS_PASS
# Replace prior version of this same package in this same repo.
OLD_ID="$(curl -fsS --netrc-file "$SECDIR/netrc" \ OLD_ID="$(curl -fsS --netrc-file "$SECDIR/netrc" \
"$NEXUS_URL/service/rest/v1/components?repository=$NEXUS_REPO" \ "$NEXUS_URL/service/rest/v1/components?repository=$NEXUS_REPO" \
| PKG_NAME="$PKG_NAME" python3 -c ' | PKG_NAME="$PKG_NAME" python3 -c '