chore: refactor release workflow for modular distro and upstream builds

This commit is contained in:
2026-06-09 21:20:20 +03:30
parent f97ac2f7c5
commit 058d835f07
10 changed files with 1423 additions and 200 deletions

View File

@@ -3,8 +3,12 @@ name: Build and Release Module
"on":
workflow_dispatch:
inputs:
nginx_versions:
description: "Space-separated Nginx versions to build against"
distro_targets:
description: "Space-separated distro images to build in, for example: ubuntu:24.04 debian:12 debian:13"
required: true
default: "ubuntu:24.04 debian:12 debian:13"
upstream_nginx_versions:
description: "Space-separated upstream nginx.org versions for generic tarball builds"
required: true
default: "1.22.1 1.24.0 1.26.3 1.28.0 1.30.0"
target_arches:
@@ -21,7 +25,7 @@ name: Build and Release Module
- minor
- major
push_image:
description: "Push multi-platform Docker image to GHCR using the new tag"
description: "Push multi-platform demo Docker image to GHCR using the new tag"
type: boolean
required: true
default: true
@@ -31,9 +35,11 @@ permissions:
packages: write
env:
DEFAULT_NGINX_VERSIONS: "1.22.1 1.24.0 1.26.3 1.28.0 1.30.0"
DEFAULT_DISTRO_TARGETS: "ubuntu:24.04 debian:12 debian:13"
DEFAULT_UPSTREAM_NGINX_VERSIONS: "1.22.1 1.24.0 1.26.3 1.28.0 1.30.0"
DEFAULT_TARGET_ARCHES: "linux-x86_64 linux-arm64 linux-armv7"
MODULE_NAME: ngx_http_monitoring_module
DEB_PACKAGE_NAME: libnginx-mod-http-monitoring
RELEASE_BUILD_IMAGE: ubuntu:18.04
RELEASE_LIBC_BASELINE: ubuntu-bionic-glibc-2.27
NGINX_CONFIGURE_ARGS: >-
@@ -46,9 +52,9 @@ env:
jobs:
release:
name: Build module and publish release
name: Build distro modules and publish release
runs-on: ubuntu-22.04
timeout-minutes: 120
timeout-minutes: 240
steps:
- name: Check out repository
@@ -186,17 +192,75 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build release packages
- name: Build distro release packages
shell: bash
env:
INPUT_NGINX_VERSIONS: ${{ github.event.inputs.nginx_versions }}
INPUT_DISTRO_TARGETS: ${{ github.event.inputs.distro_targets }}
NORMALIZED_TARGET_ARCHES: ${{ steps.targets.outputs.target_arches }}
run: |
set -euo pipefail
versions="${INPUT_NGINX_VERSIONS:-$DEFAULT_NGINX_VERSIONS}"
distro_targets="${INPUT_DISTRO_TARGETS:-$DEFAULT_DISTRO_TARGETS}"
mkdir -p "$GITHUB_WORKSPACE/dist" "$GITHUB_WORKSPACE/.release-work"
if [[ -z "$distro_targets" ]]; then
echo "No distro_targets were selected" >&2
exit 1
fi
for distro_image in $distro_targets; do
for target_arch in $NORMALIZED_TARGET_ARCHES; do
case "$target_arch" in
linux-x86_64)
docker_platform="linux/amd64"
;;
linux-arm64)
docker_platform="linux/arm64"
;;
linux-armv7)
docker_platform="linux/arm/v7"
;;
*)
echo "Unexpected normalized target: $target_arch" >&2
exit 1
;;
esac
echo "::group::Build ${distro_image} ${target_arch}"
docker run --rm -i \
--platform "$docker_platform" \
-e DEB_PACKAGE_NAME \
-e DISTRO_IMAGE="$distro_image" \
-e DOCKER_PLATFORM="$docker_platform" \
-e GITHUB_REF \
-e GITHUB_SHA \
-e LATEST_TAG \
-e MODULE_NAME \
-e NEXT_TAG \
-e NEXT_VERSION \
-e TARGET_ARCH="$target_arch" \
-v "$GITHUB_WORKSPACE:/work" \
-w /work \
"$distro_image" \
bash /work/scripts/build-distro-release.sh
echo "::endgroup::"
done
done
- name: Build upstream nginx.org release tarballs
shell: bash
env:
INPUT_UPSTREAM_NGINX_VERSIONS: ${{ github.event.inputs.upstream_nginx_versions }}
NORMALIZED_TARGET_ARCHES: ${{ steps.targets.outputs.target_arches }}
run: |
set -euo pipefail
upstream_versions="${INPUT_UPSTREAM_NGINX_VERSIONS:-$DEFAULT_UPSTREAM_NGINX_VERSIONS}"
if [[ -z "$upstream_versions" ]]; then
echo "No upstream_nginx_versions were selected" >&2
exit 1
fi
for target_arch in $NORMALIZED_TARGET_ARCHES; do
case "$target_arch" in
linux-x86_64)
@@ -214,10 +278,11 @@ jobs:
;;
esac
echo "::group::Build ${target_arch} release packages"
echo "::group::Build nginx.org ${target_arch} tarballs"
docker run --rm -i \
--platform "$docker_platform" \
-e BUILD_NGINX_VERSIONS="$versions" \
-e BUILD_NGINX_VERSIONS="$upstream_versions" \
-e DIST_DIR=/work/dist \
-e DOCKER_PLATFORM="$docker_platform" \
-e GITHUB_REF \
-e GITHUB_SHA \
@@ -232,149 +297,76 @@ jobs:
-v "$GITHUB_WORKSPACE:/work" \
-w /work \
"$RELEASE_BUILD_IMAGE" \
bash -s <<'BUILD_SCRIPT'
bash /work/scripts/build-upstream-release.sh
echo "::endgroup::"
done
- name: Generate release manifests and notes
shell: bash
run: |
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
cd "$GITHUB_WORKSPACE/dist"
apt-get update
apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
curl \
file \
libpcre2-dev \
libssl-dev \
zlib1g-dev
rm -rf /var/lib/apt/lists/*
shopt -s nullglob
compatibility_files=( *.compatibility.json )
if [[ "${#compatibility_files[@]}" -eq 0 ]]; then
echo "No compatibility metadata files were generated" >&2
exit 1
fi
target_workdir="/work/.release-work/${TARGET_ARCH}"
mkdir -p "$target_workdir" /work/dist
jq -s \
--arg releaseTag "$NEXT_TAG" \
--arg generatedAt "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'{
schema: 1,
release_tag: $releaseTag,
generated_at: $generatedAt,
artifacts: .
}' \
"${compatibility_files[@]}" > COMPATIBILITY-MATRIX.json
for nginx_version in $BUILD_NGINX_VERSIONS; do
echo "::group::Nginx ${nginx_version} (${TARGET_ARCH})"
archive="nginx-${nginx_version}.tar.gz"
archive_path="${target_workdir}/${archive}"
workdir="${target_workdir}/nginx-${nginx_version}"
if [[ ! -f "$archive_path" ]]; then
curl -fsSLo "$archive_path" \
"https://nginx.org/download/${archive}"
fi
rm -rf "$workdir"
tar -xzf "$archive_path" -C "$target_workdir"
cd "$workdir"
./configure \
--prefix=/usr/local/nginx \
--sbin-path=/usr/local/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
$NGINX_CONFIGURE_ARGS \
--add-dynamic-module=/work
make -j"$(nproc)" modules
package="${MODULE_NAME}-${NEXT_TAG}-nginx-${nginx_version}-${TARGET_ARCH}"
package_dir="/work/dist/$package"
mkdir -p "$package_dir/modules" "$package_dir/examples" "$package_dir/docs"
cp "objs/${MODULE_NAME}.so" "$package_dir/modules/${MODULE_NAME}.so"
strip --strip-unneeded "$package_dir/modules/${MODULE_NAME}.so" || true
cp /work/examples/nginx.conf "$package_dir/examples/nginx.conf"
cp /work/examples/monitoring-site.conf "$package_dir/examples/monitoring-site.conf"
cp /work/README.md "$package_dir/README.md"
cp /work/docs/API.md "$package_dir/docs/API.md"
cp /work/docs/CONFIGURATION.md "$package_dir/docs/CONFIGURATION.md"
cp /work/docs/PERFORMANCE.md "$package_dir/docs/PERFORMANCE.md"
{
printf 'module=%s\n' "$MODULE_NAME"
printf 'module_version=%s\n' "$NEXT_VERSION"
printf 'release_tag=%s\n' "$NEXT_TAG"
printf 'previous_tag=%s\n' "$LATEST_TAG"
printf 'nginx_version=%s\n' "$nginx_version"
printf 'target=%s\n' "$TARGET_ARCH"
printf 'docker_platform=%s\n' "$DOCKER_PLATFORM"
printf 'build_image=%s\n' "$RELEASE_BUILD_IMAGE"
printf 'libc_baseline=%s\n' "$RELEASE_LIBC_BASELINE"
printf 'build_machine=%s\n' "$(uname -m)"
printf 'runner=ubuntu-22.04\n'
printf 'git_ref=%s\n' "$GITHUB_REF"
printf 'git_sha=%s\n' "$GITHUB_SHA"
printf 'configure_args=%s\n' "$NGINX_CONFIGURE_ARGS"
printf 'built_at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
} > "$package_dir/METADATA.txt"
{
printf '# %s for Nginx %s\n\n' "$MODULE_NAME" "$nginx_version"
printf 'Release: `%s`\n\n' "$NEXT_TAG"
printf 'Target: `%s` (`%s`)\n\n' "$TARGET_ARCH" "$DOCKER_PLATFORM"
printf 'Libc baseline: `%s`\n\n' "$RELEASE_LIBC_BASELINE"
printf 'This package contains a prebuilt Linux dynamic module:\n\n'
printf '```text\n'
printf 'modules/%s.so\n' "$MODULE_NAME"
printf '```\n\n'
printf 'Copy it into your Nginx modules directory and add this near the top of `nginx.conf`:\n\n'
printf '```nginx\n'
printf 'load_module modules/%s.so;\n' "$MODULE_NAME"
printf '```\n\n'
printf 'This binary is built with `--with-compat` against Nginx %s on Ubuntu Bionic 18.04 for %s. ' "$nginx_version" "$TARGET_ARCH"
printf 'For safest production use, run the same Nginx version, CPU architecture, and a Linux/glibc environment compatible with `%s`. ' "$RELEASE_LIBC_BASELINE"
printf 'If your Nginx package has a materially different module ABI, rebuild from source with this repository.\n'
} > "$package_dir/INSTALL.md"
(
cd "$package_dir"
sha256sum "modules/${MODULE_NAME}.so" > SHA256SUMS
file "modules/${MODULE_NAME}.so" > FILE.txt
)
tar -czf "/work/dist/$package.tar.gz" -C /work/dist "$package"
rm -rf "$package_dir"
echo "::endgroup::"
done
BUILD_SCRIPT
echo "::endgroup::"
done
(
cd "$GITHUB_WORKSPACE/dist"
sha256sum *.tar.gz > SHA256SUMS.txt
)
find . -maxdepth 1 -type f \
\( -name '*.deb' -o -name '*.tar.gz' -o -name '*.compatibility.json' -o -name 'COMPATIBILITY-MATRIX.json' \) \
-print0 \
| sort -z \
| xargs -0 sha256sum > SHA256SUMS.txt
{
printf '# ngx_http_monitoring_module %s\n\n' "$NEXT_TAG"
printf '# %s %s\n\n' "$MODULE_NAME" "$NEXT_TAG"
printf 'Previous tag: `%s`\n\n' "$LATEST_TAG"
printf 'Libc baseline: `%s`\n\n' "$RELEASE_LIBC_BASELINE"
printf 'Prebuilt Linux dynamic module packages are attached for targets: `%s`.\n\n' "$NORMALIZED_TARGET_ARCHES"
printf 'Each tarball is built against the Nginx version and target architecture in its filename and includes:\n\n'
printf -- '- `modules/%s.so`\n' "$MODULE_NAME"
printf -- '- `INSTALL.md`\n'
printf -- '- `METADATA.txt`\n'
printf -- '- `SHA256SUMS`\n'
printf -- '- example configuration and API docs\n\n'
printf 'Nginx dynamic modules are ABI-sensitive. Use the package matching your Nginx version and CPU architecture, and rebuild locally if your Nginx distribution uses incompatible build options.\n'
} > "$GITHUB_WORKSPACE/dist/RELEASE_NOTES.md"
printf 'This release includes two artifact tiers:\n\n'
printf -- '- distro `.deb` packages built from Ubuntu/Debian Nginx source packages and pinned to the matching packaged Nginx revision\n'
printf -- '- nginx.org upstream-version tarballs for users who build or run Nginx from upstream source versions\n\n'
printf 'Recommended production artifacts are the `.deb` packages. They depend on the exact distro `nginx-abi-*` virtual package when the distribution exposes one and on the exact Nginx binary package version used for the build. That strict pin prevents Nginx package revisions from silently reusing an unrebuilt module.\n\n'
printf 'The nginx.org `.tar.gz` packages preserve upstream-version coverage but are not a safe substitute for distro packages on Ubuntu/Debian packaged Nginx.\n\n'
printf '## Distro Package Matrix\n\n'
jq -r '
.artifacts[]
| select(.build.method == "distro-source-package")
| "- `\(.artifacts.deb_file)`: \(.target.os_id) \(.target.os_version) \(.target.architecture), "
+ "\(.nginx.binary_package) \(.nginx.binary_version), source \(.nginx.source_package) \(.nginx.source_version), "
+ "ABI `\(if .nginx.abi == "" then "package-version-pinned" else .nginx.abi end)`"
' COMPATIBILITY-MATRIX.json
printf '\n## nginx.org Tarballs\n\n'
jq -r '
.artifacts[]
| select(.build.method == "upstream-nginxorg-source")
| "- `\(.artifacts.tarball_file)`: nginx.org \(.nginx.source_version), \(.target.architecture), baseline `\(.target.libc_baseline)`"
' COMPATIBILITY-MATRIX.json
printf '\n## Validation\n\n'
printf 'Distro `.deb` artifacts are installed into their target distro containers and validated with packaged `nginx -t` plus live endpoint checks. nginx.org tarballs are validated with the Nginx binary built from the same upstream source during the tarball build.\n'
} > RELEASE_NOTES.md
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: ngx-http-monitoring-module-${{ steps.version.outputs.next_tag }}-release-assets
path: |
dist/*.deb
dist/*.tar.gz
dist/*.compatibility.json
dist/COMPATIBILITY-MATRIX.json
dist/SHA256SUMS.txt
dist/RELEASE_NOTES.md
if-no-files-found: error
@@ -393,7 +385,12 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
gh release create "$NEXT_TAG" dist/*.tar.gz dist/SHA256SUMS.txt \
gh release create "$NEXT_TAG" \
dist/*.deb \
dist/*.tar.gz \
dist/*.compatibility.json \
dist/COMPATIBILITY-MATRIX.json \
dist/SHA256SUMS.txt \
--title "$NEXT_TAG" \
--notes-file dist/RELEASE_NOTES.md
@@ -414,7 +411,7 @@ jobs:
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Build and push Docker image
- name: Build and push demo Docker image
if: github.event.inputs.push_image == 'true'
uses: docker/build-push-action@v6
with:
@@ -423,8 +420,8 @@ jobs:
platforms: ${{ steps.targets.outputs.docker_platforms }}
push: true
build-args: |
BASE_IMAGE=ubuntu:18.04
OPENSSL_RUNTIME_PACKAGE=libssl1.1
BASE_IMAGE=debian:bookworm-slim
OPENSSL_RUNTIME_PACKAGE=libssl3
tags: |
${{ steps.image.outputs.repo }}:${{ steps.version.outputs.next_tag }}
${{ steps.image.outputs.repo }}:latest

View File

@@ -265,3 +265,66 @@ jobs:
.ci-runtime/${{ matrix.target.name }}/nginx-${{ matrix.nginx-version }}/logs/*.log
.ci-runtime/${{ matrix.target.name }}/nginx-${{ matrix.nginx-version }}/nginx.conf
if-no-files-found: ignore
distro-package-compat:
name: Distro package compatibility (${{ matrix.distro-image }})
runs-on: ubuntu-22.04
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
distro-image:
- ubuntu:24.04
- debian:12
- debian:13
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Build package and validate against distro nginx
shell: bash
env:
DEB_PACKAGE_NAME: libnginx-mod-http-monitoring
DISTRO_IMAGE: ${{ matrix.distro-image }}
DOCKER_PLATFORM: linux/amd64
LATEST_TAG: none
MODULE_NAME: ngx_http_monitoring_module
NEXT_TAG: ci
NEXT_VERSION: 0.0.0
TARGET_ARCH: linux-x86_64
run: |
set -euo pipefail
mkdir -p "$GITHUB_WORKSPACE/.ci-distro-dist" "$GITHUB_WORKSPACE/.ci-distro-work"
docker run --rm -i \
--platform "$DOCKER_PLATFORM" \
-e DEB_PACKAGE_NAME \
-e DISTRO_IMAGE \
-e DIST_DIR=/work/.ci-distro-dist \
-e DOCKER_PLATFORM \
-e GITHUB_REF \
-e GITHUB_SHA \
-e LATEST_TAG \
-e MODULE_NAME \
-e NEXT_TAG \
-e NEXT_VERSION \
-e TARGET_ARCH \
-e WORK_ROOT=/work/.ci-distro-work \
-v "$GITHUB_WORKSPACE:/work" \
-w /work \
"$DISTRO_IMAGE" \
bash /work/scripts/build-distro-release.sh
- name: Upload distro compatibility artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: distro-package-compat-${{ strategy.job-index }}
path: |
.ci-distro-dist/*.deb
.ci-distro-dist/*.tar.gz
.ci-distro-dist/*.compatibility.json
if-no-files-found: ignore