Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 14 additions & 159 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# Continuous release pipeline for Data Machine.
#
# Triggers on push to main (immediate release) and manual dispatch.
# Checks for releasable conventional commits since the last tag. If found:
# 1. Version bump + changelog generation
# 2. Tag + push + GitHub Release creation
# 3. WordPress release.package builds the vendor-bundled ZIP
# 4. WordPress release.publish uploads the ZIP to the Release and
# mirrors the tree to the release-latest branch (Playground CORS path)
# Triggers on push to main (immediate release) and manual dispatch. The whole
# pipeline — releasable-commit detection, dry-run version prediction,
# failed-SHA retry protection, GitHub App token, version bump, changelog,
# tag, GitHub Release, and the WordPress release.package / release.publish
# steps — is owned by the reusable Homeboy Action release workflow.
#
# No human input needed — version is computed from commit types:
# fix: → patch, feat: → minor, BREAKING CHANGE → major
Expand All @@ -29,157 +27,14 @@ on:
type: boolean
default: false

jobs:
# ── Step 1: Check for releasable commits ──
check:
name: Check for releasable commits
if: ${{ github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'release:') }}
runs-on: ubuntu-latest
outputs:
should-release: ${{ steps.check.outputs.should-release }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Restore failure cache
id: failure-cache
uses: actions/cache/restore@v5
with:
path: ${{ runner.temp }}/homeboy-release-last-failed
key: release-last-failed-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
release-last-failed-${{ github.ref_name }}-

- name: Check failed release marker
id: failed-release
run: |
HEAD_SHA="$(git rev-parse HEAD)"
FAILURE_MARKER="${RUNNER_TEMP}/homeboy-release-last-failed"
if [ -f "${FAILURE_MARKER}" ]; then
LAST_FAILED="$(tr -d '[:space:]' < "${FAILURE_MARKER}")"
if [ "${HEAD_SHA}" = "${LAST_FAILED}" ]; then
echo "::notice::HEAD ${HEAD_SHA:0:8} matches last failed release attempt — skipping until new commits"
echo "blocked=true" >> "$GITHUB_OUTPUT"
exit 0
fi
fi

echo "blocked=false" >> "$GITHUB_OUTPUT"

- name: Check for releasable commit messages
id: commit-check
if: steps.failed-release.outputs.blocked != 'true'
run: |
LAST_TAG="$(git describe --tags --match 'v[0-9]*' --abbrev=0 2>/dev/null || true)"
if [ -n "${LAST_TAG}" ]; then
RANGE="${LAST_TAG}..HEAD"
else
RANGE="HEAD"
fi

if git log --format=%B "${RANGE}" | grep -Eq '^(feat|fix)(\([^)]+\))?!?:|^BREAKING CHANGE:'; then
echo "could-release=true" >> "$GITHUB_OUTPUT"
else
echo "::notice::No releasable conventional commits in ${RANGE}"
echo "could-release=false" >> "$GITHUB_OUTPUT"
fi

- name: Dry-run release check
id: release-check
if: steps.commit-check.outputs.could-release == 'true'
uses: Extra-Chill/homeboy-action@v2
with:
commands: release
args: '--setting database_type=mysql --setting wp_codebox_phpunit_config=/wordpress/wp-content/plugins/data-machine/phpunit.xml.dist'
release-dry-run: 'true'

- name: Decide whether to release
id: check
run: |
HEAD_SHA="$(git rev-parse HEAD)"
if [ "${{ steps.failed-release.outputs.blocked }}" = "true" ]; then
echo "should-release=false" >> "$GITHUB_OUTPUT"
exit 0
fi

if [ "${{ steps.commit-check.outputs.could-release }}" != "true" ]; then
echo "should-release=false" >> "$GITHUB_OUTPUT"
echo "::notice::No releasable commits at HEAD ${HEAD_SHA:0:8}"
exit 0
fi
concurrency:
group: release
cancel-in-progress: false

RELEASE_VERSION="${{ steps.release-check.outputs.release-version }}"
BUMP_TYPE="${{ steps.release-check.outputs.release-bump-type }}"

if [ -z "${RELEASE_VERSION}" ]; then
echo "should-release=false" >> "$GITHUB_OUTPUT"
echo "::notice::No releasable commits at HEAD ${HEAD_SHA:0:8}"
else
echo "should-release=true" >> "$GITHUB_OUTPUT"
echo "::notice::Release dry-run predicts v${RELEASE_VERSION} (${BUMP_TYPE})"
fi

# ── Step 2: Release ──
jobs:
release:
name: Release
needs: check
if: needs.check.outputs.should-release == 'true'
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v3
continue-on-error: true
with:
app-id: ${{ secrets.HOMEBOY_APP_ID }}
private-key: ${{ secrets.HOMEBOY_APP_PRIVATE_KEY }}

- uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: false
token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}

- uses: Extra-Chill/homeboy-action@v2
id: release
with:
commands: release
args: '--setting database_type=mysql --setting wp_codebox_phpunit_config=/wordpress/wp-content/plugins/data-machine/phpunit.xml.dist'
release-dry-run: ${{ inputs.dry-run || 'false' }}
app-token: ${{ steps.app-token.outputs.token || '' }}

# ── Record failed SHA to prevent retry loops ──
record-failure:
name: Record failure
needs:
- check
- release
if: ${{ always() && needs.check.outputs.should-release == 'true' && needs.release.result == 'failure' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Save failed SHA
run: git rev-parse HEAD > "${RUNNER_TEMP}/homeboy-release-last-failed"

- name: Cache failed SHA
uses: actions/cache/save@v5
with:
path: ${{ runner.temp }}/homeboy-release-last-failed
key: release-last-failed-${{ github.ref_name }}-${{ github.sha }}

# ── Clear failure cache on success ──
clear-failure:
name: Clear failure cache
needs: release
if: ${{ needs.release.result == 'success' }}
runs-on: ubuntu-latest
steps:
- name: Clear failure cache
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh cache list --json id,key --jq '.[] | select(.key | startswith("release-last-failed-${{ github.ref_name }}-")) | .id' | while read -r id; do
gh cache delete "$id" 2>/dev/null || true
done
uses: Extra-Chill/homeboy-action/.github/workflows/release.yml@v2
with:
dry-run: ${{ inputs.dry-run || false }}
args: '--setting database_type=mysql --setting wp_codebox_phpunit_config=/wordpress/wp-content/plugins/data-machine/phpunit.xml.dist'
secrets: inherit
Loading