-
Notifications
You must be signed in to change notification settings - Fork 12
227 lines (202 loc) · 8.68 KB
/
release.yml
File metadata and controls
227 lines (202 loc) · 8.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: Create GitHub Release
# Triggered on tag pushes for operator, agent, and chart components.
# CLI releases are handled separately by cli-release.yaml (which also builds binaries).
#
# Tags follow the pattern <component>/v<version> (e.g. operator/v0.14.0).
# Release notes are generated by git-cliff scoped to the tagged component.
# Preview locally with: make changelog-preview COMPONENT=<name>
on:
push:
tags:
- 'operator/**'
- 'agent/**'
- 'chart/**'
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract component name from tag
id: extract
run: |
COMPONENT=$(echo "${{ github.ref_name }}" | cut -f 1 -d /)
echo "component=${COMPONENT}" >> $GITHUB_OUTPUT
- name: Install git-cliff
run: |
GC_VERSION=$(curl -sSf https://api.github.com/repos/orhun/git-cliff/releases/latest | grep '"tag_name"' | cut -d '"' -f 4)
curl -sSL "https://github.com/orhun/git-cliff/releases/download/${GC_VERSION}/git-cliff-${GC_VERSION#v}-x86_64-unknown-linux-gnu.tar.gz" \
| tar xz --wildcards "*/git-cliff" --strip-components=1
sudo mv git-cliff /usr/local/bin/
- name: Generate release notes
id: release_notes
run: |
COMPONENT="${{ steps.extract.outputs.component }}"
INCLUDE_PATH="${COMPONENT}/**"
# CLI code lives under operator/cmd/cli/ but is handled by cli-release.yaml
NOTES=$(git cliff \
--include-path "${INCLUDE_PATH}" \
--tag-pattern "${COMPONENT}/.*" \
--latest \
--strip all)
echo "notes<<EOF" >> $GITHUB_OUTPUT
echo "${NOTES}" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: operator/go.mod
cache: false
- name: Set up Python
uses: actions/setup-python@v6
with:
# Pinned to match agent-ci.yaml PYTHON_VERSION so notices generation
# uses the same interpreter as the agent build.
python-version: '3.13'
- name: Install go-licenses
run: make -C operator go-licenses
- name: Regenerate third-party notices
run: make notices
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Idempotent: skip create if the release already exists so workflow
# re-runs on the same tag can still reach the upload step below.
run: |
PRERELEASE_FLAG=""
# Release candidate tags (e.g. operator/v0.16.0-rc1) → mark as
# prerelease so they don't become "Latest" on the Releases page.
# Only -rc<N> is accepted; any other suffix after the version is
# rejected to keep the tag format predictable.
VERSION="${GITHUB_REF_NAME#*/}"
if [[ "${VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
: # plain release
elif [[ "${VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+$ ]]; then
PRERELEASE_FLAG="--prerelease"
else
echo "ERROR: tag '${GITHUB_REF_NAME}' does not match v<MAJOR>.<MINOR>.<PATCH> or v<MAJOR>.<MINOR>.<PATCH>-rc<N>" >&2
exit 1
fi
if ! gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then
gh release create "${{ github.ref_name }}" \
--title "${{ github.ref_name }}" \
--notes "${{ steps.release_notes.outputs.notes }}" \
${PRERELEASE_FLAG}
fi
- name: Upload third-party notices to release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
COMPONENT="${{ steps.extract.outputs.component }}"
case "${COMPONENT}" in
operator) NOTICES_FILE="operator/THIRD_PARTY_NOTICES.md" ;;
agent) NOTICES_FILE="agent/THIRD_PARTY_NOTICES.md" ;;
chart) NOTICES_FILE="THIRD_PARTY_NOTICES.md" ;;
*)
echo "ERROR: unknown component '${COMPONENT}' — no notices file mapping." >&2
exit 1
;;
esac
gh release upload "${{ github.ref_name }}" "${NOTICES_FILE}" --clobber
publish-chart:
if: startsWith(github.ref_name, 'chart/')
needs: release
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.16.2
- name: Verify chart version matches tag
id: chart-metadata
run: |
CHART_NAME=$(yq '.name' chart/Chart.yaml)
TAG_VERSION="${GITHUB_REF_NAME#chart/}"
CHART_VERSION=$(yq '.version' chart/Chart.yaml)
if [ "${TAG_VERSION}" != "${CHART_VERSION}" ]; then
echo "Tag version ${TAG_VERSION} does not match chart/Chart.yaml version ${CHART_VERSION}" >&2
exit 1
fi
echo "name=${CHART_NAME}" >> "${GITHUB_OUTPUT}"
echo "version=${CHART_VERSION}" >> "${GITHUB_OUTPUT}"
- name: Package chart
run: |
mkdir -p dist
helm package chart/ --destination dist/
- name: Log in to ghcr.io
run: |
echo "${{ secrets.GITHUB_TOKEN }}" \
| helm registry login ghcr.io --username "${{ github.actor }}" --password-stdin
# cosign reads ~/.docker/config.json; helm registry login writes its own
# config so cosign can't see those creds. Authenticate docker too so the
# downstream sign/attest steps can upload the .sig and SBOM layers.
- name: Log in to ghcr.io (docker, for cosign)
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push chart to ghcr.io
id: push-chart
env:
CHART_NAME: ${{ steps.chart-metadata.outputs.name }}
CHART_VERSION: ${{ steps.chart-metadata.outputs.version }}
run: |
set -euo pipefail
chart_repo="ghcr.io/nvidia/nodewright/charts"
chart_subject="${chart_repo}/${CHART_NAME}"
# `helm push` writes "Pushed:" and "Digest:" to stderr (helm 3.16+),
# so capture both streams or awk sees an empty string.
push_output="$(helm push "dist/${CHART_NAME}-${CHART_VERSION}.tgz" "oci://${chart_repo}" 2>&1)"
printf '%s\n' "${push_output}"
chart_digest="$(awk '/^Digest:/ {print $2}' <<< "${push_output}")"
if ! [[ "${chart_digest}" =~ ^sha256:[a-f0-9]{64}$ ]]; then
echo "::error::failed to parse Helm chart digest from helm push output"
exit 1
fi
echo "subject-name=${chart_subject}" >> "${GITHUB_OUTPUT}"
echo "digest=${chart_digest}" >> "${GITHUB_OUTPUT}"
- name: Sign GHCR Helm chart and attach SBOM
uses: ./.github/actions/cosign-sign-sbom
with:
subject-name: ${{ steps.push-chart.outputs.subject-name }}
subject-digest: ${{ steps.push-chart.outputs.digest }}
sbom-source: chart
- name: Attest GHCR Helm chart provenance
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-name: ${{ steps.push-chart.outputs.subject-name }}
subject-digest: ${{ steps.push-chart.outputs.digest }}
push-to-registry: true
- name: Verify GHCR Helm chart signature and attestations
uses: ./.github/actions/cosign-verify-release
with:
subject-name: ${{ steps.push-chart.outputs.subject-name }}
subject-digest: ${{ steps.push-chart.outputs.digest }}
certificate-identity-regexp: ^https://github.com/${{ github.repository }}/\.github/workflows/release\.yml@refs/tags/chart/.*$