Skip to content

Release

Release #4

Workflow file for this run

name: Release
"on":
push:
tags:
- "v*"
workflow_dispatch:
inputs:
release_tag:
description: "Release tag to publish, for example v0.1.0"
required: true
type: string
permissions:
contents: write
packages: write
attestations: write
artifact-metadata: write
id-token: write
concurrency:
group: ${{ github.workflow }}-${{ github.event.inputs.release_tag || github.ref_name || github.run_id }}
cancel-in-progress: false
jobs:
metadata:
name: Metadata
runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.vars.outputs.release_tag }}
checkout_ref: ${{ steps.vars.outputs.checkout_ref }}
control_image: ${{ steps.vars.outputs.control_image }}
control_image_name: ${{ steps.vars.outputs.control_image_name }}
dataplane_image: ${{ steps.vars.outputs.dataplane_image }}
dashboard_image: ${{ steps.vars.outputs.dashboard_image }}
steps:
- name: Compute release metadata
id: vars
run: |
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
release_tag="${{ github.event.inputs.release_tag }}"
else
release_tag="${GITHUB_REF_NAME}"
fi
if [[ -z "${release_tag}" ]]; then
echo "release tag is required" >&2
exit 1
fi
owner_lc="${GITHUB_REPOSITORY_OWNER,,}"
checkout_ref="refs/tags/${release_tag}"
control_image_name="ghcr.io/${owner_lc}/nantian-controlplane"
control_image="${control_image_name}:${release_tag}"
dataplane_image="ghcr.io/${owner_lc}/dataplane:${release_tag}"
dashboard_image="ghcr.io/${owner_lc}/dashboard:${release_tag}"
{
echo "release_tag=${release_tag}"
echo "checkout_ref=${checkout_ref}"
echo "control_image=${control_image}"
echo "control_image_name=${control_image_name}"
echo "dataplane_image=${dataplane_image}"
echo "dashboard_image=${dashboard_image}"
} >>"${GITHUB_OUTPUT}"
security-scans:
name: Security Scans
needs: metadata
permissions:
contents: read
security-events: read
uses: ./.github/workflows/security-scans.yml
with:
checkout_ref: ${{ needs.metadata.outputs.checkout_ref }}
controlplane:
name: Controlplane Tests
runs-on: ubuntu-latest
needs: metadata
timeout-minutes: 20
steps:
- name: Checkout workflow helpers
uses: actions/checkout@v6
- name: Checkout release source
uses: actions/checkout@v6
with:
ref: ${{ needs.metadata.outputs.checkout_ref }}
path: release-src
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: release-src/go.mod
cache-dependency-path: release-src/go.sum
- name: Run Go unit tests
working-directory: release-src
run: go test -count=1 -timeout 5m ./...
kind-smoke:
name: Kind Validation
runs-on: ubuntu-latest
needs:
- metadata
- controlplane
timeout-minutes: 90
env:
CLUSTER_NAME: release-validation
GATEWAY_API_VERSION: v1.5.1
CONTROLPLANE_IMAGE: ${{ needs.metadata.outputs.control_image }}
DATAPLANE_IMAGE: ${{ needs.metadata.outputs.dataplane_image }}
DASHBOARD_IMAGE: ${{ needs.metadata.outputs.dashboard_image }}
CONFORMANCE_EXPERIMENTAL: "true"
ALL_FEATURES: "true"
steps:
- name: Checkout workflow helpers
uses: actions/checkout@v6
- name: Checkout release source
uses: actions/checkout@v6
with:
ref: ${{ needs.metadata.outputs.checkout_ref }}
fetch-depth: 0
path: release-src
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: release-src/go.mod
cache-dependency-path: release-src/go.sum
- name: Install Kind tooling
working-directory: release-src
run: scripts/ci/install-kind-tools.sh
- name: Create kind cluster
working-directory: release-src
run: scripts/ci/create-kind-cluster.sh
- name: Install Gateway API CRDs
working-directory: release-src
run: scripts/ci/install-gateway-api-crds.sh
- name: Build current control-plane image
working-directory: release-src
run: scripts/ci/build-controlplane-image.sh
- name: Load images into kind
working-directory: release-src
run: scripts/ci/load-kind-images.sh
- name: Deploy Nantian Gateway
working-directory: release-src
run: scripts/ci/deploy-kind-conformance.sh
- name: Record image versions
run: |
echo "=== Images under test ==="
kubectl get pods -n nantian-gw -o json | jq -r '.items[] | .spec.containers[] | " \(.name): \(.image)"'
echo "=== Image digests ==="
kubectl get pods -n nantian-gw -o json | jq -r '.items[] | .status.containerStatuses[] | " \(.name): \(.imageID)"'
- name: Run smoke test
run: CLUSTER_NAME="$CLUSTER_NAME" GATEWAY_HTTP_PORT=80 ./test/e2e/smoke/run.sh --no-cleanup --skip-bootstrap
- name: Run full Gateway API conformance
id: conformance
env:
RELEASE_TAG: ${{ needs.metadata.outputs.release_tag }}
working-directory: release-src
run: |
mkdir -p dist/conformance
report_path="${GITHUB_WORKSPACE}/release-src/dist/conformance/report.yaml"
set +e
go test -tags=conformance -count=1 -v -timeout 30m ./conformance/ \
-args \
-gateway-class nantian-gw \
-report-output "$report_path" \
-organization "Nantian Gateway" \
-project "Nantian Gateway" \
-url "https://github.com/nantian-gw/gateway" \
-version "${RELEASE_TAG}" \
-contact "https://github.com/nantian-gw/gateway/issues" 2>&1 \
| tee dist/conformance/run.log
status=${PIPESTATUS[0]}
echo "exit_code=${status}" >>"${GITHUB_OUTPUT}"
exit "${status}"
- name: Collect diagnostics on failure
if: failure()
working-directory: release-src
run: ARTIFACT_DIR=tmp/conformance-diagnostics scripts/ci/collect-kind-diagnostics.sh
- name: Upload conformance artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: conformance-${{ needs.metadata.outputs.release_tag }}
path: |
release-src/dist/conformance/
release-src/tmp/conformance-diagnostics/
if-no-files-found: warn
- name: Cleanup
if: always()
run: command -v kind >/dev/null 2>&1 && kind delete cluster --name "$CLUSTER_NAME" || true
publish:
name: Publish Release Images
runs-on: ubuntu-latest
needs:
- metadata
- controlplane
- kind-smoke
timeout-minutes: 45
outputs:
control_digest: ${{ steps.build-controlplane.outputs.digest }}
steps:
- name: Checkout workflow helpers
uses: actions/checkout@v6
- name: Checkout release source
uses: actions/checkout@v6
with:
ref: ${{ needs.metadata.outputs.checkout_ref }}
path: release-src
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: release-src/go.mod
cache-dependency-path: release-src/go.sum
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push controlplane image
id: build-controlplane
uses: docker/build-push-action@v7
with:
context: release-src
file: release-src/Dockerfile
push: true
tags: ${{ needs.metadata.outputs.control_image }}
- name: Prepare image metadata directory
run: mkdir -p release-src/dist/image-metadata
- name: Generate image provenance
env:
RELEASE_TAG: ${{ needs.metadata.outputs.release_tag }}
CONTROL_DIGEST: ${{ steps.build-controlplane.outputs.digest }}
CONTROL_IMAGE: ${{ needs.metadata.outputs.control_image }}
TIMESTAMP: ${{ github.event.repository.updated_at }}
run: |
cat > release-src/dist/image-metadata/provenance.json <<HEREDOC
{
"release": "${RELEASE_TAG}",
"ci_run": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"controlplane": {
"image": "${CONTROL_IMAGE}",
"digest": "${CONTROL_DIGEST}"
},
"timestamp": "${TIMESTAMP}"
}
HEREDOC
- name: Upload image metadata artifact
if: always()
uses: actions/upload-artifact@v7
with:
name: image-metadata-${{ needs.metadata.outputs.release_tag }}
path: release-src/dist/image-metadata/
if-no-files-found: warn