diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml new file mode 100644 index 0000000..3b5a9bf --- /dev/null +++ b/.github/workflows/auto-release.yml @@ -0,0 +1,71 @@ +name: Auto Release + +# When a version bump lands on main, read the top CHANGELOG version and, if it +# has no matching tag yet, create the tag `vX.Y.Z` and call release.yml to build +# + publish it. No PAT needed — release.yml is invoked via workflow_call because +# the default token cannot let a tag push trigger another workflow. + +"on": + push: + branches: + - main + paths: + - CHANGELOG.md # only a version bump can start a release + +permissions: + contents: write + +concurrency: + group: auto-release + cancel-in-progress: false + +jobs: + detect: + name: Detect new version + runs-on: ubuntu-latest + outputs: + release: ${{ steps.ver.outputs.release }} + version: ${{ steps.ver.outputs.version }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # need all tags + + - name: Read top CHANGELOG version + id: ver + run: | + # First "## [x.y.z]" heading — skips "## [Unreleased]". + VERSION="$(grep -m1 -oE '^## \[[0-9]+\.[0-9]+\.[0-9]+\]' CHANGELOG.md | tr -d '## []')" + if [ -z "$VERSION" ]; then + echo "No versioned CHANGELOG entry found — nothing to release." + echo "release=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + if git rev-parse "v$VERSION" >/dev/null 2>&1; then + echo "Tag v$VERSION already exists — skipping." + echo "release=false" >> "$GITHUB_OUTPUT" + else + echo "New version detected: v$VERSION" + echo "release=true" >> "$GITHUB_OUTPUT" + fi + + - name: Create and push tag + if: steps.ver.outputs.release == 'true' + env: + VERSION: ${{ steps.ver.outputs.version }} + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "v$VERSION" -m "Release v$VERSION" + git push origin "v$VERSION" + + release: + name: Build & publish + needs: detect + if: needs.detect.outputs.release == 'true' + uses: ./.github/workflows/release.yml + permissions: + contents: write + with: + version: ${{ needs.detect.outputs.version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f0e73f..8baff4b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,21 @@ name: Release +# Publishes a GitHub Release. Two entry points: +# • a pushed tag `v*` — manual escape hatch +# • workflow_call(version) — invoked by auto-release.yml on merge to main +# (the default token cannot let a tag push trigger this workflow, so the +# auto-release path calls it directly). + on: push: tags: - 'v*' + workflow_call: + inputs: + version: + description: 'Release version without the leading v (e.g. 1.2.0)' + required: true + type: string permissions: contents: write @@ -34,11 +46,24 @@ jobs: - uses: actions/checkout@v7 with: fetch-depth: 0 - - name: Create release + - name: Resolve tag + id: tag + run: | + if [ -n "${{ inputs.version }}" ]; then + echo "tag=v${{ inputs.version }}" >> "$GITHUB_OUTPUT" + else + echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" + fi + - name: Create release (idempotent) env: GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.tag.outputs.tag }} run: | - gh release create "${GITHUB_REF_NAME}" \ - --title "${GITHUB_REF_NAME}" \ + if gh release view "$TAG" >/dev/null 2>&1; then + echo "Release $TAG already exists — nothing to do." + exit 0 + fi + gh release create "$TAG" \ + --title "$TAG" \ --generate-notes \ --verify-tag diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ee22a4..1845e5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.0.0] - 2026-07-22 + ### Added - Initial extraction of the PhpServicePlatform kernel HTTP layer into a standalone,