1010 - " **"
1111 schedule :
1212 - cron : " 0 3 * * *" # run every day at 3am UTC (nightly builds)
13- workflow_call :
13+ workflow_dispatch :
1414 inputs :
1515 is_production_release :
16+ description : ' Is this a production release?'
1617 required : false
1718 type : boolean
1819 default : false
1920 release_version :
21+ description : ' Release version (e.g., v2.0.3)'
2022 required : false
2123 type : string
2224 default : ' '
2325 operator_version :
26+ description : ' Operator release version (e.g., v1.0.0). Optional'
2427 required : false
2528 type : string
2629 default : ' '
2730 dry_run :
31+ description : ' If true, does a dry run of the production workflow'
2832 required : false
2933 type : boolean
3034 default : false
@@ -34,13 +38,70 @@ defaults:
3438 shell : bash
3539
3640concurrency :
37- group : ${{ github.ref_name } }-ci
38- cancel-in-progress : true
41+ group : ${{ inputs.is_production_release && format('prod-{0}', inputs.release_version) || format('{0 }-ci', github.ref_name) }}
42+ cancel-in-progress : ${{ !inputs.is_production_release }}
3943
4044permissions :
4145 contents : read
4246
4347jobs :
48+ create-tag-and-release :
49+ runs-on : ubuntu-24.04
50+ if : github.event_name == 'workflow_dispatch' && inputs.release_version != '' && startsWith(github.ref, 'refs/heads/release-')
51+ permissions :
52+ contents : write
53+ steps :
54+ - name : Validate Release Branch and Version
55+ run : |
56+ echo "Validating release from: ${GITHUB_REF}"
57+
58+ INPUT_VERSION="${{ inputs.release_version }}"
59+ INPUT_OPERATOR_VERSION="${{ inputs.operator_version }}"
60+
61+ # Validate version format
62+ if [[ ! "${INPUT_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
63+ echo "❌ Invalid version format: ${INPUT_VERSION}"
64+ echo "Expected format: v1.2.3"
65+ exit 1
66+ fi
67+
68+ # Validate version format if operator version is provided
69+ if [[ -n "${INPUT_OPERATOR_VERSION}" && ! "${INPUT_OPERATOR_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
70+ echo "❌ Invalid operator version format: ${INPUT_OPERATOR_VERSION}"
71+ echo "Expected format: v1.2.3"
72+ exit 1
73+ fi
74+
75+ echo "✅ Valid release branch: ${GITHUB_REF}"
76+ echo "✅ Valid version format: ${INPUT_VERSION}"
77+ [[ -n "${INPUT_OPERATOR_VERSION}" ]] && echo "✅ Valid operator version format: ${INPUT_OPERATOR_VERSION}"
78+
79+ - name : Checkout Repository
80+ uses : actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
81+ with :
82+ fetch-depth : 0
83+
84+ - name : Create Release Tag
85+ run : |
86+ VERSION="${{ inputs.release_version }}"
87+ git config user.name "NGF Release Bot"
88+ git config user.email "[email protected] " 89+
90+ if git rev-parse --verify "refs/tags/${VERSION}" >/dev/null 2>&1; then
91+ echo "Tag ${VERSION} already exists - skipping tag creation"
92+ else
93+ echo "Creating annotated tag ${VERSION}"
94+ git tag -a "${VERSION}" -m "Release ${VERSION}"
95+
96+ if [[ "${{ inputs.dry_run }}" == "true" ]]; then
97+ echo "DRY RUN: Would push tag ${VERSION} and operator tag ${{ inputs.operator_version || '' }}"
98+ git push --dry-run origin "${VERSION}"
99+ else
100+ git push origin "${VERSION}"
101+ echo "Created and pushed tag: ${VERSION}"
102+ fi
103+ fi
104+
44105 vars :
45106 name : Checks and variables
46107 runs-on : ubuntu-24.04
@@ -224,7 +285,7 @@ jobs:
224285
225286 - name : Download Syft
226287 if : ${{ inputs.is_production_release }}
227- uses : anchore/sbom-action/download-syft@aa0e114b2e19480f157109b9922bda359bd98b90 # v0.20.8
288+ uses : anchore/sbom-action/download-syft@8e94d75ddd33f69f691467e42275782e4bfefe84 # v0.20.9
228289
229290 - name : Install Cosign
230291 if : ${{ inputs.is_production_release }}
@@ -233,7 +294,7 @@ jobs:
233294 - name : Build binary
234295 uses : goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
235296 with :
236- version : v2.12.5 # renovate: datasource=github-tags depName=goreleaser/goreleaser
297+ version : v2.12.6 # renovate: datasource=github-tags depName=goreleaser/goreleaser
237298 args : ${{ (inputs.is_production_release && (inputs.dry_run == false || inputs.dry_run == null)) && 'release' || 'build --snapshot' }} --clean
238299 env :
239300 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
@@ -485,21 +546,25 @@ jobs:
485546 with :
486547 image : ${{ matrix.image }}
487548 k8s-version : ${{ matrix.k8s-version }}
549+ tag : ${{ inputs.release_version || '' }}
488550 secrets : inherit
489551 if : ${{ needs.vars.outputs.helm_changes == 'true' || github.event_name == 'schedule' }}
490552
491553 publish-helm :
492554 name : Package and Publish Helm Chart
493- runs-on : ${{ github.repository_owner == 'nginx' && (inputs.is_production_release || ((github.event_name == 'push' || github.event_name == 'schedule') && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-')))) && 'ubuntu-24.04-amd64' || 'ubuntu-24.04' }}
555+ runs-on : ${{ github.repository_owner == 'nginx' && 'ubuntu-24.04-amd64' || 'ubuntu-24.04' }}
494556 needs : [vars, helm-tests]
495- if : ${{ ( inputs.is_production_release && (inputs.dry_run == false || inputs.dry_run == null)) || ( github.event_name == 'push' && ! startsWith(github.ref, ' refs/heads/release-')) }}
557+ if : ${{ inputs.is_production_release || github.ref == 'refs/heads/main' }}
496558 permissions :
497559 contents : read
498560 packages : write # for helm to push to GHCR
499561 steps :
500562 - name : Checkout Repository
501563 uses : actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
502564
565+ - name : Setup Helm
566+ uses : azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1
567+
503568 - name : Login to GitHub Container Registry
504569 uses : docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
505570 with :
0 commit comments