diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8d15727..11fb262 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -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 .
-#
# 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>/g" src/templateDetails.xml
- # Update version in updates.xml
- sed -i "s/.*<\/version>/${VERSION}<\/version>/g" updates.xml
- # Update creation date to today
- DATE=$(date +%Y-%m-%d)
- sed -i "s/.*<\/creationDate>/${DATE}<\/creationDate>/g" src/templateDetails.xml
- sed -i "s/.*<\/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'(' + re.escape(tag) + r'.*?)[^<]*()'
+ 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] "
+ 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