428 lines
15 KiB
YAML
428 lines
15 KiB
YAML
name: Build and Release Module
|
|
|
|
"on":
|
|
workflow_dispatch:
|
|
inputs:
|
|
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:
|
|
description: "Space-separated targets: linux-x86_64 linux-arm64 linux-armv7"
|
|
required: true
|
|
default: "linux-x86_64 linux-arm64 linux-armv7"
|
|
version_bump:
|
|
description: "Semantic version part to increment from the latest v* tag"
|
|
required: true
|
|
type: choice
|
|
default: patch
|
|
options:
|
|
- patch
|
|
- minor
|
|
- major
|
|
push_image:
|
|
description: "Push multi-platform demo Docker image to GHCR using the new tag"
|
|
type: boolean
|
|
required: true
|
|
default: true
|
|
|
|
permissions:
|
|
contents: write
|
|
packages: write
|
|
|
|
env:
|
|
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: >-
|
|
--with-compat
|
|
--with-http_ssl_module
|
|
--with-http_stub_status_module
|
|
--with-http_realip_module
|
|
--with-http_v2_module
|
|
--with-http_gzip_static_module
|
|
|
|
jobs:
|
|
release:
|
|
name: Build distro modules and publish release
|
|
runs-on: ubuntu-22.04
|
|
timeout-minutes: 240
|
|
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Compute next release tag
|
|
id: version
|
|
shell: bash
|
|
env:
|
|
INPUT_VERSION_BUMP: ${{ github.event.inputs.version_bump }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
git fetch --tags --force
|
|
|
|
latest_tag="$(
|
|
git tag -l 'v*' \
|
|
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
|
|
| sort -V \
|
|
| tail -n 1 \
|
|
|| true
|
|
)"
|
|
if [[ -z "$latest_tag" ]]; then
|
|
latest_tag="v0.0.0"
|
|
fi
|
|
|
|
version="${latest_tag#v}"
|
|
IFS='.' read -r major minor patch <<< "$version"
|
|
|
|
case "$INPUT_VERSION_BUMP" in
|
|
major)
|
|
major=$((major + 1))
|
|
minor=0
|
|
patch=0
|
|
;;
|
|
minor)
|
|
minor=$((minor + 1))
|
|
patch=0
|
|
;;
|
|
patch)
|
|
patch=$((patch + 1))
|
|
;;
|
|
*)
|
|
echo "Unsupported version_bump: $INPUT_VERSION_BUMP" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
next_tag="v${major}.${minor}.${patch}"
|
|
while git rev-parse -q --verify "refs/tags/${next_tag}" >/dev/null; do
|
|
patch=$((patch + 1))
|
|
next_tag="v${major}.${minor}.${patch}"
|
|
done
|
|
|
|
{
|
|
printf 'NEXT_TAG=%s\n' "$next_tag"
|
|
printf 'NEXT_VERSION=%s\n' "${next_tag#v}"
|
|
printf 'LATEST_TAG=%s\n' "$latest_tag"
|
|
} >> "$GITHUB_ENV"
|
|
|
|
{
|
|
printf 'next_tag=%s\n' "$next_tag"
|
|
printf 'next_version=%s\n' "${next_tag#v}"
|
|
printf 'latest_tag=%s\n' "$latest_tag"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
echo "Latest tag: $latest_tag"
|
|
echo "Next tag: $next_tag"
|
|
|
|
- name: Normalize target architectures
|
|
id: targets
|
|
shell: bash
|
|
env:
|
|
INPUT_TARGET_ARCHES: ${{ github.event.inputs.target_arches }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
raw_targets="${INPUT_TARGET_ARCHES:-$DEFAULT_TARGET_ARCHES}"
|
|
normalized_targets=""
|
|
docker_platforms=""
|
|
|
|
add_target() {
|
|
local target_arch="$1"
|
|
local docker_platform="$2"
|
|
|
|
case " $normalized_targets " in
|
|
*" $target_arch "*)
|
|
return
|
|
;;
|
|
esac
|
|
|
|
normalized_targets="${normalized_targets}${normalized_targets:+ }${target_arch}"
|
|
docker_platforms="${docker_platforms}${docker_platforms:+,}${docker_platform}"
|
|
}
|
|
|
|
for raw_target in $raw_targets; do
|
|
case "$raw_target" in
|
|
linux-x86_64|x86_64|amd64|linux-amd64)
|
|
add_target "linux-x86_64" "linux/amd64"
|
|
;;
|
|
linux-arm64|linux-aarch64|arm64|aarch64)
|
|
add_target "linux-arm64" "linux/arm64"
|
|
;;
|
|
linux-armv7|linux-armhf|armv7|armhf)
|
|
add_target "linux-armv7" "linux/arm/v7"
|
|
;;
|
|
*)
|
|
echo "Unsupported target_arches entry: $raw_target" >&2
|
|
echo "Supported entries: linux-x86_64 linux-arm64 linux-armv7" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$normalized_targets" ]]; then
|
|
echo "No release target architectures were selected" >&2
|
|
exit 1
|
|
fi
|
|
|
|
{
|
|
printf 'target_arches=%s\n' "$normalized_targets"
|
|
printf 'docker_platforms=%s\n' "$docker_platforms"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
echo "Release targets: $normalized_targets"
|
|
echo "Docker platforms: $docker_platforms"
|
|
|
|
- name: Set up QEMU for ARM builds
|
|
uses: docker/setup-qemu-action@v3
|
|
with:
|
|
platforms: arm64,arm
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Build distro release packages
|
|
shell: bash
|
|
env:
|
|
INPUT_DISTRO_TARGETS: ${{ github.event.inputs.distro_targets }}
|
|
NORMALIZED_TARGET_ARCHES: ${{ steps.targets.outputs.target_arches }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
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)
|
|
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 nginx.org ${target_arch} tarballs"
|
|
docker run --rm -i \
|
|
--platform "$docker_platform" \
|
|
-e BUILD_NGINX_VERSIONS="$upstream_versions" \
|
|
-e DIST_DIR=/work/dist \
|
|
-e DOCKER_PLATFORM="$docker_platform" \
|
|
-e GITHUB_REF \
|
|
-e GITHUB_SHA \
|
|
-e LATEST_TAG \
|
|
-e MODULE_NAME \
|
|
-e NEXT_TAG \
|
|
-e NEXT_VERSION \
|
|
-e NGINX_CONFIGURE_ARGS \
|
|
-e RELEASE_BUILD_IMAGE \
|
|
-e RELEASE_LIBC_BASELINE \
|
|
-e TARGET_ARCH="$target_arch" \
|
|
-v "$GITHUB_WORKSPACE:/work" \
|
|
-w /work \
|
|
"$RELEASE_BUILD_IMAGE" \
|
|
bash /work/scripts/build-upstream-release.sh
|
|
echo "::endgroup::"
|
|
done
|
|
|
|
- name: Generate release manifests and notes
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
cd "$GITHUB_WORKSPACE/dist"
|
|
|
|
shopt -s nullglob
|
|
compatibility_files=( *.compatibility.json )
|
|
if [[ "${#compatibility_files[@]}" -eq 0 ]]; then
|
|
echo "No compatibility metadata files were generated" >&2
|
|
exit 1
|
|
fi
|
|
|
|
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
|
|
|
|
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 '# %s %s\n\n' "$MODULE_NAME" "$NEXT_TAG"
|
|
printf 'Previous tag: `%s`\n\n' "$LATEST_TAG"
|
|
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
|
|
|
|
- name: Create incremented tag
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
git tag -a "$NEXT_TAG" -m "Release $NEXT_TAG"
|
|
git push origin "$NEXT_TAG"
|
|
|
|
- name: Publish GitHub release
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
set -euo pipefail
|
|
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
|
|
|
|
- name: Compute Docker image name
|
|
if: github.event.inputs.push_image == 'true'
|
|
id: image
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
image_repo="$(echo "ghcr.io/${GITHUB_REPOSITORY}" | tr '[:upper:]' '[:lower:]')"
|
|
printf 'repo=%s\n' "$image_repo" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Log in to GHCR
|
|
if: github.event.inputs.push_image == 'true'
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ github.token }}
|
|
|
|
- name: Build and push demo Docker image
|
|
if: github.event.inputs.push_image == 'true'
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
file: dockerized/Dockerfile
|
|
platforms: ${{ steps.targets.outputs.docker_platforms }}
|
|
push: true
|
|
build-args: |
|
|
BASE_IMAGE=debian:bookworm-slim
|
|
OPENSSL_RUNTIME_PACKAGE=libssl3
|
|
tags: |
|
|
${{ steps.image.outputs.repo }}:${{ steps.version.outputs.next_tag }}
|
|
${{ steps.image.outputs.repo }}:latest
|