diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 05a30eb..ff7e6b9 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -46,6 +46,22 @@ jobs: - 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 }} @@ -65,11 +81,19 @@ jobs: "${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 "{\"tag_name\":\"${GITHUB_REF_NAME}\",\"name\":\"${GITHUB_REF_NAME}\",\"prerelease\":${prerelease}}" \ - | jq -r '.id')" + -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}" @@ -77,3 +101,65 @@ jobs: "${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 'release-bot@unsupervised.ca' + 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 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..52ac43e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,30 @@ +# Changelog + +All notable changes to Unsupervised Scheduler are documented in this file, one +section per version, newest first. The top section is always the version the code +on `main` currently carries (the `Version:` header in `unsupervised-schedular.php`). +Whether a version is "released" is purely a matter of whether its tag exists — the +changelog itself does not track that. + +When a `v*` tag is pushed, `.gitea/workflows/release.yml` publishes the matching +`## [x.y.z]` section verbatim as the Gitea release notes, then opens a PR that bumps +the plugin to the next patch version and adds a fresh section here for it. Record +each change under the current top section as you work. + +## [1.1.0] + +### Added +- Invite-only group classes, so a class can be restricted to students who hold an invite. +- Instructor group-class roster view under **My Lessons**. +- Cancellation cutoff that limits how close to a lesson a student can cancel. +- Studio-defined account-registration questions collected during student sign-up. + +### Changed +- Plugin metadata links now point at Unsupervised and the Gitea repository. + +## [1.0.0] + +First stable release: instructor/student lesson scheduling for WordPress, including +availability management, one-on-one and group-class booking, Stripe payments, student +self-registration with email confirmation and admin approval, group invite links, and +self-update from tagged Gitea releases.