Template
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c046392574 | |||
| ce4b467865 | |||
| bd9b711a7b | |||
| 5306ca2b27 | |||
| 3a18f60deb | |||
| 10692d697a | |||
| ae565211d9 | |||
| 72ec6795c0 | |||
| 12e559c21b | |||
| e36ab75aa5 | |||
| 6109c86151 | |||
| 91ea05be8e | |||
| 7a6b7fe8b1 | |||
| e27bf25e6a | |||
| 3526b6d674 | |||
| 38271472eb | |||
| 8214e8c274 | |||
| 79160c6002 | |||
| 041d21da12 | |||
| 30080a63cb | |||
| 60f54ad998 | |||
| 8af57d5f98 | |||
| a87eb3a7a8 | |||
| 8a77aedd9d | |||
| 0db35b6d6e | |||
| 39fb0ad4b5 | |||
| 7d4e0da419 | |||
| aea064345e | |||
| a5badd55be | |||
| 4ec865bde7 |
+1
-1
@@ -113,7 +113,7 @@ releases/
|
|||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
out/
|
out/
|
||||||
site/
|
/site/
|
||||||
*.map
|
*.map
|
||||||
*.css.map
|
*.css.map
|
||||||
*.js.map
|
*.js.map
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<name>Template-Joomla</name>
|
<name>Template-Joomla</name>
|
||||||
<org>MokoConsulting</org>
|
<org>MokoConsulting</org>
|
||||||
<description>Template repository for Joomla extensions (plugins, modules, components, templates)</description>
|
<description>Template repository for Joomla extensions (plugins, modules, components, templates)</description>
|
||||||
|
<version>01.01.00</version>
|
||||||
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
||||||
</identity>
|
</identity>
|
||||||
<governance>
|
<governance>
|
||||||
|
|||||||
@@ -1,285 +1,341 @@
|
|||||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: moko-platform.Release
|
# INGROUP: moko-platform.Release
|
||||||
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
|
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
|
||||||
# PATH: /templates/workflows/universal/auto-release.yml.template
|
# PATH: /templates/workflows/universal/auto-release.yml.template
|
||||||
# VERSION: 05.00.00
|
# VERSION: 05.00.00
|
||||||
# BRIEF: Universal build & release � detects platform from manifest.xml
|
# BRIEF: Universal build & release � detects platform from manifest.xml
|
||||||
#
|
#
|
||||||
# +========================================================================+
|
# +========================================================================+
|
||||||
# | UNIVERSAL BUILD & RELEASE PIPELINE |
|
# | UNIVERSAL BUILD & RELEASE PIPELINE |
|
||||||
# +========================================================================+
|
# +========================================================================+
|
||||||
# | |
|
# | |
|
||||||
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
|
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
|
||||||
# | |
|
# | |
|
||||||
# | Platform-specific: |
|
# | Platform-specific: |
|
||||||
# | joomla: XML manifest, updates.xml, type-prefixed packages |
|
# | joomla: XML manifest, type-prefixed packages |
|
||||||
# | dolibarr: mod*.class.php, update.txt, dev version reset |
|
# | dolibarr: mod*.class.php, update.txt, dev version reset |
|
||||||
# | generic: README-only, no update stream |
|
# | generic: README-only, no update stream |
|
||||||
# | |
|
# | |
|
||||||
# +========================================================================+
|
# +========================================================================+
|
||||||
|
|
||||||
name: "Universal: Build & Release"
|
name: "Universal: Build & Release"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, closed]
|
types: [opened, closed]
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
action:
|
action:
|
||||||
description: 'Action to perform'
|
description: 'Action to perform'
|
||||||
required: false
|
required: false
|
||||||
type: choice
|
type: choice
|
||||||
default: release
|
default: release
|
||||||
options:
|
options:
|
||||||
- release
|
- release
|
||||||
- promote-rc
|
- promote-rc
|
||||||
|
|
||||||
env:
|
env:
|
||||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
||||||
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
|
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
|
||||||
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
|
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# ── PR Opened → Rename branch to RC and build RC release ─────────────────────
|
# ── PR Opened → Rename branch to RC and build RC release ─────────────────────
|
||||||
promote-rc:
|
promote-rc:
|
||||||
name: Promote to RC
|
name: Promote to RC
|
||||||
runs-on: release
|
runs-on: release
|
||||||
if: >-
|
if: >-
|
||||||
(github.event.action == 'opened' && github.event.pull_request.merged != true) ||
|
(github.event.action == 'opened' && github.event.pull_request.merged != true) ||
|
||||||
(github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc')
|
(github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc')
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- name: Setup moko-platform tools
|
- name: Setup moko-platform tools
|
||||||
env:
|
env:
|
||||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
||||||
run: |
|
run: |
|
||||||
if ! command -v composer &> /dev/null; then
|
if [ -f /opt/moko-platform/cli/version_bump.php ] && [ -f /opt/moko-platform/vendor/autoload.php ]; then
|
||||||
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
|
echo Using pre-installed /opt/moko-platform
|
||||||
fi
|
echo MOKO_CLI=/opt/moko-platform/cli >> $GITHUB_ENV
|
||||||
# Always fetch latest CLI tools — never use stale cache from previous runs
|
else
|
||||||
rm -rf /tmp/moko-platform-api
|
echo Falling back to fresh clone
|
||||||
git clone --depth 1 --branch main --quiet \
|
if ! command -v composer > /dev/null 2>&1; then
|
||||||
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
|
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
|
||||||
/tmp/moko-platform-api
|
fi
|
||||||
cd /tmp/moko-platform-api
|
rm -rf /tmp/moko-platform-api
|
||||||
composer install --no-dev --no-interaction --quiet
|
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git
|
||||||
|
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/moko-platform-api
|
||||||
- name: Rename branch to rc
|
cd /tmp/moko-platform-api
|
||||||
run: |
|
composer install --no-dev --no-interaction --quiet
|
||||||
php /tmp/moko-platform-api/cli/branch_rename.php \
|
echo MOKO_CLI=/tmp/moko-platform-api/cli >> $GITHUB_ENV
|
||||||
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
|
fi
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
|
||||||
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
|
- name: Rename branch to rc
|
||||||
--pr "${{ github.event.pull_request.number }}"
|
run: |
|
||||||
|
php ${MOKO_CLI}/branch_rename.php \
|
||||||
- name: Checkout rc and configure git
|
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
|
||||||
run: |
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
||||||
git fetch origin rc
|
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
|
||||||
git checkout rc
|
--pr "${{ github.event.pull_request.number }}"
|
||||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
|
||||||
git config --local user.name "gitea-actions[bot]"
|
- name: Checkout rc and configure git
|
||||||
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
run: |
|
||||||
|
git fetch origin rc
|
||||||
- name: Publish RC release
|
git checkout rc
|
||||||
run: |
|
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||||
php /tmp/moko-platform-api/cli/release_publish.php \
|
git config --local user.name "gitea-actions[bot]"
|
||||||
--path . --stability rc --bump minor --branch rc \
|
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
|
||||||
--skip-update-stream
|
- name: Publish RC release
|
||||||
|
run: |
|
||||||
- name: Summary
|
php ${MOKO_CLI}/release_publish.php \
|
||||||
if: always()
|
--path . --stability rc --bump minor --branch rc \
|
||||||
run: |
|
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "Branch renamed to rc, minor bump, RC release built (updates.xml managed by Gitea Pages)" >> $GITHUB_STEP_SUMMARY
|
- name: Summary
|
||||||
|
if: always()
|
||||||
# ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
|
run: |
|
||||||
release:
|
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
|
||||||
name: Build & Release Pipeline
|
echo "Branch renamed to rc, minor bump, RC release built" >> $GITHUB_STEP_SUMMARY
|
||||||
runs-on: release
|
|
||||||
if: >-
|
# ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
|
||||||
github.event.pull_request.merged == true ||
|
release:
|
||||||
(github.event_name == 'workflow_dispatch' && inputs.action != 'promote-rc')
|
name: Build & Release Pipeline
|
||||||
|
runs-on: release
|
||||||
steps:
|
if: >-
|
||||||
- name: Checkout repository
|
github.event.pull_request.merged == true ||
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
(github.event_name == 'workflow_dispatch' && inputs.action != 'promote-rc')
|
||||||
with:
|
|
||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
steps:
|
||||||
fetch-depth: 0
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
- name: Configure git for bot pushes
|
with:
|
||||||
run: |
|
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
fetch-depth: 0
|
||||||
git config --local user.name "gitea-actions[bot]"
|
|
||||||
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
- name: Configure git for bot pushes
|
||||||
|
run: |
|
||||||
- name: Check for merge conflict markers
|
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||||
run: |
|
git config --local user.name "gitea-actions[bot]"
|
||||||
CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
|
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
||||||
if [ -n "$CONFLICTS" ]; then
|
|
||||||
echo "::error::Merge conflict markers found — aborting release"
|
- name: Check for merge conflict markers
|
||||||
echo "## Release Blocked: Conflict Markers" >> $GITHUB_STEP_SUMMARY
|
run: |
|
||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
|
||||||
echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
|
if [ -n "$CONFLICTS" ]; then
|
||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
echo "::error::Merge conflict markers found — aborting release"
|
||||||
exit 1
|
echo "## Release Blocked: Conflict Markers" >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
echo "No conflict markers found"
|
echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
- name: Setup moko-platform tools
|
exit 1
|
||||||
env:
|
fi
|
||||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
echo "No conflict markers found"
|
||||||
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
|
||||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
|
- name: Setup moko-platform tools
|
||||||
run: |
|
env:
|
||||||
# Ensure PHP + Composer are available
|
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
if ! command -v composer &> /dev/null; then
|
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
||||||
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
|
||||||
fi
|
run: |
|
||||||
# Always fetch latest CLI tools — never use stale cache from previous runs
|
if [ -f /opt/moko-platform/cli/version_bump.php ] && [ -f /opt/moko-platform/vendor/autoload.php ]; then
|
||||||
rm -rf /tmp/moko-platform-api
|
echo Using pre-installed /opt/moko-platform
|
||||||
git clone --depth 1 --branch main --quiet \
|
echo MOKO_CLI=/opt/moko-platform/cli >> $GITHUB_ENV
|
||||||
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
|
else
|
||||||
/tmp/moko-platform-api
|
echo Falling back to fresh clone
|
||||||
cd /tmp/moko-platform-api
|
if ! command -v composer > /dev/null 2>&1; then
|
||||||
composer install --no-dev --no-interaction --quiet
|
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
|
||||||
|
fi
|
||||||
|
rm -rf /tmp/moko-platform-api
|
||||||
- name: "Publish stable release"
|
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git
|
||||||
run: |
|
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/moko-platform-api
|
||||||
php /tmp/moko-platform-api/cli/release_publish.php \
|
cd /tmp/moko-platform-api
|
||||||
--path . --stability stable --bump minor --branch main \
|
composer install --no-dev --no-interaction --quiet
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
echo MOKO_CLI=/tmp/moko-platform-api/cli >> $GITHUB_ENV
|
||||||
--skip-update-stream
|
fi
|
||||||
|
|
||||||
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
|
- name: "Determine version bump level"
|
||||||
- name: "Step 9: Mirror release to GitHub"
|
id: bump
|
||||||
if: >-
|
run: |
|
||||||
steps.version.outputs.skip != 'true' &&
|
# Fix/patch branches: version was already bumped by pre-release, just strip suffix
|
||||||
secrets.GH_MIRROR_TOKEN != ''
|
# Feature/dev branches: bump minor for the new stable release
|
||||||
continue-on-error: true
|
HEAD_REF="${{ github.event.pull_request.head.ref || 'dev' }}"
|
||||||
run: |
|
case "$HEAD_REF" in
|
||||||
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
fix/*|patch/*|hotfix/*|bugfix/*) BUMP="none" ;;
|
||||||
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
*) BUMP="minor" ;;
|
||||||
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
esac
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
echo "level=${BUMP}" >> "$GITHUB_OUTPUT"
|
||||||
php /tmp/moko-platform-api/cli/release_mirror.php \
|
echo "Bump level: ${BUMP} (from branch: ${HEAD_REF})"
|
||||||
--version "$VERSION" --tag "$RELEASE_TAG" \
|
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
- name: "Publish stable release"
|
||||||
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
|
run: |
|
||||||
--branch main 2>&1 || true
|
BUMP_FLAG=""
|
||||||
echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
|
if [ "${{ steps.bump.outputs.level }}" != "none" ]; then
|
||||||
|
BUMP_FLAG="--bump ${{ steps.bump.outputs.level }}"
|
||||||
# -- STEP 10: Sync main branch to GitHub mirror ----------------------------
|
fi
|
||||||
- name: "Step 10: Push main to GitHub mirror"
|
php ${MOKO_CLI}/release_publish.php \
|
||||||
if: >-
|
--path . --stability stable ${BUMP_FLAG} --branch main \
|
||||||
steps.version.outputs.skip != 'true' &&
|
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
secrets.GH_MIRROR_TOKEN != ''
|
|
||||||
continue-on-error: true
|
- name: Update release notes from CHANGELOG.md
|
||||||
run: |
|
run: |
|
||||||
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1)
|
|
||||||
GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2)
|
# Extract [Unreleased] section from changelog
|
||||||
git remote add github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \
|
if [ -f "CHANGELOG.md" ]; then
|
||||||
git remote set-url github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git"
|
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
|
||||||
git fetch origin main --depth=1
|
[ -z "$NOTES" ] && NOTES="Stable release"
|
||||||
git push github origin/main:refs/heads/main --force 2>/dev/null \
|
else
|
||||||
&& echo "main branch pushed to GitHub mirror" \
|
NOTES="Stable release"
|
||||||
|| echo "WARNING: GitHub mirror push failed"
|
fi
|
||||||
|
|
||||||
- name: "Step 11: Delete rc branch and recreate dev from main"
|
# Update release body via API
|
||||||
if: steps.version.outputs.skip != 'true'
|
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
|
||||||
continue-on-error: true
|
"${API_BASE}/releases/tags/stable" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||||
run: |
|
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
if [ -n "$RELEASE_ID" ]; then
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
python3 -c "
|
||||||
|
import json, urllib.request
|
||||||
# Delete rc branch (ephemeral — created by promote-rc)
|
body = open('/dev/stdin').read()
|
||||||
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
|
payload = json.dumps({'body': body}).encode()
|
||||||
"${API_BASE}/branches/rc" 2>/dev/null \
|
req = urllib.request.Request(
|
||||||
&& echo "Deleted rc branch" || echo "rc branch not found"
|
'${API_BASE}/releases/${RELEASE_ID}',
|
||||||
|
data=payload, method='PATCH',
|
||||||
# Delete dev branch
|
headers={
|
||||||
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
|
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
|
||||||
"${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch"
|
'Content-Type': 'application/json'
|
||||||
|
})
|
||||||
# Recreate dev from main (now includes version bump + changelog promotion)
|
urllib.request.urlopen(req)
|
||||||
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
|
" <<< "$NOTES"
|
||||||
-H "Content-Type: application/json" \
|
echo "Release notes updated from CHANGELOG.md"
|
||||||
"${API_BASE}/branches" \
|
fi
|
||||||
-d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main"
|
|
||||||
|
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
|
||||||
echo "Pre-release branches cleaned, dev reset from main" >> $GITHUB_STEP_SUMMARY
|
- name: "Step 9: Mirror release to GitHub"
|
||||||
|
if: >-
|
||||||
- name: "Step 12: Create version branch from main"
|
steps.version.outputs.skip != 'true' &&
|
||||||
if: steps.version.outputs.skip != 'true'
|
secrets.GH_MIRROR_TOKEN != ''
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
||||||
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
||||||
BRANCH_NAME="version/${VERSION}"
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
MAIN_SHA=$(git rev-parse HEAD)
|
php ${MOKO_CLI}/release_mirror.php \
|
||||||
|
--version "$VERSION" --tag "$RELEASE_TAG" \
|
||||||
# Delete old version branch if it exists (same version re-release)
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
||||||
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" "${API_BASE}/branches/${BRANCH_NAME}" 2>/dev/null && echo "Deleted old ${BRANCH_NAME}"
|
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
|
||||||
|
--branch main 2>&1 || true
|
||||||
# Create version/XX.YY.ZZ from main
|
echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
|
||||||
curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" "${API_BASE}/branches" -d "{\"new_branch_name\":\"${BRANCH_NAME}\",\"old_branch_name\":\"main\"}" 2>/dev/null && echo "Created ${BRANCH_NAME} from main (${MAIN_SHA})" || echo "WARNING: ${BRANCH_NAME} creation failed"
|
|
||||||
|
# -- STEP 10: Sync main branch to GitHub mirror ----------------------------
|
||||||
echo "Version branch created: ${BRANCH_NAME} (${MAIN_SHA})" >> $GITHUB_STEP_SUMMARY
|
- name: "Step 10: Push main to GitHub mirror"
|
||||||
|
if: >-
|
||||||
|
steps.version.outputs.skip != 'true' &&
|
||||||
|
secrets.GH_MIRROR_TOKEN != ''
|
||||||
# -- Dolibarr post-release: Reset dev version -----------------------------
|
continue-on-error: true
|
||||||
- name: "Post-release: Reset dev version"
|
run: |
|
||||||
if: steps.version.outputs.skip != 'true'
|
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
||||||
continue-on-error: true
|
GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1)
|
||||||
run: |
|
GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2)
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
git remote add github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \
|
||||||
php /tmp/moko-platform-api/cli/version_reset_dev.php \
|
git remote set-url github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git"
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
|
git fetch origin main --depth=1
|
||||||
--branch dev --path . 2>&1 || true
|
git push github origin/main:refs/heads/main --force 2>/dev/null \
|
||||||
|
&& echo "main branch pushed to GitHub mirror" \
|
||||||
# -- Summary --------------------------------------------------------------
|
|| echo "WARNING: GitHub mirror push failed"
|
||||||
- name: Pipeline Summary
|
|
||||||
if: always()
|
- name: "Step 11: Delete rc branch and recreate dev from main"
|
||||||
run: |
|
if: steps.version.outputs.skip != 'true'
|
||||||
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
continue-on-error: true
|
||||||
PLATFORM="${{ steps.platform.outputs.platform }}"
|
run: |
|
||||||
if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
|
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
echo "No VERSION in README.md" >> $GITHUB_STEP_SUMMARY
|
|
||||||
elif [ "${{ steps.check.outputs.already_released }}" = "true" ]; then
|
# Delete rc branch (ephemeral — created by promote-rc)
|
||||||
echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
|
||||||
else
|
"${API_BASE}/branches/rc" 2>/dev/null \
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
&& echo "Deleted rc branch" || echo "rc branch not found"
|
||||||
echo "## Build & Release Complete (${PLATFORM})" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
# Delete dev branch
|
||||||
echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
|
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
|
||||||
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
|
"${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch"
|
||||||
echo "| Platform | \`${PLATFORM}\` |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
# Recreate dev from main (now includes version bump + changelog promotion)
|
||||||
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
|
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
|
||||||
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
|
-H "Content-Type: application/json" \
|
||||||
echo "| Release | [View](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
|
"${API_BASE}/branches" \
|
||||||
fi
|
-d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main"
|
||||||
|
|
||||||
|
echo "Pre-release branches cleaned, dev reset from main" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
- name: "Step 12: Create version branch from main"
|
||||||
|
if: steps.version.outputs.skip != 'true'
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
|
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
||||||
|
BRANCH_NAME="version/${VERSION}"
|
||||||
|
MAIN_SHA=$(git rev-parse HEAD)
|
||||||
|
|
||||||
|
# Delete old version branch if it exists (same version re-release)
|
||||||
|
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" "${API_BASE}/branches/${BRANCH_NAME}" 2>/dev/null && echo "Deleted old ${BRANCH_NAME}"
|
||||||
|
|
||||||
|
# Create version/XX.YY.ZZ from main
|
||||||
|
curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" "${API_BASE}/branches" -d "{\"new_branch_name\":\"${BRANCH_NAME}\",\"old_branch_name\":\"main\"}" 2>/dev/null && echo "Created ${BRANCH_NAME} from main (${MAIN_SHA})" || echo "WARNING: ${BRANCH_NAME} creation failed"
|
||||||
|
|
||||||
|
echo "Version branch created: ${BRANCH_NAME} (${MAIN_SHA})" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -- Dolibarr post-release: Reset dev version -----------------------------
|
||||||
|
- name: "Post-release: Reset dev version"
|
||||||
|
if: steps.version.outputs.skip != 'true'
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
php ${MOKO_CLI}/version_reset_dev.php \
|
||||||
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
|
||||||
|
--branch dev --path . 2>&1 || true
|
||||||
|
|
||||||
|
# -- Summary --------------------------------------------------------------
|
||||||
|
- name: Pipeline Summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
||||||
|
PLATFORM="${{ steps.platform.outputs.platform }}"
|
||||||
|
if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
|
||||||
|
echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "No VERSION in README.md" >> $GITHUB_STEP_SUMMARY
|
||||||
|
elif [ "${{ steps.check.outputs.already_released }}" = "true" ]; then
|
||||||
|
echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "## Build & Release Complete (${PLATFORM})" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Platform | \`${PLATFORM}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Release | [View](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,204 @@
|
|||||||
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# FILE INFORMATION
|
||||||
|
# DEFGROUP: Gitea.Workflow
|
||||||
|
# INGROUP: MokoStandards.CI
|
||||||
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||||
|
# PATH: /.gitea/workflows/ci-generic.yml
|
||||||
|
# VERSION: 01.00.00
|
||||||
|
# BRIEF: CI pipeline — lint, validate, and test for generic projects (PHP + Node.js)
|
||||||
|
|
||||||
|
name: "Generic: Project CI"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- dev
|
||||||
|
- dev/**
|
||||||
|
- rc/**
|
||||||
|
- version/**
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- dev
|
||||||
|
- dev/**
|
||||||
|
- rc/**
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# ── Lint & Validate ───────────────────────────────────────────────────
|
||||||
|
lint:
|
||||||
|
name: Lint & Validate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Detect toolchain
|
||||||
|
id: detect
|
||||||
|
run: |
|
||||||
|
HAS_PHP=false
|
||||||
|
HAS_NODE=false
|
||||||
|
[ -f "composer.json" ] && HAS_PHP=true
|
||||||
|
[ -f "package.json" ] && HAS_NODE=true
|
||||||
|
echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Toolchain: PHP=$HAS_PHP Node=$HAS_NODE"
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if ! command -v php &> /dev/null; then
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
php -v
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install PHP dependencies
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "composer.json" ]; then
|
||||||
|
composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install Node.js dependencies
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "package.json" ]; then
|
||||||
|
npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: PHP syntax check
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
ERRORS=0
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
|
||||||
|
echo "::error file=${file}::PHP syntax error"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -not -path "./node_modules/*" -print0)
|
||||||
|
|
||||||
|
echo "## PHP Lint" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "$ERRORS" -eq 0 ]; then
|
||||||
|
echo "All PHP files passed syntax check." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "${ERRORS} file(s) with syntax errors." >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: TypeScript/JavaScript lint
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "node_modules/.bin/eslint" ]; then
|
||||||
|
npx eslint src/ --quiet 2>&1 || { echo "::error::ESLint errors found"; exit 1; }
|
||||||
|
echo "## ESLint" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "All files passed ESLint." >> $GITHUB_STEP_SUMMARY
|
||||||
|
elif [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f "eslint.config.js" ]; then
|
||||||
|
echo "::warning::ESLint config found but eslint not installed"
|
||||||
|
else
|
||||||
|
echo "No ESLint configured — skipping"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: TypeScript compile check
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "tsconfig.json" ] && [ -f "node_modules/.bin/tsc" ]; then
|
||||||
|
npx tsc --noEmit 2>&1 || { echo "::error::TypeScript compilation errors"; exit 1; }
|
||||||
|
echo "## TypeScript" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "TypeScript compilation passed." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: PHPStan static analysis
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "phpstan.neon" ] && [ -f "vendor/bin/phpstan" ]; then
|
||||||
|
vendor/bin/phpstan analyse --no-progress 2>&1 || { echo "::warning::PHPStan found issues"; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Tests ─────────────────────────────────────────────────────────────
|
||||||
|
test:
|
||||||
|
name: Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: lint
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Detect toolchain
|
||||||
|
id: detect
|
||||||
|
run: |
|
||||||
|
HAS_PHP=false
|
||||||
|
HAS_NODE=false
|
||||||
|
[ -f "composer.json" ] && HAS_PHP=true
|
||||||
|
[ -f "package.json" ] && HAS_NODE=true
|
||||||
|
echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if ! command -v php &> /dev/null; then
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
[ -f "composer.json" ] && composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
|
||||||
|
[ -f "package.json" ] && { npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true; }
|
||||||
|
|
||||||
|
- name: Run PHP tests
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "vendor/bin/phpunit" ]; then
|
||||||
|
vendor/bin/phpunit --testdox 2>&1
|
||||||
|
echo "## PHPUnit" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Tests passed." >> $GITHUB_STEP_SUMMARY
|
||||||
|
elif [ -f "phpunit.xml" ] || [ -f "phpunit.xml.dist" ]; then
|
||||||
|
echo "::warning::PHPUnit config found but phpunit not installed"
|
||||||
|
else
|
||||||
|
echo "No PHPUnit configured — skipping"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run Node.js tests
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
run: |
|
||||||
|
if jq -e '.scripts.test' package.json > /dev/null 2>&1; then
|
||||||
|
npm test 2>&1
|
||||||
|
echo "## Node.js Tests" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Tests passed." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "No test script in package.json — skipping"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build check
|
||||||
|
run: |
|
||||||
|
if [ -f "Makefile" ]; then
|
||||||
|
make build 2>&1 || echo "::warning::Build failed or not configured"
|
||||||
|
elif [ -f "package.json" ] && jq -e '.scripts.build' package.json > /dev/null 2>&1; then
|
||||||
|
npm run build 2>&1 || echo "::warning::Build failed"
|
||||||
|
fi
|
||||||
@@ -245,10 +245,413 @@ jobs:
|
|||||||
echo "All ${CHECKED} directories contain index.html." >> $GITHUB_STEP_SUMMARY
|
echo "All ${CHECKED} directories contain index.html." >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Check config.xml and access.xml for components
|
||||||
|
run: |
|
||||||
|
echo "### Component Config & ACL Check" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
# Find all component manifests (XML with type="component")
|
||||||
|
COMP_MANIFESTS=$(find . -maxdepth 4 -name "*.xml" -not -path "./.git/*" -not -path "./vendor/*" -exec grep -l '<extension[^>]*type="component"' {} ; 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -z "$COMP_MANIFESTS" ]; then
|
||||||
|
echo "No component extensions found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
for MANIFEST in $COMP_MANIFESTS; do
|
||||||
|
COMP_DIR=$(dirname "$MANIFEST")
|
||||||
|
COMP_NAME=$(basename "$COMP_DIR")
|
||||||
|
echo "Component: `${COMP_NAME}` (manifest: `${MANIFEST}`)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Check access.xml exists
|
||||||
|
ACCESS_FILE=$(find "$COMP_DIR" -name "access.xml" -not -path "./.git/*" 2>/dev/null | head -1)
|
||||||
|
if [ -z "$ACCESS_FILE" ]; then
|
||||||
|
echo "- Missing `access.xml` — ACL permissions will not work." >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
if command -v php &> /dev/null; then
|
||||||
|
if ! php -r "@simplexml_load_file('$ACCESS_FILE') ?: exit(1);" 2>/dev/null; then
|
||||||
|
echo "- `access.xml` is not well-formed XML." >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
for ACTION in core.admin core.manage; do
|
||||||
|
if ! grep -q "name=\"${ACTION}\"" "$ACCESS_FILE" 2>/dev/null; then
|
||||||
|
echo "- `access.xml` missing required action: `${ACTION}`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "- `access.xml`: valid" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check config.xml exists
|
||||||
|
CONFIG_FILE=$(find "$COMP_DIR" -name "config.xml" -not -path "./.git/*" 2>/dev/null | head -1)
|
||||||
|
if [ -z "$CONFIG_FILE" ]; then
|
||||||
|
echo "- Missing `config.xml` — component Options page will be empty." >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
if command -v php &> /dev/null; then
|
||||||
|
if ! php -r "@simplexml_load_file('$CONFIG_FILE') ?: exit(1);" 2>/dev/null; then
|
||||||
|
echo "- `config.xml` is not well-formed XML." >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
echo "- `config.xml`: valid" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "${ERRORS}" -gt 0 ]; then
|
||||||
|
echo "**${ERRORS} config/ACL issue(s) found.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "**Component config & ACL check passed.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: SQL schema validation
|
||||||
|
run: |
|
||||||
|
echo "### SQL Schema Validation" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
# Find SQL files in source/htdocs
|
||||||
|
SQL_FILES=$(find . -name "*.sql" -path "*/sql/*" -not -path "./.git/*" -not -path "./vendor/*" 2>/dev/null)
|
||||||
|
if [ -z "$SQL_FILES" ]; then
|
||||||
|
echo "No SQL files found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "Found $(echo "$SQL_FILES" | wc -l) SQL file(s)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
for FILE in $SQL_FILES; do
|
||||||
|
# Basic syntax check: balanced parentheses, no empty files
|
||||||
|
SIZE=$(wc -c < "$FILE" | tr -d ' ')
|
||||||
|
if [ "$SIZE" -eq 0 ]; then
|
||||||
|
echo "- Empty SQL file: \`${FILE}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for common SQL errors
|
||||||
|
if grep -qP '^\s*$' "$FILE" && [ "$SIZE" -lt 5 ]; then
|
||||||
|
echo "- Whitespace-only SQL file: \`${FILE}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "- \`${FILE}\`: ${SIZE} bytes" >> $GITHUB_STEP_SUMMARY
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check update SQL files follow version numbering pattern
|
||||||
|
UPDATE_DIR=$(find . -path "*/sql/updates/mysql" -type d -not -path "./.git/*" 2>/dev/null | head -1)
|
||||||
|
if [ -n "$UPDATE_DIR" ]; then
|
||||||
|
BAD_NAMES=0
|
||||||
|
for UFILE in "$UPDATE_DIR"/*.sql; do
|
||||||
|
[ ! -f "$UFILE" ] && continue
|
||||||
|
BASENAME=$(basename "$UFILE" .sql)
|
||||||
|
if ! echo "$BASENAME" | grep -qP '^\d+\.\d+\.\d+'; then
|
||||||
|
echo "- Update file \`${UFILE}\` does not follow version naming (expected X.Y.Z.sql)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
BAD_NAMES=$((BAD_NAMES + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$BAD_NAMES" -gt 0 ]; then
|
||||||
|
ERRORS=$((ERRORS + BAD_NAMES))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "${ERRORS}" -gt 0 ]; then
|
||||||
|
echo "**${ERRORS} SQL issue(s) found.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "**SQL schema validation passed.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Manifest file references check
|
||||||
|
run: |
|
||||||
|
echo "### Manifest File References" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
MANIFEST=""
|
||||||
|
for XML_FILE in $(find . -maxdepth 2 -name "*.xml" -not -path "./.git/*" -not -path "./vendor/*"); do
|
||||||
|
if grep -q "<extension" "$XML_FILE" 2>/dev/null; then
|
||||||
|
MANIFEST="$XML_FILE"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$MANIFEST" ]; then
|
||||||
|
echo "No manifest found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
MANIFEST_DIR=$(dirname "$MANIFEST")
|
||||||
|
|
||||||
|
# Check <filename> references
|
||||||
|
FILENAMES=$(grep -oP '<filename[^>]*>\K[^<]+' "$MANIFEST" 2>/dev/null || true)
|
||||||
|
for F in $FILENAMES; do
|
||||||
|
if [ ! -f "${MANIFEST_DIR}/${F}" ] && [ ! -d "${MANIFEST_DIR}/${F}" ]; then
|
||||||
|
echo "- Missing: \`${F}\` (referenced in manifest)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check <folder> references
|
||||||
|
FOLDERS=$(grep -oP '<folder[^>]*>\K[^<]+' "$MANIFEST" 2>/dev/null || true)
|
||||||
|
for F in $FOLDERS; do
|
||||||
|
if [ ! -d "${MANIFEST_DIR}/${F}" ]; then
|
||||||
|
echo "- Missing folder: \`${F}\` (referenced in manifest)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check <file> references in package manifests (ZIP files won't exist in source)
|
||||||
|
EXT_TYPE=$(grep -oP '<extension[^>]*\btype="\K[^"]+' "$MANIFEST" | head -1)
|
||||||
|
if [ "$EXT_TYPE" != "package" ]; then
|
||||||
|
FILES=$(grep -oP '<file[^>]*>\K[^<]+' "$MANIFEST" 2>/dev/null || true)
|
||||||
|
for F in $FILES; do
|
||||||
|
if [ ! -f "${MANIFEST_DIR}/${F}" ]; then
|
||||||
|
echo "- Missing file: \`${F}\` (referenced in manifest)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "${ERRORS}" -gt 0 ]; then
|
||||||
|
echo "**${ERRORS} missing file reference(s).**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "**Manifest file references check passed.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Form XML validation
|
||||||
|
run: |
|
||||||
|
echo "### Form XML Validation" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
FORM_FILES=$(find . -name "*.xml" -path "*/forms/*" -not -path "./.git/*" -not -path "./vendor/*" 2>/dev/null)
|
||||||
|
if [ -z "$FORM_FILES" ]; then
|
||||||
|
echo "No form XML files found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "Found $(echo "$FORM_FILES" | wc -l) form file(s)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
for FILE in $FORM_FILES; do
|
||||||
|
if command -v php &> /dev/null; then
|
||||||
|
if ! php -r "@simplexml_load_file('$FILE') ?: exit(1);" 2>/dev/null; then
|
||||||
|
echo "- \`${FILE}\`: malformed XML" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
# Check for valid Joomla form structure
|
||||||
|
if ! grep -qE '<form|<field|<fieldset' "$FILE" 2>/dev/null; then
|
||||||
|
echo "- \`${FILE}\`: no \`<form>\`, \`<field>\`, or \`<fieldset>\` elements found" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
echo "- \`${FILE}\`: valid" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "${ERRORS}" -gt 0 ]; then
|
||||||
|
echo "**${ERRORS} form XML issue(s).**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "**Form XML validation passed.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Deprecated Joomla API check
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "### Deprecated Joomla API Check" >> $GITHUB_STEP_SUMMARY
|
||||||
|
WARNINGS=0
|
||||||
|
|
||||||
|
SRC_DIR=""
|
||||||
|
for DIR in source/ src/ htdocs/; do
|
||||||
|
[ -d "$DIR" ] && SRC_DIR="$DIR" && break
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$SRC_DIR" ]; then
|
||||||
|
echo "No source directory found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
# Joomla 3/4 deprecated patterns that break in Joomla 6
|
||||||
|
PATTERNS=(
|
||||||
|
'JFactory::'
|
||||||
|
'JText::'
|
||||||
|
'JHtml::'
|
||||||
|
'JRoute::'
|
||||||
|
'JUri::'
|
||||||
|
'JLog::'
|
||||||
|
'JTable::'
|
||||||
|
'JInput'
|
||||||
|
'CMSFactory::\$application'
|
||||||
|
'JApplicationCms'
|
||||||
|
)
|
||||||
|
|
||||||
|
for PATTERN in "${PATTERNS[@]}"; do
|
||||||
|
HITS=$(grep -rnl "$PATTERN" "$SRC_DIR" --include="*.php" 2>/dev/null || true)
|
||||||
|
if [ -n "$HITS" ]; then
|
||||||
|
COUNT=$(echo "$HITS" | wc -l)
|
||||||
|
echo "- \`${PATTERN}\` found in ${COUNT} file(s)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
WARNINGS=$((WARNINGS + COUNT))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "$WARNINGS" -gt 0 ]; then
|
||||||
|
echo "**${WARNINGS} deprecated API usage(s) found.** These will break in Joomla 6." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "**No deprecated APIs found.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Template output escaping check
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "### Template Output Escaping" >> $GITHUB_STEP_SUMMARY
|
||||||
|
WARNINGS=0
|
||||||
|
|
||||||
|
TMPL_FILES=$(find . -name "*.php" -path "*/tmpl/*" -not -path "./.git/*" -not -path "./vendor/*" 2>/dev/null)
|
||||||
|
if [ -z "$TMPL_FILES" ]; then
|
||||||
|
echo "No template files found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "Found $(echo "$TMPL_FILES" | wc -l) template file(s)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
for FILE in $TMPL_FILES; do
|
||||||
|
# Check for unescaped output: <?= $var ?> or echo $var without escape()
|
||||||
|
UNESCAPED=$(grep -nP '<\?=\s*\$(?!this->escape)' "$FILE" 2>/dev/null || true)
|
||||||
|
if [ -n "$UNESCAPED" ]; then
|
||||||
|
HITS=$(echo "$UNESCAPED" | wc -l)
|
||||||
|
echo "- \`${FILE}\`: ${HITS} unescaped \`<?= \$var ?>\` output(s) — use \`<?= \$this->escape(\$var) ?>\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
WARNINGS=$((WARNINGS + HITS))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for echo without escaping in template context
|
||||||
|
RAW_ECHO=$(grep -nP '^\s*echo\s+\$(?!this->escape)' "$FILE" 2>/dev/null || true)
|
||||||
|
if [ -n "$RAW_ECHO" ]; then
|
||||||
|
HITS=$(echo "$RAW_ECHO" | wc -l)
|
||||||
|
echo "- \`${FILE}\`: ${HITS} raw \`echo \$var\` — consider \`echo \$this->escape(\$var)\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
WARNINGS=$((WARNINGS + HITS))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "$WARNINGS" -gt 0 ]; then
|
||||||
|
echo "**${WARNINGS} potential XSS risk(s) in templates.** Review unescaped output." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "**All template output appears properly escaped.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Namespace consistency check
|
||||||
|
run: |
|
||||||
|
echo "### Namespace Consistency" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
# Find component/plugin manifests with <namespace> tags
|
||||||
|
MANIFESTS=$(find . -maxdepth 4 -name "*.xml" -not -path "./.git/*" -not -path "./vendor/*" -exec grep -l '<namespace' {} \; 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -z "$MANIFESTS" ]; then
|
||||||
|
echo "No manifests with \`<namespace>\` found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
for MANIFEST in $MANIFESTS; do
|
||||||
|
NS_PATH=$(grep -oP '<namespace[^>]*>\K[^<]+' "$MANIFEST" 2>/dev/null | head -1)
|
||||||
|
[ -z "$NS_PATH" ] && continue
|
||||||
|
MANIFEST_DIR=$(dirname "$MANIFEST")
|
||||||
|
|
||||||
|
echo "Manifest: \`${MANIFEST}\` → namespace \`${NS_PATH}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Check PHP files have matching namespace
|
||||||
|
while IFS= read -r -d '' PHP_FILE; do
|
||||||
|
FILE_NS=$(grep -oP '^\s*namespace\s+\K[^;]+' "$PHP_FILE" 2>/dev/null | head -1)
|
||||||
|
[ -z "$FILE_NS" ] && continue
|
||||||
|
|
||||||
|
# Namespace should start with the manifest namespace path
|
||||||
|
if ! echo "$FILE_NS" | grep -qF "${NS_PATH}"; then
|
||||||
|
echo "- \`${PHP_FILE}\`: namespace \`${FILE_NS}\` doesn't match manifest \`${NS_PATH}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done < <(find "$MANIFEST_DIR" -name "*.php" -path "*/src/*" -not -path "./vendor/*" -print0 2>/dev/null)
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "${ERRORS}" -gt 0 ]; then
|
||||||
|
echo "**${ERRORS} namespace mismatch(es).**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "**Namespace consistency check passed.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: SPDX license header check
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "### SPDX License Headers" >> $GITHUB_STEP_SUMMARY
|
||||||
|
MISSING=0
|
||||||
|
|
||||||
|
SRC_DIR=""
|
||||||
|
for DIR in source/ src/ htdocs/; do
|
||||||
|
[ -d "$DIR" ] && SRC_DIR="$DIR" && break
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$SRC_DIR" ]; then
|
||||||
|
echo "No source directory found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
TOTAL=0
|
||||||
|
while IFS= read -r -d '' FILE; do
|
||||||
|
TOTAL=$((TOTAL + 1))
|
||||||
|
if ! head -10 "$FILE" | grep -qi "SPDX"; then
|
||||||
|
echo "- Missing SPDX header: \`${FILE}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
MISSING=$((MISSING + 1))
|
||||||
|
fi
|
||||||
|
done < <(find "$SRC_DIR" -name "*.php" -not -path "./vendor/*" -print0)
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "$MISSING" -gt 0 ]; then
|
||||||
|
echo "**${MISSING}/${TOTAL} PHP file(s) missing SPDX license header.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "**All ${TOTAL} PHP files have SPDX headers.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Service provider check
|
||||||
|
run: |
|
||||||
|
echo "### Service Provider Check" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
PROVIDERS=$(find . -name "provider.php" -path "*/services/*" -not -path "./.git/*" -not -path "./vendor/*" 2>/dev/null)
|
||||||
|
if [ -z "$PROVIDERS" ]; then
|
||||||
|
echo "No service providers found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
for FILE in $PROVIDERS; do
|
||||||
|
# Must return a ServiceProviderInterface
|
||||||
|
if ! grep -qP 'ServiceProviderInterface|ComponentInterface|MVCFactoryInterface|DispatcherInterface' "$FILE" 2>/dev/null; then
|
||||||
|
echo "- \`${FILE}\`: does not reference ServiceProviderInterface or component interfaces" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
echo "- \`${FILE}\`: valid service provider" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Must have return statement
|
||||||
|
if ! grep -qP '^\s*return\s+new\s+' "$FILE" 2>/dev/null; then
|
||||||
|
echo "- \`${FILE}\`: missing \`return new ...\` statement" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "${ERRORS}" -gt 0 ]; then
|
||||||
|
echo "**${ERRORS} service provider issue(s).**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "**Service provider check passed.**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
release-readiness:
|
release-readiness:
|
||||||
name: Release Readiness Check
|
name: Release Readiness Check
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name == 'pull_request' && github.base_ref == 'main'
|
if: github.event_name == 'pull_request' && github.base_ref == 'main'
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# FILE INFORMATION
|
||||||
|
# DEFGROUP: Gitea.Workflow
|
||||||
|
# INGROUP: MokoStandards.Deploy
|
||||||
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-API
|
||||||
|
# PATH: /templates/workflows/joomla/deploy-manual.yml.template
|
||||||
|
# VERSION: 04.07.00
|
||||||
|
# BRIEF: Manual SFTP deploy to dev server for Joomla repos
|
||||||
|
|
||||||
|
name: "Universal: Deploy to Dev (Manual)"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
clear_remote:
|
||||||
|
description: 'Delete all remote files before uploading'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
name: SFTP Deploy to Dev
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
run: |
|
||||||
|
php -v && composer --version
|
||||||
|
|
||||||
|
- name: Setup MokoStandards tools
|
||||||
|
env:
|
||||||
|
GA_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
|
||||||
|
MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
|
||||||
|
MOKO_CLONE_HOST: ${{ secrets.GA_TOKEN && 'git.mokoconsulting.tech/MokoConsulting' || 'github.com/mokoconsulting-tech' }}
|
||||||
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GA_TOKEN || github.token }}"}}'
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 --branch main --quiet \
|
||||||
|
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \
|
||||||
|
/tmp/mokostandards-api 2>/dev/null || true
|
||||||
|
if [ -d "/tmp/mokostandards-api" ] && [ -f "/tmp/mokostandards-api/composer.json" ]; then
|
||||||
|
cd /tmp/mokostandards-api && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Check FTP configuration
|
||||||
|
id: check
|
||||||
|
env:
|
||||||
|
HOST: ${{ vars.DEV_FTP_HOST }}
|
||||||
|
PATH_VAR: ${{ vars.DEV_FTP_PATH }}
|
||||||
|
PORT: ${{ vars.DEV_FTP_PORT }}
|
||||||
|
run: |
|
||||||
|
if [ -z "$HOST" ] || [ -z "$PATH_VAR" ]; then
|
||||||
|
echo "DEV_FTP_HOST or DEV_FTP_PATH not configured -- cannot deploy"
|
||||||
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "host=$HOST" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
REMOTE="${PATH_VAR%/}"
|
||||||
|
echo "remote=$REMOTE" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
[ -z "$PORT" ] && PORT="22"
|
||||||
|
echo "port=$PORT" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Deploy via SFTP
|
||||||
|
if: steps.check.outputs.skip != 'true'
|
||||||
|
env:
|
||||||
|
SFTP_KEY: ${{ secrets.DEV_FTP_KEY }}
|
||||||
|
SFTP_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
|
||||||
|
SFTP_USER: ${{ vars.DEV_FTP_USERNAME }}
|
||||||
|
run: |
|
||||||
|
SOURCE_DIR="src"
|
||||||
|
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
||||||
|
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ -- nothing to deploy"; exit 0; }
|
||||||
|
|
||||||
|
printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \
|
||||||
|
"${{ steps.check.outputs.host }}" "${{ steps.check.outputs.port }}" "$SFTP_USER" "${{ steps.check.outputs.remote }}" \
|
||||||
|
> /tmp/sftp-config.json
|
||||||
|
|
||||||
|
if [ -n "$SFTP_KEY" ]; then
|
||||||
|
echo "$SFTP_KEY" > /tmp/deploy_key
|
||||||
|
chmod 600 /tmp/deploy_key
|
||||||
|
printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json
|
||||||
|
else
|
||||||
|
printf ',"password":"%s"}' "$SFTP_PASS" >> /tmp/sftp-config.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEPLOY_ARGS=(--path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json)
|
||||||
|
[ "${{ inputs.clear_remote }}" = "true" ] && DEPLOY_ARGS+=(--clear-remote)
|
||||||
|
|
||||||
|
PLATFORM=$(php /tmp/mokostandards-api/cli/platform_detect.php --path . 2>/dev/null || true)
|
||||||
|
if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards-api/deploy/deploy-joomla.php" ]; then
|
||||||
|
php /tmp/mokostandards-api/deploy/deploy-joomla.php "${DEPLOY_ARGS[@]}"
|
||||||
|
else
|
||||||
|
php /tmp/mokostandards-api/deploy/deploy-sftp.php "${DEPLOY_ARGS[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/deploy_key /tmp/sftp-config.json
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
if [ "${{ steps.check.outputs.skip }}" = "true" ]; then
|
||||||
|
echo "### Deploy Skipped -- FTP not configured" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "### Manual Dev Deploy Complete" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Host | \`${{ steps.check.outputs.host }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Remote | \`${{ steps.check.outputs.remote }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Clear | ${{ inputs.clear_remote }} |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
@@ -18,7 +18,6 @@ on:
|
|||||||
- "Joomla Build & Release"
|
- "Joomla Build & Release"
|
||||||
- "Joomla Extension CI"
|
- "Joomla Extension CI"
|
||||||
- "Deploy"
|
- "Deploy"
|
||||||
- "Cascade Main → Dev"
|
|
||||||
types:
|
types:
|
||||||
- completed
|
- completed
|
||||||
|
|
||||||
|
|||||||
@@ -8,234 +8,4 @@
|
|||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
|
||||||
# PATH: /templates/workflows/universal/pre-release.yml.template
|
# PATH: /templates/workflows/universal/pre-release.yml.template
|
||||||
# VERSION: 05.01.00
|
# VERSION: 05.01.00
|
||||||
# BRIEF: Manual pre-release -- builds dev/alpha/beta/rc packages from any branch
|
# BRIEF: Auto pre-release on push to dev/alpha/beta/rc branches
|
||||||
|
|
||||||
name: "Universal: Pre-Release"
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [closed]
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
pull_request_target:
|
|
||||||
types: [synchronize, opened, reopened]
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
stability:
|
|
||||||
description: 'Pre-release channel'
|
|
||||||
required: true
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- development
|
|
||||||
- alpha
|
|
||||||
- beta
|
|
||||||
- release-candidate
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
|
||||||
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
|
|
||||||
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: "Build Pre-Release (${{ inputs.stability || 'development' }})"
|
|
||||||
runs-on: release
|
|
||||||
if: >-
|
|
||||||
github.event_name == 'workflow_dispatch' ||
|
|
||||||
(github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev') ||
|
|
||||||
(github.event_name == 'pull_request_target' && github.event.pull_request.base.ref == 'main')
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
|
||||||
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || '' }}
|
|
||||||
|
|
||||||
- name: Setup moko-platform tools
|
|
||||||
env:
|
|
||||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
|
||||||
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
|
||||||
run: |
|
|
||||||
# Use pre-installed /opt/moko-platform if available (updated by cron every 6h)
|
|
||||||
if [ -f “/opt/moko-platform/cli/version_bump.php” ] && [ -f “/opt/moko-platform/vendor/autoload.php” ]; then
|
|
||||||
echo “Using pre-installed /opt/moko-platform”
|
|
||||||
echo “MOKO_CLI=/opt/moko-platform/cli” >> “$GITHUB_ENV”
|
|
||||||
else
|
|
||||||
echo “Falling back to fresh clone”
|
|
||||||
if ! command -v composer &> /dev/null; then
|
|
||||||
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
rm -rf /tmp/moko-platform-api
|
|
||||||
git clone --depth 1 --branch main --quiet \
|
|
||||||
“https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git” \
|
|
||||||
/tmp/moko-platform-api
|
|
||||||
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
|
|
||||||
echo “MOKO_CLI=/tmp/moko-platform-api/cli” >> “$GITHUB_ENV”
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Detect platform
|
|
||||||
id: platform
|
|
||||||
run: |
|
|
||||||
php ${MOKO_CLI}/manifest_read.php --path . --github-output
|
|
||||||
|
|
||||||
- name: Resolve metadata and bump version
|
|
||||||
id: meta
|
|
||||||
run: |
|
|
||||||
# Auto-detect stability: RC for PRs targeting main, else use input or default to development
|
|
||||||
if [ "${{ github.event_name }}" = "pull_request_target" ] && [ "${{ github.event.pull_request.base.ref }}" = "main" ]; then
|
|
||||||
STABILITY="release-candidate"
|
|
||||||
else
|
|
||||||
STABILITY="${{ inputs.stability || 'development' }}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$STABILITY" in
|
|
||||||
development) SUFFIX="-dev"; TAG="development" ;;
|
|
||||||
alpha) SUFFIX="-alpha"; TAG="alpha" ;;
|
|
||||||
beta) SUFFIX="-beta"; TAG="beta" ;;
|
|
||||||
release-candidate) SUFFIX="-rc"; TAG="release-candidate" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Bump version via CLI: patch for dev/alpha/beta, minor for RC
|
|
||||||
case "$STABILITY" in
|
|
||||||
release-candidate) BUMP="minor" ;;
|
|
||||||
*) BUMP="patch" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
php ${MOKO_CLI}/version_bump.php --path . $([ "$BUMP" = "minor" ] && echo "--minor") 2>/dev/null || true
|
|
||||||
|
|
||||||
# Set stability suffix and verify consistency
|
|
||||||
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "00.00.01")
|
|
||||||
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
|
|
||||||
|
|
||||||
php ${MOKO_CLI}/version_set_platform.php \
|
|
||||||
--path . --version "$VERSION" --branch "${{ github.ref_name }}" --stability "$STABILITY" 2>/dev/null || true
|
|
||||||
php ${MOKO_CLI}/version_check.php --path . --fix 2>/dev/null || true
|
|
||||||
|
|
||||||
# Append suffix for output
|
|
||||||
if [ -n "$SUFFIX" ]; then
|
|
||||||
VERSION="${VERSION}${SUFFIX}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Commit version bump
|
|
||||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
|
||||||
git config --local user.name "gitea-actions[bot]"
|
|
||||||
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
|
||||||
git add -A
|
|
||||||
git diff --cached --quiet || {
|
|
||||||
git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]"
|
|
||||||
git push origin HEAD 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Auto-detect element via manifest_element.php
|
|
||||||
php ${MOKO_CLI}/manifest_element.php \
|
|
||||||
--path . --version "$VERSION" --stability "$STABILITY" \
|
|
||||||
--repo "${GITEA_REPO}" --github-output
|
|
||||||
|
|
||||||
# Read back element outputs
|
|
||||||
EXT_ELEMENT=$(grep '^ext_element=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2)
|
|
||||||
ZIP_NAME=$(grep '^zip_name=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2)
|
|
||||||
[ -z "$EXT_ELEMENT" ] && EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
|
|
||||||
[ -z "$ZIP_NAME" ] && ZIP_NAME="${EXT_ELEMENT}-${VERSION}.zip"
|
|
||||||
|
|
||||||
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "zip_name=${ZIP_NAME}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "ext_element=${EXT_ELEMENT}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
echo "=== Pre-Release: ${EXT_ELEMENT} ${VERSION}${SUFFIX} ==="
|
|
||||||
|
|
||||||
- name: Create release
|
|
||||||
id: release
|
|
||||||
run: |
|
|
||||||
TAG="${{ steps.meta.outputs.tag }}"
|
|
||||||
VERSION="${{ steps.meta.outputs.version }}"
|
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
||||||
php ${MOKO_CLI}/release_create.php \
|
|
||||||
--path . --version "$VERSION" --tag "$TAG" \
|
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
|
||||||
--repo "${GITEA_REPO}" --branch dev --prerelease
|
|
||||||
|
|
||||||
- name: Update release notes from CHANGELOG.md
|
|
||||||
run: |
|
|
||||||
TAG="${{ steps.meta.outputs.tag }}"
|
|
||||||
VERSION="${{ steps.meta.outputs.version }}"
|
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
||||||
|
|
||||||
# Extract [Unreleased] section from changelog (everything between [Unreleased] and next ## heading)
|
|
||||||
if [ -f "CHANGELOG.md" ]; then
|
|
||||||
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
|
|
||||||
[ -z "$NOTES" ] && NOTES="Release ${VERSION}"
|
|
||||||
else
|
|
||||||
NOTES="Release ${VERSION}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update release body via API
|
|
||||||
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
|
|
||||||
"${API_BASE}/releases/tags/${TAG}" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
|
||||||
|
|
||||||
if [ -n "$RELEASE_ID" ]; then
|
|
||||||
python3 -c "
|
|
||||||
import json, urllib.request
|
|
||||||
body = open('/dev/stdin').read()
|
|
||||||
payload = json.dumps({'body': body}).encode()
|
|
||||||
req = urllib.request.Request(
|
|
||||||
'${API_BASE}/releases/${RELEASE_ID}',
|
|
||||||
data=payload, method='PATCH',
|
|
||||||
headers={
|
|
||||||
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
})
|
|
||||||
urllib.request.urlopen(req)
|
|
||||||
" <<< "$NOTES"
|
|
||||||
echo "Release notes updated from CHANGELOG.md"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build package and upload
|
|
||||||
id: package
|
|
||||||
run: |
|
|
||||||
VERSION="${{ steps.meta.outputs.version }}"
|
|
||||||
TAG="${{ steps.meta.outputs.tag }}"
|
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
||||||
php ${MOKO_CLI}/release_package.php \
|
|
||||||
--path . --version "$VERSION" --tag "$TAG" \
|
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
|
||||||
--repo "${GITEA_REPO}" --output /tmp || true
|
|
||||||
|
|
||||||
# updates.xml is generated dynamically by MokoGitea license server
|
|
||||||
# No need to build, commit, or sync updates.xml from workflows
|
|
||||||
|
|
||||||
- name: "Delete lesser pre-release channels (cascade)"
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
|
||||||
|
|
||||||
php ${MOKO_CLI}/release_cascade.php \
|
|
||||||
--stability "${{ steps.meta.outputs.stability }}" \
|
|
||||||
--token "${TOKEN}" \
|
|
||||||
--api-base "${API_BASE}"
|
|
||||||
|
|
||||||
- name: Summary
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
VERSION="${{ steps.meta.outputs.version }}"
|
|
||||||
STABILITY="${{ steps.meta.outputs.stability }}"
|
|
||||||
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
|
|
||||||
SHA256="${{ steps.package.outputs.sha256_zip }}"
|
|
||||||
echo "## Pre-Release Complete" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Channel | ${STABILITY} |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Package | \`${ZIP_NAME}\` |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| SHA-256 | \`${SHA256:-n/a}\` |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
## [Unreleased]
|
## [01.00.00] --- 2026-06-03
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Migrated all workflow and template paths from `.github/` to `.mokogitea/`
|
- Migrated all workflow and template paths from `.github/` to `.mokogitea/`
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
DEFGROUP: MokoStandards-Template-Joomla-Plugin
|
DEFGROUP: MokoStandards-Template-Joomla-Plugin
|
||||||
INGROUP: MokoStandards-Template-Joomla-Plugin.Documentation
|
INGROUP: MokoStandards-Template-Joomla-Plugin.Documentation
|
||||||
REPO: https://github.com/mokoconsulting-tech/MokoStandards-Template-Joomla-Plugin/
|
REPO: https://github.com/mokoconsulting-tech/MokoStandards-Template-Joomla-Plugin/
|
||||||
VERSION: 01.00.00
|
VERSION: 01.01.00
|
||||||
PATH: ./CODE_OF_CONDUCT.md
|
PATH: ./CODE_OF_CONDUCT.md
|
||||||
BRIEF: Community expectations and enforcement guidelines
|
BRIEF: Community expectations and enforcement guidelines
|
||||||
NOTE: Adapted with attribution from the Contributor Covenant v2.1
|
NOTE: Adapted with attribution from the Contributor Covenant v2.1
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
DEFGROUP: mokoconsulting-tech.MokoStandards-Template-Joomla-Plugin
|
DEFGROUP: mokoconsulting-tech.MokoStandards-Template-Joomla-Plugin
|
||||||
INGROUP: MokoStandards.Governance
|
INGROUP: MokoStandards.Governance
|
||||||
REPO: https://github.com/mokoconsulting-tech/MokoStandards-Template-Joomla-Plugin
|
REPO: https://github.com/mokoconsulting-tech/MokoStandards-Template-Joomla-Plugin
|
||||||
VERSION: 04.00.04
|
VERSION: 01.01.00
|
||||||
PATH: /GOVERNANCE.md
|
PATH: /GOVERNANCE.md
|
||||||
BRIEF: Project governance rules, roles, and decision process for MokoStandards-Template-Joomla-Plugin
|
BRIEF: Project governance rules, roles, and decision process for MokoStandards-Template-Joomla-Plugin
|
||||||
-->
|
-->
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ DEFGROUP: MokoStandards-Template-Joomla-Plugin
|
|||||||
INGROUP: MokoStandards-Template-Joomla-Plugin.Documentation
|
INGROUP: MokoStandards-Template-Joomla-Plugin.Documentation
|
||||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-Template-Joomla-Plugin
|
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-Template-Joomla-Plugin
|
||||||
PATH: /SECURITY.md
|
PATH: /SECURITY.md
|
||||||
VERSION: 01.00.00
|
VERSION: 01.01.00
|
||||||
BRIEF: Security vulnerability reporting and handling policy
|
BRIEF: Security vulnerability reporting and handling policy
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user