chore: refactor release workflow for modular distro and upstream builds
This commit is contained in:
283
.github/workflows/release.yml
vendored
283
.github/workflows/release.yml
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user