Rewrite release.yml: Gitea-primary, GitHub backup mirror
Some checks failed
CodeQL Security Scanning / Analyze (actions) (push) Has been cancelled
CodeQL Security Scanning / Analyze (javascript) (push) Has been cancelled
CodeQL Security Scanning / Security Scan Summary (push) Has been cancelled
Repo Health / Access control (push) Has been cancelled
Repo Health / Release configuration (push) Has been cancelled
Repo Health / Scripts governance (push) Has been cancelled
Repo Health / Repository health (push) Has been cancelled
Standards Compliance / Secret Scanning (push) Has been cancelled
Standards Compliance / License Header Validation (push) Has been cancelled
Standards Compliance / Repository Structure Validation (push) Has been cancelled
Standards Compliance / Coding Standards Check (push) Has been cancelled
Standards Compliance / Version Consistency Check (push) Has been cancelled
Standards Compliance / Workflow Configuration Check (push) Has been cancelled
Standards Compliance / Documentation Quality Check (push) Has been cancelled
Standards Compliance / README Completeness Check (push) Has been cancelled
Standards Compliance / Git Repository Hygiene (push) Has been cancelled
Standards Compliance / Script Integrity Validation (push) Has been cancelled
Standards Compliance / Line Length Check (push) Has been cancelled
Standards Compliance / File Naming Standards (push) Has been cancelled
Standards Compliance / Insecure Code Pattern Detection (push) Has been cancelled
Standards Compliance / Code Complexity Analysis (push) Has been cancelled
Standards Compliance / Code Duplication Detection (push) Has been cancelled
Standards Compliance / Dead Code Detection (push) Has been cancelled
Standards Compliance / File Size Limits (push) Has been cancelled
Standards Compliance / Binary File Detection (push) Has been cancelled
Standards Compliance / TODO/FIXME Tracking (push) Has been cancelled
Standards Compliance / Dependency Vulnerability Scanning (push) Has been cancelled
Standards Compliance / Unused Dependencies Check (push) Has been cancelled
Standards Compliance / Broken Link Detection (push) Has been cancelled
Standards Compliance / API Documentation Coverage (push) Has been cancelled
Standards Compliance / Accessibility Check (push) Has been cancelled
Standards Compliance / Performance Metrics (push) Has been cancelled
Standards Compliance / Enterprise Readiness Check (push) Has been cancelled
Standards Compliance / Repository Health Check (push) Has been cancelled
Standards Compliance / Terraform Configuration Validation (push) Has been cancelled
Standards Compliance / Compliance Summary (push) Has been cancelled

- All release creation via Gitea API (curl), no gh CLI or softprops
- GitHub mirror is optional (uses GH_MIRROR_TOKEN, continue-on-error)
- Stability input: development/alpha/beta/rc/stable with proper suffixes
- ZIP excludes sftp-config, .local, .env, keys
- Auto-updates updates.xml SHA-256 for matching channel
- Uses GITEA_TOKEN secret for authentication

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan Miller
2026-04-16 22:09:41 -05:00
parent 7969dd1282
commit 2862d2530e

View File

