Files
unsupervised-scheduler/.gitea/workflows/release.yml
T
thatguygriffandClaude Opus 5 1291af0b72
CI / PHPStan (pull_request) Successful in 6m52s
CI / Tests (PHP 8.1) (pull_request) Successful in 6m0s
CI / Tests (PHP 8.2) (pull_request) Successful in 1m11s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m55s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 7m6s
CI / Build Plugin Zip (pull_request) Skipped
Authenticate setup-php against the GitHub API
setup-php resolves its tools through the GitHub API, unauthenticated at 60
requests an hour per source address. A CI fan-out across the fleet exhausts
that bucket, and the step then retries for several minutes before reporting
only "Could not setup PHP 8.3". It reads as a hang rather than a throttle,
and it took out both a main CI run and a release build.

Each cluster has its own egress address and so its own bucket, which is why
the same job passed on one runner and failed on another in the same minute.

The token comes from 1Password through the Connect instance in whichever
cluster picked up the job, matching the pattern in thatguygriff/infra. That
repository's composite action is not reachable from here, so it is mirrored
locally. It stays a step output rather than being exported to the job
environment, to keep it away from the package scripts composer install runs.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0133tYSQoZhoKebKZV8o2GPs
2026-08-20 13:27:22 -03:00

181 lines
7.6 KiB
YAML

