chore: update .github/workflows/auto-release.yml from MokoStandards
This commit is contained in:
255
.github/workflows/auto-release.yml
vendored
255
.github/workflows/auto-release.yml
vendored
@@ -6,24 +6,22 @@
|
||||
# DEFGROUP: GitHub.Workflow
|
||||
# INGROUP: MokoStandards.Release
|
||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
# PATH: /templates/workflows/joomla/auto-release.yml.template
|
||||
# VERSION: 04.06.00
|
||||
# BRIEF: Joomla build & release — ZIP package, updates.xml, SHA-256 checksum
|
||||
# PATH: /templates/workflows/shared/auto-release.yml
|
||||
# VERSION: 04.05.13
|
||||
# BRIEF: Generic build & release pipeline — version branch, platform version, badges, tag, release
|
||||
#
|
||||
# +========================================================================+
|
||||
# | BUILD & RELEASE PIPELINE (JOOMLA) |
|
||||
# | BUILD & RELEASE PIPELINE |
|
||||
# +========================================================================+
|
||||
# | |
|
||||
# | Triggers on push to main (skips bot commits + [skip ci]): |
|
||||
# | |
|
||||
# | Every push: |
|
||||
# | 1. Read version from README.md |
|
||||
# | 3. Set platform version (Joomla <version>) |
|
||||
# | 3. Set platform version |
|
||||
# | 4. Update [VERSION: XX.YY.ZZ] badges in markdown files |
|
||||
# | 5. Write updates.xml (Joomla update server XML) |
|
||||
# | 6. Create git tag vXX.YY.ZZ |
|
||||
# | 7a. Patch: update existing GitHub Release for this minor |
|
||||
# | 8. Build ZIP, upload asset, write SHA-256 to updates.xml |
|
||||
# | |
|
||||
# | Every version change: archives main -> version/XX.YY branch |
|
||||
# | Patch 00 = development (no release). First release = patch 01. |
|
||||
@@ -35,14 +33,13 @@
|
||||
name: Build & Release
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'htdocs/**'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
@@ -55,7 +52,8 @@ jobs:
|
||||
name: Build & Release Pipeline
|
||||
runs-on: ubuntu-latest
|
||||
if: >-
|
||||
github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
|
||||
!contains(github.event.head_commit.message, '[skip ci]') &&
|
||||
github.actor != 'github-actions[bot]'
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -143,11 +141,11 @@ jobs:
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
ERRORS=0
|
||||
|
||||
echo "## Pre-Release Sanity Checks (Joomla)" >> $GITHUB_STEP_SUMMARY
|
||||
echo "## Pre-Release Sanity Checks" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# -- Version drift check (must pass before release) --------
|
||||
README_VER=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' README.md 2>/dev/null | head -1)
|
||||
README_VER=$(grep -oP 'VERSION:\s*\K[\d.]+' README.md 2>/dev/null | head -1)
|
||||
if [ "$README_VER" != "$VERSION" ]; then
|
||||
echo "- Version drift: README says \`${README_VER}\` but releasing \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||
ERRORS=$((ERRORS+1))
|
||||
@@ -156,7 +154,7 @@ jobs:
|
||||
fi
|
||||
|
||||
# Check CHANGELOG version matches
|
||||
CL_VER=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' CHANGELOG.md 2>/dev/null | head -1)
|
||||
CL_VER=$(grep -oP 'VERSION:\s*\K[\d.]+' CHANGELOG.md 2>/dev/null | head -1)
|
||||
if [ -n "$CL_VER" ] && [ "$CL_VER" != "$VERSION" ]; then
|
||||
echo "- CHANGELOG drift: \`${CL_VER}\` != \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||
ERRORS=$((ERRORS+1))
|
||||
@@ -164,7 +162,7 @@ jobs:
|
||||
|
||||
# Check composer.json version if present
|
||||
if [ -f "composer.json" ]; then
|
||||
COMP_VER=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' composer.json 2>/dev/null | head -1)
|
||||
COMP_VER=$(grep -oP '"version"\s*:\s*"\K[^"]+' composer.json 2>/dev/null | head -1)
|
||||
if [ -n "$COMP_VER" ] && [ "$COMP_VER" != "$VERSION" ]; then
|
||||
echo "- composer.json drift: \`${COMP_VER}\` != \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||
ERRORS=$((ERRORS+1))
|
||||
@@ -185,30 +183,6 @@ jobs:
|
||||
echo "- Source directory present" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
# -- Joomla: manifest version drift --------
|
||||
MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
|
||||
if [ -n "$MANIFEST" ]; then
|
||||
XML_VER=$(sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" 2>/dev/null | head -1)
|
||||
if [ -n "$XML_VER" ] && [ "$XML_VER" != "$VERSION" ]; then
|
||||
echo "- Manifest drift: \`${XML_VER}\` != \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||
ERRORS=$((ERRORS+1))
|
||||
else
|
||||
echo "- Manifest version: \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
fi
|
||||
|
||||
# -- Joomla: XML manifest existence --------
|
||||
if [ -z "$MANIFEST" ]; then
|
||||
echo "- No Joomla XML manifest found" >> $GITHUB_STEP_SUMMARY
|
||||
ERRORS=$((ERRORS+1))
|
||||
else
|
||||
echo "- Manifest: \`${MANIFEST}\`" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# -- Joomla: extension type check --------
|
||||
TYPE=$(sed -n 's/.*<extension[^>]*type="\([^"]*\)".*/\1/p' "$MANIFEST" 2>/dev/null)
|
||||
echo "- Extension type: ${TYPE:-unknown}" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
if [ "$ERRORS" -gt 0 ]; then
|
||||
echo "**${ERRORS} error(s) — release may be incomplete**" >> $GITHUB_STEP_SUMMARY
|
||||
@@ -259,120 +233,6 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
# -- STEP 5: Write updates.xml (Joomla update server) ---------------------
|
||||
- name: "Step 5: Write updates.xml"
|
||||
if: >-
|
||||
steps.version.outputs.skip != 'true' &&
|
||||
steps.check.outputs.already_released != 'true'
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
REPO="${{ github.repository }}"
|
||||
|
||||
# -- Parse extension metadata from XML manifest ----------------
|
||||
MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
|
||||
if [ -z "$MANIFEST" ]; then
|
||||
echo "Warning: No Joomla XML manifest found — skipping updates.xml" >> $GITHUB_STEP_SUMMARY
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extract fields using sed (portable — no grep -P)
|
||||
EXT_NAME=$(sed -n 's/.*<name>\([^<]*\)<\/name>.*/\1/p' "$MANIFEST" | head -1)
|
||||
EXT_TYPE=$(sed -n 's/.*<extension[^>]*type="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
|
||||
EXT_ELEMENT=$(sed -n 's/.*<element>\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" | head -1)
|
||||
EXT_CLIENT=$(sed -n 's/.*<extension[^>]*client="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
|
||||
EXT_FOLDER=$(sed -n 's/.*<extension[^>]*group="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
|
||||
TARGET_PLATFORM=$(sed -n 's/.*\(<targetplatform[^/]*\/>\).*/\1/p' "$MANIFEST" | head -1)
|
||||
PHP_MINIMUM=$(sed -n 's/.*<php_minimum>\([^<]*\)<\/php_minimum>.*/\1/p' "$MANIFEST" | head -1)
|
||||
|
||||
# Fallbacks
|
||||
[ -z "$EXT_NAME" ] && EXT_NAME="${{ github.event.repository.name }}"
|
||||
[ -z "$EXT_TYPE" ] && EXT_TYPE="component"
|
||||
|
||||
# Templates/modules don't have <element> — derive from <name> (lowercased)
|
||||
if [ -z "$EXT_ELEMENT" ]; then
|
||||
EXT_ELEMENT=$(echo "$EXT_NAME" | tr '[:upper:]' '[:lower:]' | tr -d ' ')
|
||||
fi
|
||||
|
||||
# Build client tag: plugins and frontend modules need <client>site</client>
|
||||
CLIENT_TAG=""
|
||||
if [ -n "$EXT_CLIENT" ]; then
|
||||
CLIENT_TAG="<client>${EXT_CLIENT}</client>"
|
||||
elif [ "$EXT_TYPE" = "module" ] || [ "$EXT_TYPE" = "plugin" ]; then
|
||||
CLIENT_TAG="<client>site</client>"
|
||||
fi
|
||||
|
||||
# Build folder tag for plugins (required for Joomla to match the update)
|
||||
FOLDER_TAG=""
|
||||
if [ -n "$EXT_FOLDER" ] && [ "$EXT_TYPE" = "plugin" ]; then
|
||||
FOLDER_TAG="<folder>${EXT_FOLDER}</folder>"
|
||||
fi
|
||||
|
||||
# Build targetplatform (fallback to Joomla 5 if not in manifest)
|
||||
if [ -z "$TARGET_PLATFORM" ]; then
|
||||
TARGET_PLATFORM=$(printf '<targetplatform name="joomla" version="5.*" %s>' "/")
|
||||
fi
|
||||
|
||||
# Build php_minimum tag
|
||||
PHP_TAG=""
|
||||
if [ -n "$PHP_MINIMUM" ]; then
|
||||
PHP_TAG="<php_minimum>${PHP_MINIMUM}</php_minimum>"
|
||||
fi
|
||||
|
||||
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/v${VERSION}/${EXT_ELEMENT}-${VERSION}.zip"
|
||||
INFO_URL="https://github.com/${REPO}/releases/tag/v${VERSION}"
|
||||
|
||||
# -- Build stable entry to temp file ─────────────────────────
|
||||
{
|
||||
printf '%s\n' ' <update>'
|
||||
printf '%s\n' " <name>${EXT_NAME}</name>"
|
||||
printf '%s\n' " <description>${EXT_NAME} update</description>"
|
||||
printf '%s\n' " <element>${EXT_ELEMENT}</element>"
|
||||
printf '%s\n' " <type>${EXT_TYPE}</type>"
|
||||
printf '%s\n' " <version>${VERSION}</version>"
|
||||
[ -n "$CLIENT_TAG" ] && printf '%s\n' " ${CLIENT_TAG}"
|
||||
[ -n "$FOLDER_TAG" ] && printf '%s\n' " ${FOLDER_TAG}"
|
||||
printf '%s\n' ' <tags>'
|
||||
printf '%s\n' ' <tag>stable</tag>'
|
||||
printf '%s\n' ' </tags>'
|
||||
printf '%s\n' " <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>"
|
||||
printf '%s\n' ' <downloads>'
|
||||
printf '%s\n' " <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>"
|
||||
printf '%s\n' ' </downloads>'
|
||||
printf '%s\n' " ${TARGET_PLATFORM}"
|
||||
[ -n "$PHP_TAG" ] && printf '%s\n' " ${PHP_TAG}"
|
||||
printf '%s\n' ' <maintainer>Moko Consulting</maintainer>'
|
||||
printf '%s\n' ' <maintainerurl>https://mokoconsulting.tech</maintainerurl>'
|
||||
printf '%s\n' ' </update>'
|
||||
} > /tmp/stable_entry.xml
|
||||
|
||||
# -- Write updates.xml preserving dev/rc entries ──────────────
|
||||
# Extract existing entries for other stability levels
|
||||
# Order reflects release workflow: development → alpha → beta → rc → stable
|
||||
if [ -f "updates.xml" ]; then
|
||||
printf 'import re, sys\n' > /tmp/extract.py
|
||||
printf 'with open("updates.xml") as f: c = f.read()\n' >> /tmp/extract.py
|
||||
printf 'tag = sys.argv[1]\n' >> /tmp/extract.py
|
||||
printf 'm = re.search(r"( <update>.*?<tag>" + re.escape(tag) + r"</tag>.*?</update>)", c, re.DOTALL)\n' >> /tmp/extract.py
|
||||
printf 'if m: print(m.group(1))\n' >> /tmp/extract.py
|
||||
fi
|
||||
DEV_ENTRY=$(python3 /tmp/extract.py development 2>/dev/null || true)
|
||||
ALPHA_ENTRY=$(python3 /tmp/extract.py alpha 2>/dev/null || true)
|
||||
BETA_ENTRY=$(python3 /tmp/extract.py beta 2>/dev/null || true)
|
||||
RC_ENTRY=$(python3 /tmp/extract.py rc 2>/dev/null || true)
|
||||
|
||||
{
|
||||
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
|
||||
printf '%s\n' '<updates>'
|
||||
[ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY"
|
||||
[ -n "$ALPHA_ENTRY" ] && echo "$ALPHA_ENTRY"
|
||||
[ -n "$BETA_ENTRY" ] && echo "$BETA_ENTRY"
|
||||
[ -n "$RC_ENTRY" ] && echo "$RC_ENTRY"
|
||||
cat /tmp/stable_entry.xml
|
||||
printf '%s\n' '</updates>'
|
||||
} > updates.xml
|
||||
|
||||
echo "updates.xml: ${VERSION} (stable + rc/dev preserved)" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# -- Commit all changes ---------------------------------------------------
|
||||
- name: Commit release changes
|
||||
if: >-
|
||||
@@ -430,14 +290,14 @@ jobs:
|
||||
EXISTING=$(gh release view "$RELEASE_TAG" --json tagName -q .tagName 2>/dev/null || true)
|
||||
|
||||
if [ -z "$EXISTING" ]; then
|
||||
# First release for this major
|
||||
# First release for this major: create GitHub Release
|
||||
gh release create "$RELEASE_TAG" \
|
||||
--title "v${MAJOR} (latest: ${VERSION})" \
|
||||
--notes-file /tmp/release_notes.md \
|
||||
--target "$BRANCH"
|
||||
echo "Release created: ${RELEASE_TAG} (${VERSION})" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
# Append version notes to existing major release
|
||||
# Update existing major release with new version info
|
||||
CURRENT_NOTES=$(gh release view "$RELEASE_TAG" --json body -q .body 2>/dev/null || true)
|
||||
{
|
||||
echo "$CURRENT_NOTES"
|
||||
@@ -454,89 +314,6 @@ jobs:
|
||||
echo "Release updated: ${RELEASE_TAG} -> ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
# -- STEP 8: Build Joomla install ZIP + SHA-256 checksum ------------------
|
||||
# Every patch builds an install-ready ZIP and uploads it to the minor release.
|
||||
# Result: one Release per minor version with a ZIP for each patch.
|
||||
- name: "Step 8: Build Joomla package and update checksum"
|
||||
if: >-
|
||||
steps.version.outputs.skip != 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
||||
REPO="${{ github.repository }}"
|
||||
|
||||
# All ZIPs upload to the major release tag (vXX)
|
||||
gh release view "$RELEASE_TAG" --json tagName > /dev/null 2>&1 || {
|
||||
echo "No release ${RELEASE_TAG} found — skipping ZIP upload"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Find extension element name from manifest
|
||||
MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1 || true)
|
||||
[ -z "$MANIFEST" ] && exit 0
|
||||
|
||||
EXT_ELEMENT=$(sed -n 's/.*<element>\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" 2>/dev/null | head -1 || basename "$MANIFEST" .xml)
|
||||
ZIP_NAME="${EXT_ELEMENT}-${VERSION}.zip"
|
||||
TAR_NAME="${EXT_ELEMENT}-${VERSION}.tar.gz"
|
||||
|
||||
# -- Build install packages from src/ ----------------------------
|
||||
SOURCE_DIR="src"
|
||||
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
||||
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ — skipping package"; exit 0; }
|
||||
|
||||
EXCLUDES=".ftpignore sftp-config* *.ppk *.pem *.key .env*"
|
||||
|
||||
# ZIP package
|
||||
cd "$SOURCE_DIR"
|
||||
zip -r "/tmp/${ZIP_NAME}" . -x $EXCLUDES
|
||||
cd ..
|
||||
|
||||
# tar.gz package
|
||||
tar -czf "/tmp/${TAR_NAME}" -C "$SOURCE_DIR" \
|
||||
--exclude='.ftpignore' --exclude='sftp-config*' \
|
||||
--exclude='*.ppk' --exclude='*.pem' --exclude='*.key' --exclude='.env*' .
|
||||
|
||||
ZIP_SIZE=$(stat -c%s "/tmp/${ZIP_NAME}" 2>/dev/null || stat -f%z "/tmp/${ZIP_NAME}" 2>/dev/null || echo "unknown")
|
||||
TAR_SIZE=$(stat -c%s "/tmp/${TAR_NAME}" 2>/dev/null || stat -f%z "/tmp/${TAR_NAME}" 2>/dev/null || echo "unknown")
|
||||
|
||||
# -- Calculate SHA-256 for both ----------------------------------
|
||||
SHA256_ZIP=$(sha256sum "/tmp/${ZIP_NAME}" | cut -d' ' -f1)
|
||||
SHA256_TAR=$(sha256sum "/tmp/${TAR_NAME}" | cut -d' ' -f1)
|
||||
|
||||
# -- Upload both to release tag ----------------------------------
|
||||
gh release upload "$RELEASE_TAG" "/tmp/${ZIP_NAME}" --clobber 2>/dev/null || true
|
||||
gh release upload "$RELEASE_TAG" "/tmp/${TAR_NAME}" --clobber 2>/dev/null || true
|
||||
|
||||
# -- Update updates.xml with both download formats ---------------
|
||||
if [ -f "updates.xml" ]; then
|
||||
ZIP_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${ZIP_NAME}"
|
||||
TAR_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${TAR_NAME}"
|
||||
|
||||
# Replace downloads block with both formats + SHA
|
||||
sed -i "s|<downloads>.*</downloads>|<downloads>\n <downloadurl type=\"full\" format=\"zip\">${ZIP_URL}</downloadurl>\n <downloadurl type=\"full\" format=\"tar.gz\">${TAR_URL}</downloadurl>\n </downloads>|" updates.xml 2>/dev/null || true
|
||||
if grep -q '<sha256>' updates.xml; then
|
||||
sed -i "s|<sha256>.*</sha256>|<sha256>sha256:${SHA256_ZIP}</sha256>|" updates.xml
|
||||
else
|
||||
sed -i "s|</downloads>|</downloads>\n <sha256>sha256:${SHA256_ZIP}</sha256>|" updates.xml
|
||||
fi
|
||||
|
||||
git add updates.xml
|
||||
git commit -m "chore(release): ZIP + tar.gz for ${VERSION} [skip ci]" \
|
||||
--author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>" || true
|
||||
git push || true
|
||||
fi
|
||||
|
||||
echo "### Joomla Packages" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Package | Size | SHA-256 |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "|---------|------|---------|" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| \`${ZIP_NAME}\` | ${ZIP_SIZE} | \`${SHA256_ZIP}\` |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| \`${TAR_NAME}\` | ${TAR_SIZE} | \`${SHA256_TAR}\` |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Release | \`${RELEASE_TAG}\` | |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Download | [${PACKAGE_NAME}](https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}) |" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# -- Summary --------------------------------------------------------------
|
||||
- name: Pipeline Summary
|
||||
if: always()
|
||||
@@ -549,7 +326,7 @@ jobs:
|
||||
echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "## Build & Release Complete (Joomla)" >> $GITHUB_STEP_SUMMARY
|
||||
echo "## Build & Release Complete" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
Reference in New Issue
Block a user