-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathrelease-pipeline.yaml
More file actions
548 lines (522 loc) · 20.1 KB
/
release-pipeline.yaml
File metadata and controls
548 lines (522 loc) · 20.1 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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: pipeline-release
spec:
params:
- name: package
description: package to release
default: github.com/tektoncd/pipeline
- name: repoName
description: repository name (e.g., pipeline, triggers, etc.)
default: pipeline
- name: gitRevision
description: the git revision to release
- name: imageRegistry
description: The target image registry
default: ghcr.io
- name: imageRegistryPath
description: The path (project) in the image registry
default: "tekton-releases-nightly" # Will be overridden based on releaseMode
- name: imageRegistryRegions
description: The target image registry regions
default: "" # Empty for GHCR, "us eu asia" for GCR
- name: imageRegistryUser
description: The user for the image registry credentials
default: _json_key
- name: versionTag
description: Version tag (vX.Y.Z for stable, vYYYYMMDD-abc1234 for nightly)
- name: releaseBucket
description: bucket where the release is stored. The bucket must be project specific.
default: "tekton-nightly" # Will be overridden based on releaseMode
- name: releaseAsLatest
description: Whether to tag and publish this release as latest
default: "false" # Will be overridden based on releaseMode
- name: buildPlatforms
description: Platforms to build images for (e.g. linux/amd64,linux/arm64)
default: linux/amd64,linux/arm64,linux/s390x,linux/ppc64le
- name: publishPlatforms
description: |
Platforms to publish images for (e.g. linux/amd64,linux/arm64,windows/amd64). This
can differ from buildPlatforms due to the fact that a windows-compatible base image
is constructed for the publishing phase.)
default: linux/amd64,linux/arm64,linux/s390x,linux/ppc64le,windows/amd64
- name: koExtraArgs
description: Extra args to be passed to ko
default: "--preserve-import-paths"
- name: serviceAccountImagesPath
description: The path to the service account file or credentials within the release-images-secret workspace
- name: runTests
description: If set to something other than "true", skip the build and test tasks
default: "true"
- name: previousReleaseTag
description: Previous release tag for changelog generation (e.g. v1.8.0). If empty, auto-detected from git tags.
default: ""
- name: releaseName
description: Release name (e.g. "Devon Rex Dreadnought"). If empty, uses version tag.
default: ""
workspaces:
- name: workarea
description: The workspace where the repo will be cloned.
- name: release-secret
description: The secret that contains auth credentials to push to the output bucket
- name: release-images-secret
description: The secret that contains a service account authorized to push to the imageRegistry
- name: github-secret
description: |
The secret containing GITHUB_TOKEN for creating draft releases.
When not bound, the draft-release tasks (wait-for-chains, prepare-draft-release,
create-draft-release) are skipped and the draft must be created manually
following the cheat sheet instructions.
optional: true
results:
- name: commit-sha
description: the sha of the commit that was released
value: $(tasks.git-clone.results.commit)
- name: release-file
description: the URL of the release file
value: $(tasks.report-bucket.results.release)
- name: release-file-no-tag
description: the URL of the release file
value: $(tasks.report-bucket.results.release-no-tag)
tasks:
- name: git-clone
taskRef:
resolver: bundles
params:
- name: bundle
value: ghcr.io/tektoncd/catalog/upstream/tasks/git-clone:0.7
- name: name
value: git-clone
- name: kind
value: task
workspaces:
- name: output
workspace: workarea
subPath: git
params:
- name: url
value: https://$(params.package)
- name: revision
value: $(params.gitRevision)
- name: precheck
runAfter: [git-clone]
taskRef:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/plumbing
- name: revision
value: 50bc706c351cc05087564bb17afc1e658090edb0
- name: pathInRepo
value: tekton/resources/release/base/prerelease_checks_oci.yaml
params:
- name: package
value: $(params.package)
- name: versionTag
value: $(params.versionTag)
- name: releaseBucket
value: $(params.releaseBucket)/$(params.repoName)
workspaces:
- name: source-to-release
workspace: workarea
subPath: git
- name: oci-credentials
workspace: release-secret
- name: unit-tests
runAfter: [precheck]
when:
- cel: "'$(params.runTests)' == 'true'"
taskRef:
resolver: bundles
params:
- name: bundle
value: ghcr.io/tektoncd/catalog/upstream/tasks/golang-test:0.2
- name: name
value: golang-test
- name: kind
value: task
params:
- name: package
value: $(params.package)
- name: packages
value: "./..."
- name: flags
value: -v -mod=vendor
workspaces:
- name: source
workspace: workarea
subPath: git
- name: build
runAfter: [precheck]
when:
- cel: "'$(params.runTests)' == 'true'"
taskRef:
resolver: bundles
params:
- name: bundle
value: ghcr.io/tektoncd/catalog/upstream/tasks/golang-build:0.3
- name: name
value: golang-build
- name: kind
value: task
params:
- name: package
value: $(params.package)
- name: packages
value: ./cmd/...
workspaces:
- name: source
workspace: workarea
subPath: git
- name: publish-images
runAfter: [unit-tests, build]
taskRef:
resolver: git
params:
- name: repo
value: pipeline
- name: org
value: tektoncd
- name: revision
value: $(params.gitRevision)
- name: pathInRepo
value: tekton/publish.yaml
params:
- name: package
value: $(params.package)
- name: versionTag
value: $(params.versionTag)
- name: imageRegistry
value: $(params.imageRegistry)
- name: imageRegistryPath
value: $(params.imageRegistryPath)
- name: imageRegistryUser
value: $(params.imageRegistryUser)
- name: imageRegistryRegions
value: $(params.imageRegistryRegions)
- name: releaseAsLatest
value: $(params.releaseAsLatest)
- name: serviceAccountPath
value: $(params.serviceAccountImagesPath)
- name: platforms
value: $(params.publishPlatforms)
- name: koExtraArgs
value: $(params.koExtraArgs)
workspaces:
- name: source
workspace: workarea
subPath: git
- name: output
workspace: workarea
subPath: bucket
- name: release-secret
workspace: release-images-secret
timeout: 3h
- name: publish-to-bucket
runAfter: [publish-images]
taskRef:
resolver: bundles
params:
- name: bundle
value: ghcr.io/tektoncd/catalog/upstream/tasks/oracle-cloud-storage-upload:0.2
- name: name
value: oracle-cloud-storage-upload
- name: kind
value: task
workspaces:
- name: credentials
workspace: release-secret
- name: source
workspace: workarea
subPath: bucket
params:
- name: path
value: $(params.versionTag)
- name: bucketName
value: $(params.releaseBucket)
- name: objectPrefix
value: $(params.repoName)/previous/$(params.versionTag)/
- name: replaceExistingFiles
value: "true"
- name: recursive
value: "true"
- name: publish-to-bucket-latest
runAfter: [publish-images]
when:
- input: "$(params.releaseAsLatest)"
operator: in
values: ["true"]
taskRef:
resolver: bundles
params:
- name: bundle
value: ghcr.io/tektoncd/catalog/upstream/tasks/oracle-cloud-storage-upload:0.2
- name: name
value: oracle-cloud-storage-upload
- name: kind
value: task
workspaces:
- name: credentials
workspace: release-secret
- name: source
workspace: workarea
subPath: bucket
params:
- name: path
value: $(params.versionTag)
- name: bucketName
value: $(params.releaseBucket)
- name: objectPrefix
value: $(params.repoName)/latest/
- name: replaceExistingFiles
value: "true"
- name: recursive
value: "true"
- name: deleteExtraFiles
value: "true" # Uses sync to copy content into latest
- name: report-bucket
runAfter: [publish-to-bucket]
params:
- name: releaseBucket
value: $(params.releaseBucket)
- name: versionTag
value: $(params.versionTag)
- name: repoName
value: $(params.repoName)
taskSpec:
params:
- name: releaseBucket
- name: versionTag
- name: repoName
results:
- name: release
description: The full URL of the release file in the bucket
- name: release-no-tag
description: The full URL of the release file (no tag) in the bucket
steps:
- name: create-results
image: docker.io/library/alpine:3.20.3@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d
env:
- name: RELEASE_BUCKET
value: $(params.releaseBucket)
- name: VERSION_TAG
value: $(params.versionTag)
- name: REPO_NAME
value: $(params.repoName)
script: |
# Oracle Cloud Storage: Construct public URL
# Format: https://infra.tekton.dev/<releaseBucket>/<repoName>/previous/<versionTag>
BASE_URL="https://infra.tekton.dev/${RELEASE_BUCKET}/${REPO_NAME}/previous/${VERSION_TAG}"
echo "${BASE_URL}/release.yaml" > $(results.release.path)
echo "${BASE_URL}/release.notags.yaml" > $(results.release-no-tag.path)
- name: wait-for-chains
runAfter: [publish-images]
timeout: "30m"
when:
- input: "$(workspaces.github-secret.bound)"
operator: in
values: ["true"]
params:
- name: pipelineRunName
value: $(context.pipelineRun.name)
- name: namespace
value: $(context.pipelineRun.namespace)
taskSpec:
params:
- name: pipelineRunName
- name: namespace
results:
- name: rekor-uuid
description: Rekor UUID from Chains transparency log
- name: signed
description: Whether Chains signing succeeded (true, failed, or timeout)
steps:
- name: wait-and-extract
image: docker.io/library/alpine/k8s:1.32.2
script: |
#!/bin/sh
set -e
NAMESPACE="$(params.namespace)"
PIPELINERUN="$(params.pipelineRunName)"
# Find the TaskRun name for publish-images
# The TaskRun name follows the pattern: <pipelinerun>-<taskname>-<random>
echo "Looking for publish-images TaskRun in PipelineRun ${PIPELINERUN}..."
TASKRUN_NAME=""
MAX_FIND_ATTEMPTS=10
FIND_ATTEMPT=0
while [ -z "${TASKRUN_NAME}" ] && [ $FIND_ATTEMPT -lt $MAX_FIND_ATTEMPTS ]; do
TASKRUN_NAME=$(kubectl get taskrun -n "${NAMESPACE}" \
-l tekton.dev/pipelineRun="${PIPELINERUN}",tekton.dev/pipelineTask=publish-images \
-o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
if [ -z "${TASKRUN_NAME}" ]; then
FIND_ATTEMPT=$((FIND_ATTEMPT + 1))
echo " Attempt ${FIND_ATTEMPT}/${MAX_FIND_ATTEMPTS} - TaskRun not found yet..."
sleep 10
fi
done
if [ -z "${TASKRUN_NAME}" ]; then
echo "ERROR: Could not find publish-images TaskRun"
printf 'unknown' > "$(results.rekor-uuid.path)"
printf 'error' > "$(results.signed.path)"
# Don't fail the pipeline — the release artifacts are already published.
# The draft release can be created manually using the cheat sheet.
exit 0
fi
echo "Found TaskRun: ${TASKRUN_NAME}"
echo "Waiting for Chains to sign TaskRun ${TASKRUN_NAME}..."
MAX_ATTEMPTS=60 # 30 minutes with 30s interval
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
SIGNED=$(kubectl get taskrun "${TASKRUN_NAME}" -n "${NAMESPACE}" \
-o jsonpath='{.metadata.annotations.chains\.tekton\.dev/signed}' 2>/dev/null || echo "")
if [ "${SIGNED}" = "true" ] || [ "${SIGNED}" = "failed" ]; then
echo "Chains signing status: ${SIGNED}"
printf '%s' "${SIGNED}" > "$(results.signed.path)"
# Extract Rekor UUID from transparency URL
TRANSPARENCY=$(kubectl get taskrun "${TASKRUN_NAME}" -n "${NAMESPACE}" \
-o jsonpath='{.metadata.annotations.chains\.tekton\.dev/transparency}' 2>/dev/null || echo "")
if [ -n "${TRANSPARENCY}" ]; then
# URL format: https://rekor.sigstore.dev/api/v1/log/entries?logIndex=NNNN
REKOR_UUID=$(echo "${TRANSPARENCY}" | grep -oE 'logIndex=[0-9]+' | cut -d= -f2)
if [ -z "${REKOR_UUID}" ]; then
# Might be a direct UUID format
REKOR_UUID="${TRANSPARENCY}"
fi
echo "Rekor UUID: ${REKOR_UUID}"
printf '%s' "${REKOR_UUID}" > "$(results.rekor-uuid.path)"
else
echo "WARNING: No transparency URL found"
printf 'unknown' > "$(results.rekor-uuid.path)"
fi
exit 0
fi
ATTEMPT=$((ATTEMPT + 1))
echo " Attempt ${ATTEMPT}/${MAX_ATTEMPTS} - signing status: '${SIGNED}'"
sleep 30
done
echo "WARNING: Timed out waiting for Chains to sign"
printf 'timeout' > "$(results.signed.path)"
printf 'unknown' > "$(results.rekor-uuid.path)"
# Don't fail the pipeline — the release artifacts are already published.
# The draft release can be created manually using the cheat sheet.
exit 0
- name: prepare-draft-release
runAfter: [publish-to-bucket]
when:
- input: "$(workspaces.github-secret.bound)"
operator: in
values: ["true"]
params:
- name: package
value: $(params.package)
- name: versionTag
value: $(params.versionTag)
- name: previousReleaseTag
value: $(params.previousReleaseTag)
- name: releaseName
value: $(params.releaseName)
workspaces:
- name: workarea
workspace: workarea
taskSpec:
params:
- name: package
- name: versionTag
- name: previousReleaseTag
- name: releaseName
results:
- name: package
description: The package in org/repo format (without github.com/ prefix)
- name: previous-tag
description: The previous release tag
- name: release-name
description: The release name to use
workspaces:
- name: workarea
steps:
- name: setup
image: docker.io/library/alpine:3.21
script: |
#!/bin/sh
set -e
apk add --no-cache git > /dev/null 2>&1
WORKAREA="$(workspaces.workarea.path)"
VERSION="$(params.versionTag)"
PREVIOUS="$(params.previousReleaseTag)"
NAME="$(params.releaseName)"
# The create-draft-release-oci task expects:
# <workspace>/repo -> git checkout
# <workspace>/release -> release artifacts
# The release pipeline uses:
# <workspace>/git -> git checkout
# <workspace>/bucket/<versionTag> -> release artifacts
ln -sfn "${WORKAREA}/git" "${WORKAREA}/repo"
ln -sfn "${WORKAREA}/bucket/${VERSION}" "${WORKAREA}/release"
echo "Created workspace symlinks:"
ls -la "${WORKAREA}/repo" "${WORKAREA}/release"
# Strip github.com/ prefix from package for the draft release task
# (it expects org/repo format, e.g. tektoncd/pipeline)
PACKAGE=$(echo "$(params.package)" | sed 's|^github\.com/||')
printf '%s' "${PACKAGE}" > "$(results.package.path)"
echo "Package: ${PACKAGE}"
# Detect previous tag if not provided
if [ -z "${PREVIOUS}" ]; then
git config --global --add safe.directory "${WORKAREA}/git"
git -C "${WORKAREA}/git" fetch --tags
PREVIOUS=$(git -C "${WORKAREA}/git" tag --sort=-v:refname | grep '^v[0-9]' | while read tag; do
if [ "$(printf '%s\n%s' "$tag" "$VERSION" | sort -V | head -1)" = "$tag" ] && [ "$tag" != "$VERSION" ]; then
echo "$tag"
break
fi
done)
if [ -z "${PREVIOUS}" ]; then
echo "WARNING: Could not auto-detect previous tag"
PREVIOUS="unknown"
fi
echo "Auto-detected previous tag: ${PREVIOUS}"
fi
printf '%s' "${PREVIOUS}" > "$(results.previous-tag.path)"
# Use provided name or fall back to version
if [ -z "${NAME}" ]; then
NAME="Release ${VERSION}"
fi
printf '%s' "${NAME}" > "$(results.release-name.path)"
- name: create-draft-release
runAfter: [prepare-draft-release, wait-for-chains]
when:
- input: "$(workspaces.github-secret.bound)"
operator: in
values: ["true"]
- input: "$(tasks.wait-for-chains.results.signed)"
operator: in
values: ["true"]
taskRef:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/plumbing
# Pinned to current HEAD. Update after tektoncd/plumbing#3169 merges
# (modernizes hub→gh, adds flexible path params, removing the need
# for the prepare-draft-release symlink task).
- name: revision
value: c6ccd417b39dd9d0c3055795f00cbce051f6bc9e
- name: pathInRepo
value: tekton/resources/release/base/github_release_oci.yaml
params:
- name: package
value: $(tasks.prepare-draft-release.results.package)
- name: git-revision
value: $(params.gitRevision)
- name: release-name
value: $(tasks.prepare-draft-release.results.release-name)
- name: release-tag
value: $(params.versionTag)
- name: previous-release-tag
value: $(tasks.prepare-draft-release.results.previous-tag)
- name: rekor-uuid
value: $(tasks.wait-for-chains.results.rekor-uuid)
workspaces:
- name: shared
workspace: workarea