name: Release
# Fires when a v* tag is pushed — including tags created through Gitea's
# "New Release" UI. Builds the distributable plugin zip and attaches it to
# the release for that tag (creating the release if only a bare tag was
# pushed). The attached zip is what UpdateChecker serves to WordPress
# sites as the update package.
on:
push:
tags:
- 'v*'
jobs:
release:
name: Build and Publish Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# setup-php resolves its tools through the GitHub API, which allows 60
# requests an hour per source address unauthenticated. A CI fan-out across
# the fleet exhausts that, and the step then retries for minutes before
# reporting only "Could not setup PHP".
- name: Load GitHub API token
id: gh-token
uses: ./.gitea/actions/op-github-token
with:
connect-host: ${{ vars.OP_CONNECT_HOST }}
op-connect-token-eris: ${{ secrets.OP_CONNECT_TOKEN_ERIS }}
op-connect-token-kallone: ${{ secrets.OP_CONNECT_TOKEN_KALLONE }}
op-connect-token-nemesis: ${{ secrets.OP_CONNECT_TOKEN_NEMESIS }}
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
tools: composer:v2
env:
GITHUB_TOKEN: ${{ steps.gh-token.outputs.token }}
# A tag that disagrees with the plugin header would make sites see a
# phantom update forever (or never see a real one), so fail fast.
- name: Verify tag matches plugin version
id: meta
run: |
tag_version="${GITHUB_REF_NAME#v}"
header_version="$(sed -nE 's/^[[:space:]]*\*?[[:space:]]*Version:[[:space:]]*([^[:space:]]+).*/\1/p' unsupervised-schedular.php | head -1)"
if [ "$tag_version" != "$header_version" ]; then
echo "Tag ${GITHUB_REF_NAME} does not match plugin header Version: ${header_version}" >&2
exit 1
fi
echo "version=${header_version}" >> "$GITHUB_OUTPUT"
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: Run tests
run: composer test
- name: Build plugin zip
run: composer build
# Pull the section for this version out of CHANGELOG.md so it can become
# the release body. Matches "## [x.y.z]" and prints every line up to the
# next "## " heading. A missing section is a warning, not a failure — the
# release still publishes with empty notes.
- name: Extract changelog notes
run: |
version="${{ steps.meta.outputs.version }}"
awk -v ver="$version" '
$0 ~ "^## \\[" ver "\\]" { found = 1; next }
found && /^## / { exit }
found { print }
' CHANGELOG.md | sed -e '/./,$!d' | tac | sed -e '/./,$!d' | tac > release-notes.md
if [ ! -s release-notes.md ]; then
echo "::warning::No CHANGELOG.md section found for version ${version}"
fi
- name: Publish release with zip asset
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
api="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
version="${{ steps.meta.outputs.version }}"
zip="dist/unsupervised-schedular-${version}.zip"
# Pre-release versions (1.2.3-rc.1) are flagged so Gitea's
# /releases/latest endpoint — and therefore the update checker —
# skips them.
prerelease=false
case "$version" in *-*) prerelease=true ;; esac
# Reuse the release if the tag was created via Gitea's release UI.
release_id="$(curl -sS -H "Authorization: token ${TOKEN}" \
"${api}/releases/tags/${GITHUB_REF_NAME}" | jq -r '.id // empty' || true)"
if [ -z "$release_id" ]; then
body="$(jq -Rs --arg tag "${GITHUB_REF_NAME}" --argjson pre "${prerelease}" \
'{tag_name:$tag, name:$tag, prerelease:$pre, body:.}' release-notes.md)"
release_id="$(curl -fsS -X POST "${api}/releases" \
-H "Authorization: token ${TOKEN}" \
-H 'Content-Type: application/json' \
-d "${body}" | jq -r '.id')"
else
# Release pre-created via the UI: fill in the notes from the changelog.
body="$(jq -Rs '{body:.}' release-notes.md)"
curl -fsS -X PATCH "${api}/releases/${release_id}" \
-H "Authorization: token ${TOKEN}" \
-H 'Content-Type: application/json' \
-d "${body}" > /dev/null
fi
echo "Attaching ${zip} to release ${release_id}"
curl -fsS -X POST \
"${api}/releases/${release_id}/assets?name=unsupervised-schedular-${version}.zip" \
-H "Authorization: token ${TOKEN}" \
-F "attachment=@${zip}" > /dev/null
# After a stable release, move main forward: bump the plugin to the next patch
# version and open a fresh changelog section for it, via a PR. Skipped for
# pre-releases (tags containing a hyphen, e.g. v1.2.0-rc.1) — those don't
# advance the mainline version.
bump-version:
name: Open next-version bump PR
needs: release
if: ${{ !contains(github.ref_name, '-') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Compute next patch version
id: next
run: |
current="$(sed -nE 's/^[[:space:]]*\*?[[:space:]]*Version:[[:space:]]*([^[:space:]]+).*/\1/p' unsupervised-schedular.php | head -1)"
base="${current%%-*}" # drop any pre-release suffix
major="${base%%.*}"
rest="${base#*.}"
minor="${rest%%.*}"
patch="${rest#*.}"
next="${major}.${minor}.$((patch + 1))"
echo "next=${next}" >> "$GITHUB_OUTPUT"
- name: Apply version bump and open changelog section
run: |
next="${{ steps.next.outputs.next }}"
# Plugin header + USC_VERSION constant must stay in lockstep.
sed -i -E "s/^([[:space:]]*\*?[[:space:]]*Version:[[:space:]]*).*/\1${next}/" unsupervised-schedular.php
sed -i -E "s/(define\('USC_VERSION', ')[^']+('\);)/\1${next}\2/" unsupervised-schedular.php
# Insert an empty section for the new version above the current top one
# (the first "## [" heading in the file).
awk -v ver="$next" '
!done && /^## \[/ { print "## [" ver "]"; print ""; done = 1 }
{ print }
' CHANGELOG.md > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
- name: Open pull request
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
next="${{ steps.next.outputs.next }}"
branch="release/bump-${next}"
api="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
git config user.name 'Release Bot'
git config user.email '[email protected]'
git checkout -b "${branch}"
git commit -am "Bump version to ${next} and open changelog section"
git push origin "${branch}"
curl -fsS -X POST "${api}/pulls" \
-H "Authorization: token ${TOKEN}" \
-H 'Content-Type: application/json' \
-d "$(jq -n --arg head "${branch}" --arg title "Bump version to ${next}" \
'{head:$head, base:"main", title:$title, body:"Automated post-release bump to the next patch version. Record changes for this version under its changelog heading."}')" \
> /dev/null