@@ -4,27 +4,13 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# FILE INFORMATION
# DEFGROUP: GitHub.Workflow
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoCassiopeia.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoCassiopeia
# PATH: /.github/workflows/release.yml
# VERSION: 03.09.03
# BRIEF: Automated release workflow for MokoCassiopeia Joomla template
# NOTE: Creates release packages and publishes to GitHub Releases
# VERSION: 03.09.16
# BRIEF: Joomla release — build ZIP, publish to Gitea, mirror to GitHub
name: Create Release
@@ -35,7 +21,7 @@ on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., 03.08.03)'
description: 'Release version (e.g., 03.09.16)'
required: true
type: string
prerelease:
@@ -43,15 +29,26 @@ on:
required: false
type: boolean
default: false
stability:
description: 'Stability tag (development, alpha, beta, rc, stable)'
required: false
type: string
default: 'development'
permissions:
contents: write
env:
GITEA_URL: https://git.mokoconsulting.tech
GITEA_ORG: MokoConsulting
GITEA_REPO: MokoCassiopeia
EXT_ELEMENT: mokocassiopeia
jobs:
build:
name: Build Release Package
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
@@ -65,16 +62,38 @@ jobs:
extensions: mbstring, xml, zip
tools: composer:v2
- name: Get version
id: version
- name: Get version and stability
id: meta
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ inputs.version }}"
STABILITY="${{ inputs.stability }}"
PRERELEASE="${{ inputs.prerelease }}"
else
VERSION=${GITHUB_REF#refs/tags/}
STABILITY="stable"
PRERELEASE="false"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Building version: ${VERSION}"
# Derive suffix and tag from stability
case "$STABILITY" in
development) SUFFIX="-dev"; TAG_NAME="development" ;;
alpha) SUFFIX="-alpha"; TAG_NAME="alpha" ;;
beta) SUFFIX="-beta"; TAG_NAME="beta" ;;
rc) SUFFIX="-rc"; TAG_NAME="release-candidate" ;;
stable) SUFFIX=""; TAG_NAME="v${VERSION%%.*}" ;;
*) SUFFIX="-dev"; TAG_NAME="development" ;;
esac
ZIP_NAME="${EXT_ELEMENT}-${VERSION}${SUFFIX}.zip"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
echo "prerelease=${PRERELEASE}" >> "$GITHUB_OUTPUT"
echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT"
echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
echo "zip_name=${ZIP_NAME}" >> "$GITHUB_OUTPUT"
echo "Building: ${ZIP_NAME} (${STABILITY})"
- name: Install dependencies
run: |
@@ -82,129 +101,226 @@ jobs:
composer install --no-dev --optimize-autoloader
fi
- name: Update version in manifest files
run: |
VERSION="${{ steps.version.outputs.version }}"
# Update version in templateDetails.xml
sed -i "s/<version>.*<\/version>/<version>${VERSION}<\/version>/g" src/templateDetails.xml
# Update version in updates.xml
sed -i "s/<version>.*<\/version>/<version>${VERSION}<\/version>/g" updates.xml
# Update creation date to today
DATE=$(date +%Y-%m-%d)
sed -i "s/<creationDate>.*<\/creationDate>/<creationDate>${DATE}<\/creationDate>/g" src/templateDetails.xml
sed -i "s/<creationDate>.*<\/creationDate>/<creationDate>${DATE}<\/creationDate>/g" updates.xml
- name: Create package structure
- name: Create package
run: |
mkdir -p build/package
# Copy template files from src (excluding media directory)
rsync -av --exclude='media' src/ build/package/
# Copy media files from src/media to package/media directory
mkdir -p build/package/media
rsync -av src/media/ build/package/media/
rsync -av \
--exclude='sftp-config*' \
--exclude='.ftpignore' \
--exclude='*.ppk' \
--exclude='*.pem' \
--exclude='*.key' \
--exclude='.env*' \
--exclude='*.local' \
src/ build/package/
- name: Create source ZIP package
- name: Build ZIP
id: zip
run: |
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
cd build/package
VERSION="${{ steps.version.outputs.version }}"
ZIP_NAME="mokocassiopeia-src-${VERSION}.zip"
zip -r "../${ZIP_NAME}" .
cd ../..
echo "ZIP_NAME=${ZIP_NAME}" >> $GITHUB_ENV
echo "Created package: ${ZIP_NAME}"
cd ..
- name: Generate checksums
SHA256=$(sha256sum "${ZIP_NAME}" | cut -d' ' -f1)
SIZE=$(stat -c%s "${ZIP_NAME}")
echo "sha256=${SHA256}" >> "$GITHUB_OUTPUT"
echo "size=${SIZE}" >> "$GITHUB_OUTPUT"
echo "SHA-256: ${SHA256}"
echo "Size: ${SIZE} bytes"
# ── Gitea Release (PRIMARY) ──────────────────────────────────────
- name: "Gitea: Delete existing release"
run: |
cd build
sha256sum "${ZIP_NAME}" > "${ZIP_NAME}.sha256"
md5sum "${ZIP_NAME}" > "${ZIP_NAME}.md5"
# Extract just the hash for updates.xml
SHA256_HASH=$(sha256sum "${ZIP_NAME}" | cut -d' ' -f1)
echo "SHA256_HASH=${SHA256_HASH}" >> $GITHUB_ENV
echo "SHA-256: ${SHA256_HASH}"
TAG="${{ steps.meta.outputs.tag_name }}"
TOKEN="${{ secrets.GITEA_TOKEN }}"
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: release-package
path: |
build/*.zip
build/*.sha256
build/*.md5
# Find and delete existing release by tag
RELEASE_ID=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API}/releases/tags/${TAG}" 2>/dev/null | jq -r '.id // empty')
release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: release-package
path: ./artifacts
- name: Get version
id: version
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ inputs.version }}"
else
VERSION=${GITHUB_REF#refs/tags/}
if [ -n "$RELEASE_ID" ]; then
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API}/releases/${RELEASE_ID}" || true
echo "Deleted existing release id=${RELEASE_ID}"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Extract changelog
id: changelog
# Delete existing tag
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API}/tags/${TAG}" 2>/dev/null || true
- name: "Gitea: Create release"
id: gitea_release
run: |
TAG="${{ steps.meta.outputs.tag_name }}"
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
PRERELEASE="${{ steps.meta.outputs.prerelease }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
TOKEN="${{ secrets.GITEA_TOKEN }}"
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
# Build release body
BODY="## ${EXT_ELEMENT} ${VERSION} (${STABILITY})
### SHA-256
\`${SHA256}\`"
# Extract changelog if available
if [ -f "CHANGELOG.md" ]; then
# Extract changelog for this version
VERSION="${{ steps.version.outputs.version }}"
awk "/## \[${VERSION}\]/,/## \[/{if(/## \[${VERSION}\]/)print;else if(/## \[/)exit;else print}" CHANGELOG.md > release_notes.md
if [ ! -s release_notes.md ]; then
echo "No specific changelog found for version ${VERSION}" > release_notes.md
echo "" >> release_notes.md
echo "Please refer to the full CHANGELOG.md for details." >> release_notes.md
NOTES=$(awk "/## \[${VERSION}\]/,/## \[/{if(/## \[${VERSION}\]/)next;if(/## \[/)exit;print}" CHANGELOG.md)
if [ -n "$NOTES" ]; then
BODY="## ${EXT_ELEMENT} ${VERSION} (${STABILITY})
${NOTES}
### SHA-256
\`${SHA256}\`"
fi
else
echo "Release version ${{ steps.version.outputs.version }}" > release_notes.md
fi
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.version.outputs.version }}
name: Release ${{ steps.version.outputs.version }}
body_path: release_notes.md
draft: false
prerelease: ${{ inputs.prerelease || false }}
files: |
artifacts/*.zip
artifacts/*.sha256
artifacts/*.md5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
IS_PRE="true"
if [ "$STABILITY" = "stable" ]; then
IS_PRE="false"
fi
- name: Release summary
RESULT=$(curl -sf -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API}/releases" \
-d "$(jq -n \
--arg tag "$TAG" \
--arg target "${{ github.ref_name }}" \
--arg name "${EXT_ELEMENT} ${VERSION} ${STABILITY^}" \
--arg body "$BODY" \
--argjson pre "$IS_PRE" \
'{tag_name: $tag, target_commitish: $target, name: $name, body: $body, prerelease: $pre}'
)")
RELEASE_ID=$(echo "$RESULT" | jq -r '.id')
echo "release_id=${RELEASE_ID}" >> "$GITHUB_OUTPUT"
echo "Gitea release created: id=${RELEASE_ID}, tag=${TAG}"
- name: "Gitea: Upload ZIP"
run: |
echo "### Release Created Successfully" >> $GITHUB_STEP_SUMMARY
RELEASE_ID="${{ steps.gitea_release.outputs.release_id }}"
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
TOKEN="${{ secrets.GITEA_TOKEN }}"
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/octet-stream" \
"${API}/releases/${RELEASE_ID}/assets?name=${ZIP_NAME}" \
--data-binary "@build/${ZIP_NAME}"
echo "Uploaded ${ZIP_NAME} to Gitea release ${RELEASE_ID}"
# ── GitHub Mirror (BACKUP) ───────────────────────────────────────
- name: "GitHub: Mirror release (backup)"
if: ${{ secrets.GH_MIRROR_TOKEN != '' }}
continue-on-error: true
run: |
TAG="${{ steps.meta.outputs.tag_name }}"
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
TOKEN="${{ secrets.GH_MIRROR_TOKEN }}"
GH_REPO="mokoconsulting-tech/${GITEA_REPO}"
GH_API="https://api.github.com/repos/${GH_REPO}"
IS_PRE="true"
[ "$STABILITY" = "stable" ] && IS_PRE="false"
# Delete existing release by tag
EXISTING=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${GH_API}/releases/tags/${TAG}" 2>/dev/null | jq -r '.id // empty')
if [ -n "$EXISTING" ]; then
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${GH_API}/releases/${EXISTING}" || true
fi
# Delete tag
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${GH_API}/git/refs/tags/${TAG}" 2>/dev/null || true
# Create release
RELEASE_ID=$(curl -sf -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${GH_API}/releases" \
-d "$(jq -n \
--arg tag "$TAG" \
--arg target "${{ github.sha }}" \
--arg name "${EXT_ELEMENT} ${VERSION} ${STABILITY^} (mirror)" \
--arg body "Mirror of Gitea release. SHA-256: \`${SHA256}\`" \
--argjson pre "$IS_PRE" \
'{tag_name: $tag, target_commitish: $target, name: $name, body: $body, prerelease: $pre}'
)" | jq -r '.id')
# Upload ZIP
if [ -n "$RELEASE_ID" ] && [ "$RELEASE_ID" != "null" ]; then
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/octet-stream" \
"https://uploads.github.com/repos/${GH_REPO}/releases/${RELEASE_ID}/assets?name=${ZIP_NAME}" \
--data-binary "@build/${ZIP_NAME}"
echo "GitHub mirror: uploaded ${ZIP_NAME}"
fi
# ── Update updates.xml ──────────────────────────────────────────
- name: "Update updates.xml SHA-256"
run: |
TAG="${{ steps.meta.outputs.tag_name }}"
STABILITY="${{ steps.meta.outputs.stability }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
if [ -f "updates.xml" ] && [ -n "$SHA256" ]; then
# Update the SHA for the matching stability channel
python3 -c "
import re, sys
tag_map = {'development':'development','alpha':'alpha','beta':'beta','rc':'rc','stable':'stable'}
tag = tag_map.get('${STABILITY}', 'development')
with open('updates.xml', 'r') as f:
content = f.read()
# Find the update block with matching tag and replace its sha256
pattern = r'(<tag>' + re.escape(tag) + r'</tag>.*?<sha256>)[^<]*(</sha256>)'
content = re.sub(pattern, r'\g<1>sha256:${SHA256}\g<2>', content, flags=re.DOTALL)
with open('updates.xml', 'w') as f:
f.write(content)
print(f'Updated SHA for {tag} channel')
"
fi
- name: "Commit updates.xml"
run: |
if git diff --quiet updates.xml 2>/dev/null; then
echo "No changes to updates.xml"
exit 0
fi
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git add updates.xml
git commit -m "chore: update ${STABILITY} SHA-256 for ${{ steps.meta.outputs.version }} [skip ci]" \
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>"
git push || true
- name: Summary
run: |
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
TAG="${{ steps.meta.outputs.tag_name }}"
echo "### Release Created" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- Version: ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- Repository: $GITHUB_REPOSITORY" >> $GITHUB_STEP_SUMMARY
echo "- Tag: ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- Pre-release: ${{ inputs.prerelease || false }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Package files:" >> $GITHUB_STEP_SUMMARY
ls -lh artifacts/ >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Next Steps" >> $GITHUB_STEP_SUMMARY
echo "1. Verify the release at: https://github.com/$GITHUB_REPOSITORY/releases/tag/${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "2. Update updates.xml with the SHA-256 hash from the .sha256 file" >> $GITHUB_STEP_SUMMARY
echo "3. Test the installation package" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Stability | ${STABILITY} |" >> $GITHUB_STEP_SUMMARY
echo "| Tag | \`${TAG}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Package | \`${ZIP_NAME}\` |" >> $GITHUB_STEP_SUMMARY
echo "| SHA-256 | \`${SHA256}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Gitea | [Release](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${TAG}) |" >> $GITHUB_STEP_SUMMARY