Skip to content

Patch Release

Patch Release #13

name: Patch Release
"on":
workflow_dispatch:
inputs:
branch:
description: "Release branch (e.g. release-v0.3.x)"
required: true
type: string
version:
description: "Version to release (e.g. v0.3.6)"
required: true
type: string
release_as_latest:
description: "Publish as latest release"
required: false
type: boolean
default: true
schedule:
# Weekly on Thursday at 10:00 UTC
- cron: "0 10 * * 4"
permissions:
contents: read
env:
PAC_CONTROLLER_URL: "https://pac.infra.tekton.dev"
PAC_REPOSITORY_NAME: "tektoncd-pruner"
# Ignore release branches older than this (major.minor)
MIN_RELEASE_VERSION: "0.3"
jobs:
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- 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.3.5 → v0.3.6
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
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"
trigger-manual-release:
name: "Trigger ${{ inputs.version }} (${{ inputs.branch }})"
if: github.event_name == 'workflow_dispatch' && github.repository_owner == 'tektoncd'
runs-on: ubuntu-latest
steps:
- name: Validate inputs
env:
BRANCH: ${{ inputs.branch }}
VERSION: ${{ inputs.version }}
run: |
if [[ ! "${BRANCH}" =~ ^release-v[0-9]+\.[0-9]+\.x$ ]]; then
echo "::error::Invalid branch format: ${BRANCH}. Expected: release-vX.Y.x"
exit 1
fi
if [[ ! "${VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid version format: ${VERSION}. Expected: vX.Y.Z"
exit 1
fi
- name: Trigger PAC incoming webhook
env:
PAC_INCOMING_SECRET: ${{ secrets.PAC_INCOMING_SECRET }}
BRANCH: ${{ inputs.branch }}
VERSION: ${{ inputs.version }}
RELEASE_AS_LATEST: ${{ inputs.release_as_latest }}
run: |
echo "::notice::Triggering release ${VERSION} on ${BRANCH} (latest=${RELEASE_AS_LATEST})"
curl -sf -X POST "${PAC_CONTROLLER_URL}/incoming" \
-H "Content-Type: application/json" \
-d '{
"repository": "'"${PAC_REPOSITORY_NAME}"'",
"branch": "'"${BRANCH}"'",
"pipelinerun": "release-patch",
"secret": "'"${PAC_INCOMING_SECRET}"'",
"params": {
"version": "'"${VERSION}"'",
"release_as_latest": "'"${RELEASE_AS_LATEST}"'"
}
}'
echo "Release triggered successfully"