Skip to content

Commit 459c291

Browse files
nightly release with gh actions
1 parent 2c9e5ee commit 459c291

File tree

5 files changed

+374
-86
lines changed

5 files changed

+374
-86
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
name: Tekton Nightly Build
2+
3+
on:
4+
schedule:
5+
# Run at 03:00 UTC daily
6+
- cron: "0 3 * * *"
7+
workflow_dispatch:
8+
inputs:
9+
kubernetes_version:
10+
description: 'Kubernetes version to test with'
11+
required: false
12+
default: 'v1.33.0'
13+
type: choice
14+
options:
15+
- v1.33.0
16+
- v1.32.0
17+
- v1.31.0
18+
dry_run:
19+
description: 'Perform dry run (no actual publishing)'
20+
required: false
21+
default: false
22+
type: boolean
23+
nightly_bucket:
24+
description: 'Nightly bucket for builds'
25+
required: false
26+
default: 'gs://tekton-releases-nightly/pipeline'
27+
type: string
28+
# uncomment the following to enable manual testing of the workflow
29+
# push:
30+
# branches:
31+
# - test-rel
32+
# paths:
33+
# - '.github/workflows/nightly-builds.yaml'
34+
# - 'tekton/**'
35+
# - 'cmd/**'
36+
# - 'pkg/**'
37+
38+
env:
39+
KUBERNETES_VERSION: ${{ inputs.kubernetes_version || 'v1.33.0' }}
40+
REGISTRY: ghcr.io
41+
DRY_RUN: ${{ inputs.dry_run || false }}
42+
43+
COMPONENT: pipeline
44+
45+
PACKAGE: github.com/${{ github.repository }}
46+
GIT_ORG: ${{ github.repository_owner }}
47+
GIT_REPO: ${{ github.event.repository.name }}
48+
BUCKET: ${{ inputs.nightly_bucket || 'gs://anitha-tekton-nightly-test/pipeline' }}
49+
IMAGE_REGISTRY_PATH: ${{ github.repository }}
50+
IMAGE_REGISTRY_USER: ${{ github.actor }}
51+
52+
jobs:
53+
build:
54+
name: Nightly Build (K8s ${{ inputs.kubernetes_version || 'v1.33.0' }})
55+
runs-on: ubuntu-latest
56+
57+
permissions:
58+
contents: read
59+
packages: write
60+
id-token: write
61+
62+
steps:
63+
- name: Checkout repository
64+
uses: actions/checkout@v4
65+
with:
66+
fetch-depth: 0
67+
68+
- name: Generate version info
69+
id: version
70+
run: |
71+
latest_sha=${{ github.sha }}
72+
date_tag=$(date +v%Y%m%d-${latest_sha:0:7})
73+
echo "version_tag=${date_tag}" >> "$GITHUB_OUTPUT"
74+
echo "latest_sha=${latest_sha}" >> "$GITHUB_OUTPUT"
75+
76+
- name: Set up Kind cluster
77+
uses: helm/kind-action@v1.8.0
78+
with:
79+
node_image: kindest/node:${{ env.KUBERNETES_VERSION }}
80+
cluster_name: tekton-nightly
81+
82+
- name: Set up Tekton
83+
uses: tektoncd/actions/setup-tektoncd@main
84+
with:
85+
pipeline_version: latest
86+
setup_registry: "true"
87+
patch_etc_hosts: "true"
88+
89+
- name: Configure Tekton Git Resolver
90+
env:
91+
GITHUB_TOKEN: ${{ secrets.GHCR_TOKEN || github.token }}
92+
run: |
93+
kubectl create secret generic git-resolver-secret \
94+
--from-literal=token="${GITHUB_TOKEN}" \
95+
-n tekton-pipelines-resolvers || true
96+
97+
kubectl patch configmap resolvers-feature-flags -n tekton-pipelines-resolvers --patch='
98+
data:
99+
enable-git-resolver: "true"
100+
enable-hub-resolver: "true"
101+
enable-bundles-resolver: "true"
102+
enable-cluster-resolver: "true"
103+
' || true
104+
105+
kubectl patch configmap git-resolver-config -n tekton-pipelines-resolvers --patch='
106+
data:
107+
default-url: "https://github.com"
108+
default-revision: "main"
109+
fetch-timeout: "1m"
110+
scm-type: "github"
111+
server-url: "https://api.github.com"
112+
api-token-secret-name: "git-resolver-secret"
113+
api-token-secret-key: "token"
114+
' || true
115+
116+
- name: Install tkn CLI
117+
uses: tektoncd/actions/setup-tektoncd-cli@main
118+
with:
119+
version: latest
120+
121+
- name: Apply Build Pipeline Definition
122+
run: |
123+
kubectl apply -f tekton/publish.yaml
124+
kubectl apply -f tekton/release-pipeline.yaml
125+
126+
- name: Create secrets and PVC template
127+
env:
128+
GCS_SERVICE_ACCOUNT_KEY: ${{ secrets.GCS_SERVICE_ACCOUNT_KEY }}
129+
GHCR_TOKEN: ${{ secrets.GHCR_TOKEN || github.token }}
130+
run: |
131+
echo "${GCS_SERVICE_ACCOUNT_KEY}" > /tmp/gcs-key.json
132+
kubectl create secret generic release-secret \
133+
--from-file=release.json=/tmp/gcs-key.json
134+
rm -f /tmp/gcs-key.json
135+
136+
kubectl create secret docker-registry ghcr-creds \
137+
--docker-server=ghcr.io \
138+
--docker-username=${{ github.actor }} \
139+
--docker-password="${GHCR_TOKEN}" \
140+
--docker-email=${{ github.actor }}@users.noreply.github.com
141+
142+
cat > workspace-template.yaml << EOF
143+
spec:
144+
accessModes:
145+
- ReadWriteOnce
146+
resources:
147+
requests:
148+
storage: 1Gi
149+
EOF
150+
151+
- name: Start Tekton Build Pipeline
152+
run: |
153+
set -euo pipefail # Exit on any error, undefined variables, or pipe failures
154+
155+
echo "Starting Tekton pipeline..."
156+
157+
PIPELINE_RUN=$(tkn pipeline start pipeline-release \
158+
--param package="${{ env.PACKAGE }}" \
159+
--param gitRevision="${{ steps.version.outputs.latest_sha }}" \
160+
--param versionTag="${{ steps.version.outputs.version_tag }}" \
161+
--param releaseBucket="${{ env.BUCKET }}" \
162+
--param imageRegistry=${{ env.REGISTRY }} \
163+
--param imageRegistryPath="${{ env.IMAGE_REGISTRY_PATH }}" \
164+
--param imageRegistryUser="${{ env.IMAGE_REGISTRY_USER }}" \
165+
--param imageRegistryRegions="" \
166+
--param buildPlatforms="linux/amd64" \
167+
--param publishPlatforms="linux/amd64" \
168+
--param koExtraArgs="" \
169+
--param serviceAccountPath=release.json \
170+
--param serviceAccountImagesPath=.dockerconfigjson \
171+
--param releaseAsLatest="false" \
172+
--param runTests="false" \
173+
--workspace name=workarea,volumeClaimTemplateFile=workspace-template.yaml \
174+
--workspace name=release-secret,secret=release-secret \
175+
--workspace name=release-images-secret,secret=ghcr-creds \
176+
--pipeline-timeout 2h \
177+
--output name) || {
178+
echo "Failed to start Tekton pipeline!"
179+
exit 1
180+
}
181+
182+
echo "Pipeline started: ${PIPELINE_RUN}"
183+
tkn pipelinerun logs "${PIPELINE_RUN}" -f
184+
185+
# Check if pipeline succeeded
186+
tkn pipelinerun describe "${PIPELINE_RUN}" --output jsonpath='{.status.conditions[?(@.type=="Succeeded")].status}' | grep -q "True" || {
187+
echo "Pipeline failed!"
188+
tkn pipelinerun describe "${PIPELINE_RUN}"
189+
exit 1
190+
}
191+
192+
echo "✅ Pipeline Run completed successfully!"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,4 @@ We are so excited to have you!
101101
- Look at our
102102
[good first issues](https://github.com/tektoncd/pipeline/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
103103
and our
104-
[help wanted issues](https://github.com/tektoncd/pipeline/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
104+
[help wanted issues](https://github.com/tektoncd/pipeline/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)

tekton/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ consumers of a project. In that case we'll make a patch release. To make one:
4646

4747
## Nightly releases
4848

49+
### Existing approach:
50+
4951
[The nightly release pipeline](release-pipeline.yaml) is
5052
[triggered nightly by Tekton](https://github.com/tektoncd/plumbing/tree/main/tekton).
5153

@@ -207,3 +209,57 @@ The image which we use for this is built from
207209

208210
_[go-containerregistry#383](https://github.com/google/go-containerregistry/issues/383)
209211
is about publishing a `ko` image, which hopefully we'll be able to move it._
212+
213+
### GitHub Action based approach:
214+
215+
The GitHub Actions workflow provides an alternative approach for automated nightly releases with enhanced CI/CD capabilities and better integration with GitHub infrastructure.
216+
217+
[The nightly release workflow](../.github/workflows/nightly-release.yaml) is triggered daily and uses:
218+
219+
- [release-nightly-pipeline.yaml](release-nightly-pipeline.yaml) - Tekton Pipeline for nightly releases
220+
- [publish-nightly.yaml](publish-nightly.yaml) - Tekton Task for building and publishing nightly images
221+
222+
#### Key Features:
223+
224+
**Automated Scheduling:**
225+
- Runs daily at 03:00 UTC via cron schedule
226+
- Supports manual triggering with customizable parameters
227+
- Intelligent change detection - only releases when there are recent commits (configurable)
228+
229+
**Multi-mode Operation:**
230+
- **Production mode**: For `tektoncd/pipeline` repository with full release capabilities
231+
- **Fork mode**: For testing in forks with isolated buckets and registries
232+
233+
#### Usage:
234+
235+
**Scheduled Release:**
236+
The workflow runs automatically every night and will create a release if:
237+
- There have been commits in the last 25 hours, OR
238+
- Force release is enabled, OR
239+
- It's manually triggered
240+
241+
**Manual Release:**
242+
```bash
243+
# Trigger via GitHub UI or CLI
244+
gh workflow run nightly-release.yaml \
245+
--field kubernetes_version=v1.33.0 \
246+
--field force_release=true \
247+
--field dry_run=false
248+
```
249+
250+
**Fork Testing:**
251+
For testing in forks, the workflow automatically:
252+
- Uses a test bucket pattern: `gs://tekton-releases-nightly-{repo-owner}`
253+
- Publishes to `ghcr.io/{owner}/pipeline/*` instead of production registry
254+
- Skips certain production-only validations
255+
256+
#### Output:
257+
258+
The workflow generates:
259+
- Container images tagged with `vYYYYMMDD-{sha7}` format
260+
- Release YAML manifests uploaded to GCS bucket
261+
- Multi-architecture image support
262+
- Comprehensive build logs and artifacts
263+
264+
This approach provides better observability, easier debugging, and more flexible configuration compared to the traditional Tekton-only pipeline approach.
265+

tekton/publish.yaml

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
apiVersion: tekton.dev/v1beta1
1+
apiVersion: tekton.dev/v1
22
kind: Task
33
metadata:
44
name: publish-release
@@ -16,15 +16,15 @@ spec:
1616
description: Extra args to be passed to ko
1717
default: "--preserve-import-paths"
1818
- name: versionTag
19-
description: The vX.Y.Z version that the artifacts should be tagged with (including `v`)
19+
description: Version tag (X.Y.Z for stable, vYYYYMMDD-abc1234 for nightly)
2020
- name: imageRegistry
2121
description: The target image registry
22-
default: gcr.io
22+
default: ghcr.io
2323
- name: imageRegistryPath
2424
description: The path (project) in the image registry
2525
- name: imageRegistryRegions
2626
description: The target image registry regions
27-
default: "us eu asia"
27+
default: ""
2828
- name: imageRegistryUser
2929
description: Username to be used to login to the container registry
3030
default: "_json_key"
@@ -41,9 +41,9 @@ spec:
4141
description: >-
4242
The workspace where the repo has been cloned. This should ideally
4343
be /go/src/$(params.package) however that is not possible today,
44-
see https://github.com/tektoncd/pipeline/issues/3786. To use this
45-
task on a fork of pipeline change the mountPath below
46-
mountPath: /go/src/github.com/tektoncd/pipeline
44+
see https://github.com/tektoncd/pipeline/issues/3786. For nightly builds
45+
on forks, we use a more generic mount path that works across repositories.
46+
mountPath: /go/src/repo
4747
- name: release-secret
4848
description: The secret that contains a service account authorized to push to the imageRegistry and to the output bucket
4949
- name: output
@@ -73,23 +73,57 @@ spec:
7373
steps:
7474

7575
- name: container-registry-auth
76-
image: cgr.dev/chainguard/crane:latest-dev@sha256:430c7813147443b59185d79ce7f5d682698a9fc3072f100850dc3a04100c1d91
76+
image: cgr.dev/chainguard/crane:latest-dev@sha256:68d9b984ee9cb5ff9cf7a779e8bdf3c2022f9042abfa1f0f5727a082a9429535
7777
script: |
7878
#!/bin/sh
7979
set -ex
8080
81-
# Login to the container registry
82-
DOCKER_CONFIG=$(cat ${CONTAINER_REGISTRY_CREDENTIALS} | \
83-
crane auth login -u ${CONTAINER_REGISTRY_USER} --password-stdin $(params.imageRegistry) 2>&1 | \
84-
sed -n 's,^.*logged in via \(.*\)$,\1,p')
81+
# For GHCR (GitHub Container Registry), handle authentication differently
82+
if [[ "$(params.imageRegistry)" == "ghcr.io" ]]; then
83+
echo "🔍 Configuring authentication for GitHub Container Registry"
8584
86-
# Auth with account credentials for all regions.
87-
for region in ${REGIONS}
88-
do
89-
HOSTNAME=${region}.$(params.imageRegistry)
90-
cat ${CONTAINER_REGISTRY_CREDENTIALS} | crane auth login -u ${CONTAINER_REGISTRY_USER} --password-stdin ${HOSTNAME}
91-
done
92-
cp ${DOCKER_CONFIG} /workspace/docker-config.json
85+
# For GHCR with Docker registry secrets, the secret structure is different
86+
# Check if we have a .dockerconfigjson file (from kubectl create secret docker-registry)
87+
if [[ -f "$(workspaces.release-secret.path)/.dockerconfigjson" ]]; then
88+
echo "Using Docker registry secret format"
89+
cp "$(workspaces.release-secret.path)/.dockerconfigjson" /workspace/docker-config.json
90+
elif [[ -f "${CONTAINER_REGISTRY_CREDENTIALS}" ]]; then
91+
# Check if it's a docker config.json or a simple token
92+
if cat ${CONTAINER_REGISTRY_CREDENTIALS} | jq -r '.auths // empty' >/dev/null 2>&1; then
93+
# It's a docker config.json, copy it directly
94+
echo "Using docker config.json format"
95+
cp ${CONTAINER_REGISTRY_CREDENTIALS} /workspace/docker-config.json
96+
else
97+
# It's a simple token, create docker config
98+
echo "Using token-based authentication"
99+
TOKEN=$(cat ${CONTAINER_REGISTRY_CREDENTIALS})
100+
101+
# Create docker config for GHCR
102+
mkdir -p ~/.docker
103+
echo '{"auths":{"ghcr.io":{"auth":"'$(echo -n "${CONTAINER_REGISTRY_USER}:${TOKEN}" | base64 -w 0)'"}}}' > ~/.docker/config.json
104+
cp ~/.docker/config.json /workspace/docker-config.json
105+
fi
106+
else
107+
echo "Credentials file not found: ${CONTAINER_REGISTRY_CREDENTIALS}"
108+
exit 1
109+
fi
110+
else
111+
# Original GCR authentication logic
112+
echo "🔍 Configuring authentication for GCR/other registries"
113+
114+
# Login to the container registry
115+
DOCKER_CONFIG=$(cat ${CONTAINER_REGISTRY_CREDENTIALS} | \
116+
crane auth login -u ${CONTAINER_REGISTRY_USER} --password-stdin $(params.imageRegistry) 2>&1 | \
117+
sed -n 's,^.*logged in via \(.*\)$,\1,p')
118+
119+
# Auth with account credentials for all regions.
120+
for region in ${REGIONS}
121+
do
122+
HOSTNAME=${region}.$(params.imageRegistry)
123+
cat ${CONTAINER_REGISTRY_CREDENTIALS} | crane auth login -u ${CONTAINER_REGISTRY_USER} --password-stdin ${HOSTNAME}
124+
done
125+
cp ${DOCKER_CONFIG} /workspace/docker-config.json
126+
fi
93127
94128
- name: create-ko-yaml
95129
image: cgr.dev/chainguard/go:latest-dev@sha256:8e2632f8725d1a48d6f97a13c71e1594fe17dc9c0e7d00543091a04ac82e429b
@@ -146,6 +180,10 @@ spec:
146180
#!/usr/bin/env sh
147181
set -ex
148182
183+
# Fix Git ownership issue for the repository directory
184+
git config --global --add safe.directory /go/src/repo
185+
git config --global --add safe.directory ${PROJECT_ROOT}
186+
149187
# Use the generated `.ko.yaml`
150188
export KO_CONFIG_PATH=/workspace
151189
cat ${KO_CONFIG_PATH}/.ko.yaml
@@ -273,4 +311,4 @@ spec:
273311
# regional copies of the images in the result - see https://github.com/tektoncd/pipeline/issues/4282
274312
# echo ${REGION}.$IMAGE_WITH_SHA, >> $(results.IMAGES.path)
275313
done
276-
done
314+
done

0 commit comments

Comments
 (0)