Skip to content

tekton: automate releases with Pipelines-as-Code#1656

Open
ab-ghosh wants to merge 1 commit into
tektoncd:mainfrom
ab-ghosh:automate-release
Open

tekton: automate releases with Pipelines-as-Code#1656
ab-ghosh wants to merge 1 commit into
tektoncd:mainfrom
ab-ghosh:automate-release

Conversation

@ab-ghosh
Copy link
Copy Markdown
Member

@ab-ghosh ab-ghosh commented May 8, 2026

Changes

Automate releases using Pipelines-as-Code instead of manual tkn pipeline start commands.

What's included

  • .tekton/release.yaml — Initial release PipelineRun, triggered automatically when a release-v* branch is created. Version derived from branch name via CEL (release-v0.27.xv0.27.0).
  • .tekton/release-patch.yaml — Patch release PipelineRun, triggered via PAC incoming webhook. Version and releaseAsLatest passed dynamically.
  • .github/workflows/patch-release.yaml — GitHub Actions workflow with two modes:
    • workflow_dispatch: manual trigger with branch/version inputs
    • schedule: weekly cron (Thursday 10:00 UTC) scanning for unreleased commits on release branches ≥ v0.20
  • Updated release/README.md — reflects the new automated workflow, with manual tkn command preserved as a fallback section.

