Update release_from_version.yml
This commit is contained in:
275
.github/workflows/release_from_version.yml
vendored
275
.github/workflows/release_from_version.yml
vendored
@@ -2,277 +2,64 @@ name: Release from Version Branch Pipeline
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_branch:
|
||||
description: "Source dev branch. Example dev/03.06.00"
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
meta:
|
||||
name: Derive version metadata from branch
|
||||
rename_branch:
|
||||
name: 01 Promote dev to version
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
branch: ${{ steps.meta.outputs.branch }}
|
||||
version: ${{ steps.meta.outputs.version }}
|
||||
is_prerelease: ${{ steps.meta.outputs.is_prerelease }}
|
||||
version: ${{ steps.extract.outputs.version }}
|
||||
version_branch: ${{ steps.extract.outputs.version_branch }}
|
||||
|
||||
steps:
|
||||
- name: Determine branch and version
|
||||
id: meta
|
||||
- name: Extract Version from Branch Name
|
||||
id: extract
|
||||
run: |
|
||||
BRANCH="${GITHUB_REF_NAME}"
|
||||
set -euo pipefail
|
||||
|
||||
echo "Running on branch: ${BRANCH}"
|
||||
SRC="${{ inputs.source_branch }}"
|
||||
|
||||
if [[ ! "${BRANCH}" =~ ^version\/[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9._]+)?$ ]]; then
|
||||
echo "This workflow must be run on a branch named version/X.Y.Z or version/X.Y.Z-suffix"
|
||||
exit 1
|
||||
fi
|
||||
echo "$SRC" | grep -E '^dev/[0-9]+\.[0-9]+\.[0-9]+$'
|
||||
|
||||
VERSION="${BRANCH#version/}"
|
||||
VERSION="${SRC#dev/}"
|
||||
VERSION_BRANCH="version/$VERSION"
|
||||
|
||||
echo "Detected version: ${VERSION}"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "version_branch=$VERSION_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
|
||||
if [[ "${VERSION}" =~ -(alpha|beta|rc|pre|preview|dev|test) ]]; then
|
||||
echo "Version is prerelease: ${VERSION}"
|
||||
IS_PRERELEASE="true"
|
||||
else
|
||||
echo "Version is stable: ${VERSION}"
|
||||
IS_PRERELEASE="false"
|
||||
fi
|
||||
|
||||
echo "branch=${BRANCH}" >> "$GITHUB_OUTPUT"
|
||||
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
echo "is_prerelease=${IS_PRERELEASE}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
build-and-test:
|
||||
name: Build and test (sanity check)
|
||||
runs-on: ubuntu-latest
|
||||
needs: meta
|
||||
|
||||
steps:
|
||||
- name: Check out version branch
|
||||
- name: Checkout Source Branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.branch }}
|
||||
|
||||
- name: Set up PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.2"
|
||||
coverage: none
|
||||
|
||||
- name: PHP lint under src (if present)
|
||||
run: |
|
||||
if [ -d "src" ]; then
|
||||
echo "Running php -l against PHP files in src/"
|
||||
find src -type f -name "*.php" -print0 | xargs -0 -n 1 -P 4 php -l
|
||||
else
|
||||
echo "No src directory found. Skipping PHP lint."
|
||||
fi
|
||||
|
||||
- name: Install dependencies if composer.json exists
|
||||
run: |
|
||||
if [ -f "composer.json" ]; then
|
||||
composer install --no-interaction --no-progress --prefer-dist
|
||||
else
|
||||
echo "No composer.json found. Skipping composer install."
|
||||
fi
|
||||
|
||||
- name: Run Composer tests when defined
|
||||
run: |
|
||||
if [ ! -f "composer.json" ]; then
|
||||
echo "No composer.json. Nothing to test."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if composer run -q | grep -q "^ test"; then
|
||||
echo "Detected composer script 'test'. Running composer test."
|
||||
composer test
|
||||
else
|
||||
echo "No 'test' script defined in composer.json. Skipping tests."
|
||||
fi
|
||||
|
||||
changelog:
|
||||
name: Update CHANGELOG.md on version branch
|
||||
runs-on: ubuntu-latest
|
||||
needs: [meta, build-and-test]
|
||||
|
||||
steps:
|
||||
- name: Check out version branch with history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.branch }}
|
||||
ref: ${{ inputs.source_branch }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Fetch main for comparison
|
||||
run: |
|
||||
git fetch origin main
|
||||
|
||||
- name: Update CHANGELOG using script
|
||||
env:
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
run: |
|
||||
if [ ! -f "scripts/update_changelog.sh" ]; then
|
||||
echo "ERROR: scripts/update_changelog.sh not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod +x scripts/update_changelog.sh
|
||||
./scripts/update_changelog.sh "${VERSION}"
|
||||
|
||||
- name: Commit CHANGELOG.md if changed
|
||||
env:
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
- name: Configure Git Identity
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
if git diff --quiet; then
|
||||
echo "No changelog changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git add CHANGELOG.md
|
||||
git commit -m "chore: update changelog for ${VERSION}"
|
||||
git push origin HEAD
|
||||
|
||||
pr-merge-release:
|
||||
name: PR, conditional squash, and GitHub release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [meta, changelog]
|
||||
|
||||
steps:
|
||||
- name: Check out version branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.branch }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Verify branch has commits ahead of main
|
||||
- name: Promote dev branch to version branch
|
||||
run: |
|
||||
git fetch origin main
|
||||
set -euo pipefail
|
||||
|
||||
AHEAD_COUNT=$(git rev-list --count origin/main..HEAD)
|
||||
echo "Commits ahead of main: ${AHEAD_COUNT}"
|
||||
SRC="${{ inputs.source_branch }}"
|
||||
DST="${{ steps.extract.outputs.version_branch }}"
|
||||
|
||||
if [ "${AHEAD_COUNT}" -eq 0 ]; then
|
||||
echo "ERROR: No commits between main and ${GITHUB_REF_NAME}."
|
||||
echo "Action required: commit changes to the version branch before running this workflow."
|
||||
git fetch origin
|
||||
|
||||
if git show-ref --verify --quiet "refs/remotes/origin/$DST"; then
|
||||
echo "ERROR: $DST already exists."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Ensure standard PR labels exist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo "Ensuring standard labels exist"
|
||||
gh label create "release" --color "0E8A16" --description "Release related PR" || echo "Label 'release' already exists"
|
||||
gh label create "version-update" --color "5319E7" --description "Version bump and release PR" || echo "Label 'version-update' already exists"
|
||||
|
||||
- name: Create or reuse PR from version branch to main
|
||||
id: pr
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: ${{ needs.meta.outputs.branch }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
run: |
|
||||
echo "Ensuring PR exists for ${BRANCH} -> main"
|
||||
|
||||
PR_NUMBER=$(gh pr list --head "${BRANCH}" --base "main" --state open --json number -q '.[0].number' || true)
|
||||
|
||||
if [ -z "${PR_NUMBER}" ]; then
|
||||
echo "No existing open PR found. Creating PR."
|
||||
PR_URL=$(gh pr create --base "main" --head "${BRANCH}" --title "Merge version ${VERSION} into main" --body "Automated PR to merge version ${VERSION} into main.")
|
||||
PR_NUMBER=$(gh pr view "${PR_URL}" --json number -q '.number')
|
||||
|
||||
echo "Applying standard labels (non-blocking)"
|
||||
gh pr edit "${PR_NUMBER}" --add-label "release" || echo "Label 'release' not found or cannot be applied"
|
||||
gh pr edit "${PR_NUMBER}" --add-label "version-update" || echo "Label 'version-update' not found or cannot be applied"
|
||||
else
|
||||
echo "Found existing PR #${PR_NUMBER}"
|
||||
fi
|
||||
|
||||
echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Squash merge PR into main (stable only)
|
||||
if: needs.meta.outputs.is_prerelease == 'false'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
PR_NUMBER: ${{ steps.pr.outputs.pr_number }}
|
||||
run: |
|
||||
if [ -z "${PR_NUMBER}" ]; then
|
||||
echo "No pull request number returned. Cannot squash merge."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Performing squash merge PR #${PR_NUMBER} into main"
|
||||
|
||||
MERGE_PAYLOAD=$(jq -n --arg method "squash" --arg title "Squash merge version ${VERSION} into main" '{"merge_method": $method, "commit_title": $title}')
|
||||
|
||||
curl -sS -X PUT -H "Authorization: Bearer ${GITHUB_TOKEN}" -H "Accept: application/vnd.github+json" "https://api.github.com/repos/${REPO}/pulls/${PR_NUMBER}/merge" -d "${MERGE_PAYLOAD}"
|
||||
|
||||
- name: Skip squash (prerelease detected)
|
||||
if: needs.meta.outputs.is_prerelease == 'true'
|
||||
run: |
|
||||
echo "Prerelease version detected. PR created but squash merge intentionally skipped."
|
||||
|
||||
- name: Create GitHub Release (stable and prerelease) and attach ZIP from src
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
IS_PRERELEASE: ${{ needs.meta.outputs.is_prerelease }}
|
||||
run: |
|
||||
PRERELEASE_FLAG="false"
|
||||
if [ "${IS_PRERELEASE}" = "true" ]; then
|
||||
PRERELEASE_FLAG="true"
|
||||
fi
|
||||
|
||||
echo "Building ZIP from src for version ${VERSION}"
|
||||
|
||||
REPO_NAME="${GITHUB_REPOSITORY##*/}"
|
||||
ASSET_NAME="${REPO_NAME}-${VERSION}.zip"
|
||||
|
||||
if [ ! -d "src" ]; then
|
||||
echo "ERROR: src directory does not exist. Cannot build release ZIP."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p dist
|
||||
cd src
|
||||
zip -r "../dist/${ASSET_NAME}" .
|
||||
cd ..
|
||||
|
||||
echo "Preparing GitHub release for ${VERSION} (prerelease=${PRERELEASE_FLAG}) with asset dist/${ASSET_NAME}"
|
||||
|
||||
if gh release view "${VERSION}" >/dev/null 2>&1; then
|
||||
echo "Release ${VERSION} already exists. Uploading asset."
|
||||
gh release upload "${VERSION}" "dist/${ASSET_NAME}" --clobber
|
||||
else
|
||||
ARGS=(
|
||||
"${VERSION}"
|
||||
"dist/${ASSET_NAME}"
|
||||
--title
|
||||
"Version ${VERSION}"
|
||||
--notes
|
||||
"Release generated from branch version/${VERSION}."
|
||||
)
|
||||
|
||||
if [ "${PRERELEASE_FLAG}" = "true" ]; then
|
||||
ARGS+=(--prerelease)
|
||||
fi
|
||||
|
||||
gh release create "${ARGS[@]}"
|
||||
fi
|
||||
|
||||
- name: Optional delete version branch after merge (stable only)
|
||||
if: needs.meta.outputs.is_prerelease == 'false'
|
||||
env:
|
||||
BRANCH: ${{ needs.meta.outputs.branch }}
|
||||
run: |
|
||||
echo "Deleting branch ${BRANCH} after squash merge and release"
|
||||
git push origin --delete "${BRANCH}" || echo "Branch already deleted or cannot delete"
|
||||
git checkout -B "$DST" "origin/$SRC"
|
||||
git push origin "$DST"
|
||||
git push origin --delete "$SRC"
|
||||
|
||||
Reference in New Issue
Block a user