Patch Release #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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" |