Files
thatguygriffandClaude Opus 4.8 4bca2fbc96
CI / Tests (PHP 8.1) (pull_request) Successful in 49s
CI / Tests (PHP 8.2) (pull_request) Successful in 48s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 7m54s
CI / PHPStan (pull_request) Successful in 9m2s
CI / Coding Standards (pull_request) Successful in 9m12s
CI / Build Plugin Zip (pull_request) Skipped
Add CHANGELOG and publish it as release notes; auto-open next-version bump PR
Add CHANGELOG.md (one section per version, newest first; the top section
always reflects the current plugin header version — release status is
purely a matter of tagging).

The Release workflow now extracts the tagged version's changelog section
and publishes it as the Gitea release body (POST on create, PATCH when the
release was pre-created via the UI). After a stable release, a new
bump-version job bumps the plugin to the next patch version, opens a fresh
changelog section, and opens a PR. Pre-release tags are skipped.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-23 16:34:52 -03:00

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