CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.1) (pull_request) Successful in 56s
CI / Tests (PHP 8.2) (pull_request) Successful in 57s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m56s
CI / Coding Standards (pull_request) Successful in 7m5s
CI / Build Plugin Zip (pull_request) Skipped
CI / PHPStan (pull_request) Successful in 8m5s
The GitHub API rate limit was the wrong diagnosis, so this reverts the 1Password-backed token added in #175 along with the mirrored composite action, leaving the workflows as they were. Timing every Setup PHP step across runs 454-523 rules the rate limit out. PHP 8.1 and 8.2 install in 26-41 seconds, 12 for 12, never once failing. PHP 8.3 has never finished in under 143 seconds and ranges up to 1273, with two outright failures. Those jobs share a fan-out, and so an egress address and a rate limit bucket, with the 8.1 and 8.2 jobs that are never touched. A throttle could not sort itself by PHP version that way. Run 523, the first to carry the token, is the direct refutation: the token resolved and verified, and Setup PHP still took 749 seconds on kallone and 408 on eris. The 8.3 penalty also predates the whole story, sitting at ~145 seconds back on 30 July. What is left is a slow path specific to 8.3 on these arm64 runners, whose long tail sometimes crosses the step timeout and reports the unhelpful "Could not setup PHP 8.3". That is worth fixing on its own terms rather than behind a token that was never in the path. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Uw545F1vveNJKjzLxdi2ks
166 lines
6.8 KiB
YAML
166 lines
6.8 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
|
|
|
|
- name: Setup PHP
|
|
uses: shivammathur/setup-php@v2
|
|
with:
|
|
php-version: '8.3'
|
|
tools: composer:v2
|
|
|
|
# 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
|