CI / Coding Standards & Static Analysis (pull_request) Successful in 37s
CI / Tests (PHP 8.1) (pull_request) Successful in 21s
CI / Tests (PHP 8.2) (pull_request) Successful in 20s
CI / Tests (PHP 8.3) (pull_request) Successful in 19s
CI / Tests (PHP 8.5) (pull_request) Successful in 19s
CI / No Debug Code (pull_request) Successful in 2s
CI / Build Plugin Zip (pull_request) Skipped
Replaces setup-php with `container:` in every job that needs PHP. The images published by ci-images.yml already carry PHP, Composer, the intl and zip extensions and the CLI tools the workflow scripts shell out to, so nothing installs PHP at job time any more. That removes the apt path #178 was about: a ~145s floor on 8.3 against ~35s on 8.1/8.2, with a tail that twice ran past the step timeout and failed the run. All three copies of the `Keep downloaded .debs` / `Cache apt packages` workaround go with it. no-debug and bump-version stay on the runner image — neither needs PHP, and no-debug wants the runner's GNU `grep --include`. The Composer cache moves to /composer/cache, which is COMPOSER_HOME in the image, and release.yml gains the cache step it never had. Also corrects the image size in docs/ci.md to the 67MB measured from the published manifest; the ~120MB in the original was an estimate. Closes #187 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
172 lines
7.2 KiB
YAML
172 lines
7.2 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
|
|
# Runs in the prebuilt CI image rather than installing PHP — see
|
|
# docs/ci.md and #187. The image carries composer, jq, curl and GNU
|
|
# coreutils, which is everything the steps below shell out to.
|
|
container:
|
|
image: git.unsupervised.ca/unsupervised/ci-php:8.3
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
# 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"
|
|
|
|
# COMPOSER_HOME is /composer in the CI image.
|
|
- name: Cache Composer packages
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: /composer/cache
|
|
key: composer-${{ hashFiles('composer.json') }}
|
|
|
|
- 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
|