Dependencies

  • PAC deployed to oci-ci-cd cluster (tektoncd/plumbing#3256)
  • PAC Repository CR for tektoncd/chains (tektoncd/plumbing#3358)
  • Release secrets provisioned in releases-chains namespace (tektoncd/infra)
  • GitHub App tekton-as-code installed on this repo
  • PAC_INCOMING_SECRET GitHub Actions secret configured

See tektoncd/plumbing#58 for the
full automated release plan.

/kind feature

Submitter Checklist

As the author of this PR, please check off the items in this checklist:

  • Has Docs included if any changes are user facing
  • Has Tests included if any functionality added or changed
  • Follows the commit message standard
  • Meets the Tekton contributor standards (including
    functionality, content, code)
  • Release notes block below has been updated with any user facing changes (API changes, bug fixes, changes requiring upgrade notices or deprecation warnings)
  • Release notes contains the string "action required" if the change requires additional action from users switching to the new release

Release Notes

NONE

Jira: SRVKP-11937

Signed-off-by: ab-ghosh <abghosh@redhat.com>
@tekton-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
To complete the pull request process, please assign wlynch after the PR has been reviewed.
You can assign the PR to them by writing /assign @wlynch in a comment when ready.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@tekton-robot tekton-robot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label May 8, 2026
steps:
- name: Validate inputs
run: |
if [[ ! "${{ inputs.branch }}" =~ ^release-v[0-9]+\.[0-9]+\.x$ ]]; then
- name: Validate inputs
run: |
if [[ ! "${{ inputs.branch }}" =~ ^release-v[0-9]+\.[0-9]+\.x$ ]]; then
echo "::error::Invalid branch format: ${{ inputs.branch }}. Expected: release-vX.Y.x"
echo "::error::Invalid branch format: ${{ inputs.branch }}. Expected: release-vX.Y.x"
exit 1
fi
if [[ ! "${{ inputs.version }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
exit 1
fi
if [[ ! "${{ inputs.version }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid version format: ${{ inputs.version }}. Expected: vX.Y.Z"
env:
PAC_INCOMING_SECRET: ${{ secrets.PAC_INCOMING_SECRET }}
run: |
echo "::notice::Triggering release ${{ inputs.version }} on ${{ inputs.branch }} (latest=${{ inputs.release_as_latest }})"
-H "Content-Type: application/json" \
-d '{
"repository": "'"${PAC_REPOSITORY_NAME}"'",
"branch": "${{ inputs.branch }}",
"pipelinerun": "release-patch",
"secret": "'"${PAC_INCOMING_SECRET}"'",
"params": {
"version": "${{ inputs.version }}",
Comment on lines +30 to +113
scan-release-branches:
name: Scan for unreleased commits
if: github.event_name == 'schedule' && github.repository_owner == 'tektoncd'
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.scan.outputs.matrix }}
has_releases: ${{ steps.scan.outputs.has_releases }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

- name: Scan release branches for new commits
id: scan
run: |
# Determine which release branch is the latest (highest version)
latest_branch=""
latest_major=0
latest_minor=0
for ref in $(git branch -r --list 'origin/release-v*'); do
branch="${ref#origin/}"
if [[ "$branch" =~ release-v([0-9]+)\.([0-9]+)\.x ]]; then
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
if [ "$major" -gt "$latest_major" ] || { [ "$major" -eq "$latest_major" ] && [ "$minor" -gt "$latest_minor" ]; }; then
latest_major=$major
latest_minor=$minor
latest_branch=$branch
fi
fi
done
echo "::notice::Latest release branch: ${latest_branch}"

MIN_MAJOR="${MIN_RELEASE_VERSION%%.*}"
MIN_MINOR="${MIN_RELEASE_VERSION##*.}"

releases=()
for ref in $(git branch -r --list 'origin/release-v*'); do
branch="${ref#origin/}"

# Skip branches older than MIN_RELEASE_VERSION
if [[ "$branch" =~ release-v([0-9]+)\.([0-9]+)\.x ]]; then
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
if [ "$major" -lt "$MIN_MAJOR" ] || { [ "$major" -eq "$MIN_MAJOR" ] && [ "$minor" -lt "$MIN_MINOR" ]; }; then
echo "::notice::Branch ${branch} is older than v${MIN_RELEASE_VERSION} — skipping"
continue
fi
fi

# Find the latest tag on this branch
last_tag=$(git describe --tags --abbrev=0 --match 'v*' "$ref" 2>/dev/null || echo "")
if [ -z "$last_tag" ]; then
echo "::notice::Branch ${branch} has no tags — skipping (initial release handled by branch creation)"
continue
fi

# Count commits since last tag
new_commits=$(git rev-list "${last_tag}..${ref}" --count)
if [ "$new_commits" -eq 0 ]; then
echo "::notice::Branch ${branch} has no new commits since ${last_tag}"
continue
fi

# Calculate next patch version: v0.26.3 → v0.26.4
next_version=$(echo "$last_tag" | awk -F. '{printf "%s.%s.%d", $1, $2, $3+1}')

# Only the latest release branch publishes as latest
is_latest="false"
if [ "$branch" = "$latest_branch" ]; then
is_latest="true"
fi

echo "::notice::Branch ${branch}: ${new_commits} new commits since ${last_tag} → ${next_version} (latest=${is_latest})"
releases+=("{\"branch\":\"${branch}\",\"version\":\"${next_version}\",\"release_as_latest\":\"${is_latest}\"}")
done

if [ ${#releases[@]} -eq 0 ]; then
echo "matrix=[]" >> "$GITHUB_OUTPUT"
echo "has_releases=false" >> "$GITHUB_OUTPUT"
else
echo "matrix=[$(IFS=,; echo "${releases[*]}")]" >> "$GITHUB_OUTPUT"
echo "has_releases=true" >> "$GITHUB_OUTPUT"
fi
Comment on lines +115 to +142
trigger-scanned-releases:
name: "Trigger ${{ matrix.release.version }} (${{ matrix.release.branch }})"
needs: scan-release-branches
if: needs.scan-release-branches.outputs.has_releases == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
release: ${{ fromJson(needs.scan-release-branches.outputs.matrix) }}
max-parallel: 1
steps:
- name: Trigger PAC incoming webhook
env:
PAC_INCOMING_SECRET: ${{ secrets.PAC_INCOMING_SECRET }}
run: |
echo "::notice::Triggering release ${{ matrix.release.version }} on ${{ matrix.release.branch }} (latest=${{ matrix.release.release_as_latest }})"
curl -sf -X POST "${PAC_CONTROLLER_URL}/incoming" \
-H "Content-Type: application/json" \
-d '{
"repository": "'"${PAC_REPOSITORY_NAME}"'",
"branch": "${{ matrix.release.branch }}",
"pipelinerun": "release-patch",
"secret": "'"${PAC_INCOMING_SECRET}"'",
"params": {
"version": "${{ matrix.release.version }}",
"release_as_latest": "${{ matrix.release.release_as_latest }}"
}
}'
echo "Release triggered successfully"
Comment on lines +38 to +40
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants