chore(deps)(deps): bump the github-actions group with 6 updates #119
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@@ -11,7 +11,7 @@
|
|||||||
# ── Synced workflows (managed by MokoStandards — do not edit manually) ────
|
# ── Synced workflows (managed by MokoStandards — do not edit manually) ────
|
||||||
/.github/workflows/deploy-dev.yml @jmiller-moko
|
/.github/workflows/deploy-dev.yml @jmiller-moko
|
||||||
/.github/workflows/deploy-demo.yml @jmiller-moko
|
/.github/workflows/deploy-demo.yml @jmiller-moko
|
||||||
/.github/workflows/deploy-rs.yml @jmiller-moko
|
/.github/workflows/deploy-manual.yml @jmiller-moko
|
||||||
/.github/workflows/auto-release.yml @jmiller-moko
|
/.github/workflows/auto-release.yml @jmiller-moko
|
||||||
/.github/workflows/auto-dev-issue.yml @jmiller-moko
|
/.github/workflows/auto-dev-issue.yml @jmiller-moko
|
||||||
/.github/workflows/auto-assign.yml @jmiller-moko
|
/.github/workflows/auto-assign.yml @jmiller-moko
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
/.github/workflows/ci-dolibarr.yml @jmiller-moko
|
/.github/workflows/ci-dolibarr.yml @jmiller-moko
|
||||||
/.github/workflows/publish-to-mokodolimods.yml @jmiller-moko
|
/.github/workflows/publish-to-mokodolimods.yml @jmiller-moko
|
||||||
/.github/workflows/changelog-validation.yml @jmiller-moko
|
/.github/workflows/changelog-validation.yml @jmiller-moko
|
||||||
|
/.github/workflows/branch-freeze.yml @jmiller-moko
|
||||||
# Custom workflows in .github/workflows/ not listed above are repo-owned.
|
# Custom workflows in .github/workflows/ not listed above are repo-owned.
|
||||||
|
|
||||||
# ── GitHub configuration ─────────────────────────────────────────────────
|
# ── GitHub configuration ─────────────────────────────────────────────────
|
||||||
|
|||||||
2
.github/workflows/auto-assign.yml
vendored
2
.github/workflows/auto-assign.yml
vendored
@@ -6,7 +6,7 @@
|
|||||||
# INGROUP: MokoStandards.Workflows.Shared
|
# INGROUP: MokoStandards.Workflows.Shared
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /.github/workflows/auto-assign.yml
|
# PATH: /.github/workflows/auto-assign.yml
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Auto-assign jmiller-moko to unassigned issues and PRs every 15 minutes
|
# BRIEF: Auto-assign jmiller-moko to unassigned issues and PRs every 15 minutes
|
||||||
|
|
||||||
name: Auto-Assign Issues & PRs
|
name: Auto-Assign Issues & PRs
|
||||||
|
|||||||
2
.github/workflows/auto-dev-issue.yml
vendored
2
.github/workflows/auto-dev-issue.yml
vendored
@@ -9,7 +9,7 @@
|
|||||||
# INGROUP: MokoStandards.Automation
|
# INGROUP: MokoStandards.Automation
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/auto-dev-issue.yml.template
|
# PATH: /templates/workflows/shared/auto-dev-issue.yml.template
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Auto-create tracking issue with sub-issues for dev/rc branch workflow
|
# BRIEF: Auto-create tracking issue with sub-issues for dev/rc branch workflow
|
||||||
# NOTE: Synced via bulk-repo-sync to .github/workflows/auto-dev-issue.yml in all governed repos.
|
# NOTE: Synced via bulk-repo-sync to .github/workflows/auto-dev-issue.yml in all governed repos.
|
||||||
|
|
||||||
|
|||||||
126
.github/workflows/auto-release.yml
vendored
126
.github/workflows/auto-release.yml
vendored
@@ -7,7 +7,7 @@
|
|||||||
# INGROUP: MokoStandards.Release
|
# INGROUP: MokoStandards.Release
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/joomla/auto-release.yml.template
|
# PATH: /templates/workflows/joomla/auto-release.yml.template
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Joomla build & release — ZIP package, updates.xml, SHA-256 checksum
|
# BRIEF: Joomla build & release — ZIP package, updates.xml, SHA-256 checksum
|
||||||
#
|
#
|
||||||
# +========================================================================+
|
# +========================================================================+
|
||||||
@@ -35,13 +35,14 @@
|
|||||||
name: Build & Release
|
name: Build & Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
pull_request:
|
||||||
|
types: [closed]
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- master
|
|
||||||
paths:
|
paths:
|
||||||
- 'src/**'
|
- 'src/**'
|
||||||
- 'htdocs/**'
|
- 'htdocs/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
@@ -54,8 +55,7 @@ jobs:
|
|||||||
name: Build & Release Pipeline
|
name: Build & Release Pipeline
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >-
|
if: >-
|
||||||
!contains(github.event.head_commit.message, '[skip ci]') &&
|
github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
|
||||||
github.actor != 'github-actions[bot]'
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -147,7 +147,7 @@ jobs:
|
|||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
# -- Version drift check (must pass before release) --------
|
# -- Version drift check (must pass before release) --------
|
||||||
README_VER=$(grep -oP 'VERSION:\s*\K[\d.]+' README.md 2>/dev/null | head -1)
|
README_VER=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' README.md 2>/dev/null | head -1)
|
||||||
if [ "$README_VER" != "$VERSION" ]; then
|
if [ "$README_VER" != "$VERSION" ]; then
|
||||||
echo "- Version drift: README says \`${README_VER}\` but releasing \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
echo "- Version drift: README says \`${README_VER}\` but releasing \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
ERRORS=$((ERRORS+1))
|
ERRORS=$((ERRORS+1))
|
||||||
@@ -156,7 +156,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check CHANGELOG version matches
|
# Check CHANGELOG version matches
|
||||||
CL_VER=$(grep -oP 'VERSION:\s*\K[\d.]+' CHANGELOG.md 2>/dev/null | head -1)
|
CL_VER=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' CHANGELOG.md 2>/dev/null | head -1)
|
||||||
if [ -n "$CL_VER" ] && [ "$CL_VER" != "$VERSION" ]; then
|
if [ -n "$CL_VER" ] && [ "$CL_VER" != "$VERSION" ]; then
|
||||||
echo "- CHANGELOG drift: \`${CL_VER}\` != \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
echo "- CHANGELOG drift: \`${CL_VER}\` != \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
ERRORS=$((ERRORS+1))
|
ERRORS=$((ERRORS+1))
|
||||||
@@ -164,7 +164,7 @@ jobs:
|
|||||||
|
|
||||||
# Check composer.json version if present
|
# Check composer.json version if present
|
||||||
if [ -f "composer.json" ]; then
|
if [ -f "composer.json" ]; then
|
||||||
COMP_VER=$(grep -oP '"version"\s*:\s*"\K[^"]+' composer.json 2>/dev/null | head -1)
|
COMP_VER=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' composer.json 2>/dev/null | head -1)
|
||||||
if [ -n "$COMP_VER" ] && [ "$COMP_VER" != "$VERSION" ]; then
|
if [ -n "$COMP_VER" ] && [ "$COMP_VER" != "$VERSION" ]; then
|
||||||
echo "- composer.json drift: \`${COMP_VER}\` != \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
echo "- composer.json drift: \`${COMP_VER}\` != \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
ERRORS=$((ERRORS+1))
|
ERRORS=$((ERRORS+1))
|
||||||
@@ -188,7 +188,7 @@ jobs:
|
|||||||
# -- Joomla: manifest version drift --------
|
# -- Joomla: manifest version drift --------
|
||||||
MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
|
MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
|
||||||
if [ -n "$MANIFEST" ]; then
|
if [ -n "$MANIFEST" ]; then
|
||||||
XML_VER=$(grep -oP '<version>\K[^<]+' "$MANIFEST" 2>/dev/null | head -1)
|
XML_VER=$(sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" 2>/dev/null | head -1)
|
||||||
if [ -n "$XML_VER" ] && [ "$XML_VER" != "$VERSION" ]; then
|
if [ -n "$XML_VER" ] && [ "$XML_VER" != "$VERSION" ]; then
|
||||||
echo "- Manifest drift: \`${XML_VER}\` != \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
echo "- Manifest drift: \`${XML_VER}\` != \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
ERRORS=$((ERRORS+1))
|
ERRORS=$((ERRORS+1))
|
||||||
@@ -205,7 +205,7 @@ jobs:
|
|||||||
echo "- Manifest: \`${MANIFEST}\`" >> $GITHUB_STEP_SUMMARY
|
echo "- Manifest: \`${MANIFEST}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
# -- Joomla: extension type check --------
|
# -- Joomla: extension type check --------
|
||||||
TYPE=$(grep -oP '<extension[^>]+type="\K[^"]+' "$MANIFEST" 2>/dev/null)
|
TYPE=$(sed -n 's/.*<extension[^>]*type="\([^"]*\)".*/\1/p' "$MANIFEST" 2>/dev/null)
|
||||||
echo "- Extension type: ${TYPE:-unknown}" >> $GITHUB_STEP_SUMMARY
|
echo "- Extension type: ${TYPE:-unknown}" >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -275,17 +275,22 @@ jobs:
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
EXT_NAME=$(grep -oP '<name>\K[^<]+' "$MANIFEST" 2>/dev/null | head -1 || echo "${{ github.event.repository.name }}")
|
# Extract fields using sed (portable — no grep -P)
|
||||||
EXT_TYPE=$(grep -oP '<extension[^>]+type="\K[^"]+' "$MANIFEST" 2>/dev/null || echo "component")
|
EXT_NAME=$(sed -n 's/.*<name>\([^<]*\)<\/name>.*/\1/p' "$MANIFEST" | head -1)
|
||||||
EXT_ELEMENT=$(grep -oP '<element>\K[^<]+' "$MANIFEST" 2>/dev/null | head -1 || echo "")
|
EXT_TYPE=$(sed -n 's/.*<extension[^>]*type="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
|
||||||
EXT_CLIENT=$(grep -oP '<extension[^>]+client="\K[^"]+' "$MANIFEST" 2>/dev/null || echo "")
|
EXT_ELEMENT=$(sed -n 's/.*<element>\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" | head -1)
|
||||||
EXT_FOLDER=$(grep -oP '<extension[^>]+group="\K[^"]+' "$MANIFEST" 2>/dev/null || echo "")
|
EXT_CLIENT=$(sed -n 's/.*<extension[^>]*client="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
|
||||||
TARGET_PLATFORM=$(grep -oP '<targetplatform[^/]*/>' "$MANIFEST" 2>/dev/null | head -1 || echo "")
|
EXT_FOLDER=$(sed -n 's/.*<extension[^>]*group="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
|
||||||
PHP_MINIMUM=$(grep -oP '<php_minimum>\K[^<]+' "$MANIFEST" 2>/dev/null | head -1 || echo "")
|
TARGET_PLATFORM=$(sed -n 's/.*\(<targetplatform[^/]*\/>\).*/\1/p' "$MANIFEST" | head -1)
|
||||||
|
PHP_MINIMUM=$(sed -n 's/.*<php_minimum>\([^<]*\)<\/php_minimum>.*/\1/p' "$MANIFEST" | head -1)
|
||||||
|
|
||||||
# Derive element from manifest filename if not in XML
|
# Fallbacks
|
||||||
|
[ -z "$EXT_NAME" ] && EXT_NAME="${{ github.event.repository.name }}"
|
||||||
|
[ -z "$EXT_TYPE" ] && EXT_TYPE="component"
|
||||||
|
|
||||||
|
# Templates/modules don't have <element> — derive from <name> (lowercased)
|
||||||
if [ -z "$EXT_ELEMENT" ]; then
|
if [ -z "$EXT_ELEMENT" ]; then
|
||||||
EXT_ELEMENT=$(basename "$MANIFEST" .xml)
|
EXT_ELEMENT=$(echo "$EXT_NAME" | tr '[:upper:]' '[:lower:]' | tr -d ' ')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build client tag: plugins and frontend modules need <client>site</client>
|
# Build client tag: plugins and frontend modules need <client>site</client>
|
||||||
@@ -341,24 +346,28 @@ jobs:
|
|||||||
} > /tmp/stable_entry.xml
|
} > /tmp/stable_entry.xml
|
||||||
|
|
||||||
# -- Write updates.xml preserving dev/rc entries ──────────────
|
# -- Write updates.xml preserving dev/rc entries ──────────────
|
||||||
RC_ENTRY=""
|
# Extract existing entries for other stability levels
|
||||||
DEV_ENTRY=""
|
# Order reflects release workflow: development → alpha → beta → rc → stable
|
||||||
if [ -f "updates.xml" ]; then
|
if [ -f "updates.xml" ]; then
|
||||||
printf 'import re\n' > /tmp/extract.py
|
printf 'import re, sys\n' > /tmp/extract.py
|
||||||
printf 'with open("updates.xml") as f: c = f.read()\n' >> /tmp/extract.py
|
printf 'with open("updates.xml") as f: c = f.read()\n' >> /tmp/extract.py
|
||||||
printf 'import sys; tag = sys.argv[1]\n' >> /tmp/extract.py
|
printf 'tag = sys.argv[1]\n' >> /tmp/extract.py
|
||||||
printf 'm = re.search(r"( <update>.*?<tag>" + re.escape(tag) + r"</tag>.*?</update>)", c, re.DOTALL)\n' >> /tmp/extract.py
|
printf 'm = re.search(r"( <update>.*?<tag>" + re.escape(tag) + r"</tag>.*?</update>)", c, re.DOTALL)\n' >> /tmp/extract.py
|
||||||
printf 'if m: print(m.group(1))\n' >> /tmp/extract.py
|
printf 'if m: print(m.group(1))\n' >> /tmp/extract.py
|
||||||
RC_ENTRY=$(python3 /tmp/extract.py rc 2>/dev/null || true)
|
|
||||||
DEV_ENTRY=$(python3 /tmp/extract.py development 2>/dev/null || true)
|
|
||||||
fi
|
fi
|
||||||
|
DEV_ENTRY=$(python3 /tmp/extract.py development 2>/dev/null || true)
|
||||||
|
ALPHA_ENTRY=$(python3 /tmp/extract.py alpha 2>/dev/null || true)
|
||||||
|
BETA_ENTRY=$(python3 /tmp/extract.py beta 2>/dev/null || true)
|
||||||
|
RC_ENTRY=$(python3 /tmp/extract.py rc 2>/dev/null || true)
|
||||||
|
|
||||||
{
|
{
|
||||||
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
|
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
|
||||||
printf '%s\n' '<updates>'
|
printf '%s\n' '<updates>'
|
||||||
cat /tmp/stable_entry.xml
|
|
||||||
[ -n "$RC_ENTRY" ] && echo "$RC_ENTRY"
|
|
||||||
[ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY"
|
[ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY"
|
||||||
|
[ -n "$ALPHA_ENTRY" ] && echo "$ALPHA_ENTRY"
|
||||||
|
[ -n "$BETA_ENTRY" ] && echo "$BETA_ENTRY"
|
||||||
|
[ -n "$RC_ENTRY" ] && echo "$RC_ENTRY"
|
||||||
|
cat /tmp/stable_entry.xml
|
||||||
printf '%s\n' '</updates>'
|
printf '%s\n' '</updates>'
|
||||||
} > updates.xml
|
} > updates.xml
|
||||||
|
|
||||||
@@ -468,55 +477,64 @@ jobs:
|
|||||||
MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1 || true)
|
MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1 || true)
|
||||||
[ -z "$MANIFEST" ] && exit 0
|
[ -z "$MANIFEST" ] && exit 0
|
||||||
|
|
||||||
EXT_ELEMENT=$(grep -oP '<element>\K[^<]+' "$MANIFEST" 2>/dev/null | head -1 || basename "$MANIFEST" .xml)
|
EXT_ELEMENT=$(sed -n 's/.*<element>\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" 2>/dev/null | head -1 || basename "$MANIFEST" .xml)
|
||||||
PACKAGE_NAME="${EXT_ELEMENT}-${VERSION}.zip"
|
ZIP_NAME="${EXT_ELEMENT}-${VERSION}.zip"
|
||||||
|
TAR_NAME="${EXT_ELEMENT}-${VERSION}.tar.gz"
|
||||||
|
|
||||||
# -- Build install-ready ZIP from src/ ----------------------------
|
# -- Build install packages from src/ ----------------------------
|
||||||
SOURCE_DIR="src"
|
SOURCE_DIR="src"
|
||||||
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
||||||
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ — skipping package"; exit 0; }
|
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ — skipping package"; exit 0; }
|
||||||
|
|
||||||
|
EXCLUDES=".ftpignore sftp-config* *.ppk *.pem *.key .env*"
|
||||||
|
|
||||||
|
# ZIP package
|
||||||
cd "$SOURCE_DIR"
|
cd "$SOURCE_DIR"
|
||||||
zip -r "/tmp/${PACKAGE_NAME}" . -x '.ftpignore'
|
zip -r "/tmp/${ZIP_NAME}" . -x $EXCLUDES
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
FILESIZE=$(stat -c%s "/tmp/${PACKAGE_NAME}" 2>/dev/null || stat -f%z "/tmp/${PACKAGE_NAME}" 2>/dev/null || echo "unknown")
|
# tar.gz package
|
||||||
|
tar -czf "/tmp/${TAR_NAME}" -C "$SOURCE_DIR" \
|
||||||
|
--exclude='.ftpignore' --exclude='sftp-config*' \
|
||||||
|
--exclude='*.ppk' --exclude='*.pem' --exclude='*.key' --exclude='.env*' .
|
||||||
|
|
||||||
# -- Calculate SHA-256 -------------------------------------------
|
ZIP_SIZE=$(stat -c%s "/tmp/${ZIP_NAME}" 2>/dev/null || stat -f%z "/tmp/${ZIP_NAME}" 2>/dev/null || echo "unknown")
|
||||||
SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1)
|
TAR_SIZE=$(stat -c%s "/tmp/${TAR_NAME}" 2>/dev/null || stat -f%z "/tmp/${TAR_NAME}" 2>/dev/null || echo "unknown")
|
||||||
|
|
||||||
# -- Upload ZIP to the minor release tag -------------------------
|
# -- Calculate SHA-256 for both ----------------------------------
|
||||||
gh release upload "$RELEASE_TAG" "/tmp/${PACKAGE_NAME}" --clobber 2>/dev/null || {
|
SHA256_ZIP=$(sha256sum "/tmp/${ZIP_NAME}" | cut -d' ' -f1)
|
||||||
echo "Could not upload with --clobber, retrying..."
|
SHA256_TAR=$(sha256sum "/tmp/${TAR_NAME}" | cut -d' ' -f1)
|
||||||
gh release upload "$RELEASE_TAG" "/tmp/${PACKAGE_NAME}" 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
# -- Update updates.xml with SHA-256 for latest patch -------------
|
# -- Upload both to release tag ----------------------------------
|
||||||
|
gh release upload "$RELEASE_TAG" "/tmp/${ZIP_NAME}" --clobber 2>/dev/null || true
|
||||||
|
gh release upload "$RELEASE_TAG" "/tmp/${TAR_NAME}" --clobber 2>/dev/null || true
|
||||||
|
|
||||||
|
# -- Update updates.xml with both download formats ---------------
|
||||||
if [ -f "updates.xml" ]; then
|
if [ -f "updates.xml" ]; then
|
||||||
|
ZIP_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${ZIP_NAME}"
|
||||||
|
TAR_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${TAR_NAME}"
|
||||||
|
|
||||||
|
# Replace downloads block with both formats + SHA
|
||||||
|
sed -i "s|<downloads>.*</downloads>|<downloads>\n <downloadurl type=\"full\" format=\"zip\">${ZIP_URL}</downloadurl>\n <downloadurl type=\"full\" format=\"tar.gz\">${TAR_URL}</downloadurl>\n </downloads>|" updates.xml 2>/dev/null || true
|
||||||
if grep -q '<sha256>' updates.xml; then
|
if grep -q '<sha256>' updates.xml; then
|
||||||
sed -i "s|<sha256>.*</sha256>|<sha256>sha256:${SHA256}</sha256>|" updates.xml
|
sed -i "s|<sha256>.*</sha256>|<sha256>sha256:${SHA256_ZIP}</sha256>|" updates.xml
|
||||||
else
|
else
|
||||||
sed -i "s|</downloads>|</downloads>\n <sha256>sha256:${SHA256}</sha256>|" updates.xml
|
sed -i "s|</downloads>|</downloads>\n <sha256>sha256:${SHA256_ZIP}</sha256>|" updates.xml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Also update the download URL to point to this patch's ZIP
|
|
||||||
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}"
|
|
||||||
sed -i "s|<downloadurl[^>]*>[^<]*</downloadurl>|<downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>|" updates.xml
|
|
||||||
|
|
||||||
git add updates.xml
|
git add updates.xml
|
||||||
git commit -m "chore(release): SHA-256 + download URL for ${VERSION} [skip ci]" \
|
git commit -m "chore(release): ZIP + tar.gz for ${VERSION} [skip ci]" \
|
||||||
--author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>" || true
|
--author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>" || true
|
||||||
git push || true
|
git push || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "### Joomla Package" >> $GITHUB_STEP_SUMMARY
|
echo "### Joomla Packages" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
|
echo "| Package | Size | SHA-256 |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
|
echo "|---------|------|---------|" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Package | \`${PACKAGE_NAME}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| \`${ZIP_NAME}\` | ${ZIP_SIZE} | \`${SHA256_ZIP}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Size | ${FILESIZE} bytes |" >> $GITHUB_STEP_SUMMARY
|
echo "| \`${TAR_NAME}\` | ${TAR_SIZE} | \`${SHA256_TAR}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| SHA-256 | \`${SHA256}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| Release | \`${RELEASE_TAG}\` | |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Release | \`${RELEASE_TAG}\` |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Download | [${PACKAGE_NAME}](https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}) |" >> $GITHUB_STEP_SUMMARY
|
echo "| Download | [${PACKAGE_NAME}](https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
# -- Summary --------------------------------------------------------------
|
# -- Summary --------------------------------------------------------------
|
||||||
|
|||||||
114
.github/workflows/branch-freeze.yml
vendored
Normal file
114
.github/workflows/branch-freeze.yml
vendored
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# FILE INFORMATION
|
||||||
|
# DEFGROUP: GitHub.Workflow
|
||||||
|
# INGROUP: MokoStandards.Automation
|
||||||
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
|
# PATH: /templates/workflows/shared/branch-freeze.yml.template
|
||||||
|
# VERSION: 04.06.00
|
||||||
|
# BRIEF: Freeze or unfreeze any branch via ruleset — manual workflow_dispatch
|
||||||
|
|
||||||
|
name: Branch Freeze
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch:
|
||||||
|
description: 'Branch to freeze/unfreeze (e.g., version/04, dev/feature)'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
action:
|
||||||
|
description: 'Action to perform'
|
||||||
|
required: true
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- freeze
|
||||||
|
- unfreeze
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
manage-freeze:
|
||||||
|
name: "${{ inputs.action }} branch: ${{ inputs.branch }}"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check permissions
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
||||||
|
run: |
|
||||||
|
ACTOR="${{ github.actor }}"
|
||||||
|
REPO="${{ github.repository }}"
|
||||||
|
PERMISSION=$(gh api "repos/${REPO}/collaborators/${ACTOR}/permission" \
|
||||||
|
--jq '.permission' 2>/dev/null || echo "read")
|
||||||
|
if [ "$PERMISSION" != "admin" ]; then
|
||||||
|
echo "Denied: only admins can freeze/unfreeze branches (${ACTOR} has ${PERMISSION})"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: "${{ inputs.action }} branch"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
||||||
|
run: |
|
||||||
|
BRANCH="${{ inputs.branch }}"
|
||||||
|
ACTION="${{ inputs.action }}"
|
||||||
|
REPO="${{ github.repository }}"
|
||||||
|
RULESET_NAME="FROZEN: ${BRANCH}"
|
||||||
|
|
||||||
|
echo "## Branch Freeze" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ "$ACTION" = "freeze" ]; then
|
||||||
|
# Check if ruleset already exists
|
||||||
|
EXISTING=$(gh api "repos/${REPO}/rulesets" \
|
||||||
|
--jq ".[] | select(.name == \"${RULESET_NAME}\") | .id" 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -n "$EXISTING" ]; then
|
||||||
|
echo "Branch \`${BRANCH}\` is already frozen (ruleset #${EXISTING})" >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create freeze ruleset — blocks all updates except admin bypass
|
||||||
|
printf '{"name":"%s","target":"branch","enforcement":"active",' "${RULESET_NAME}" > /tmp/ruleset.json
|
||||||
|
printf '"bypass_actors":[{"actor_id":5,"actor_type":"RepositoryRole","bypass_mode":"always"}],' >> /tmp/ruleset.json
|
||||||
|
printf '"conditions":{"ref_name":{"include":["refs/heads/%s"],"exclude":[]}},' "${BRANCH}" >> /tmp/ruleset.json
|
||||||
|
printf '"rules":[{"type":"update"},{"type":"deletion"},{"type":"non_fast_forward"}]}' >> /tmp/ruleset.json
|
||||||
|
|
||||||
|
RESULT=$(gh api "repos/${REPO}/rulesets" -X POST --input /tmp/ruleset.json --jq '.id' 2>&1) || true
|
||||||
|
|
||||||
|
if echo "$RESULT" | grep -qE '^[0-9]+$'; then
|
||||||
|
echo "Frozen \`${BRANCH}\` — ruleset #${RESULT}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Branch | \`${BRANCH}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Ruleset | #${RESULT} |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Rules | No updates, no deletion, no force push |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Bypass | Repository admins only |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "Failed to freeze: ${RESULT}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [ "$ACTION" = "unfreeze" ]; then
|
||||||
|
# Find and delete the freeze ruleset
|
||||||
|
RULESET_ID=$(gh api "repos/${REPO}/rulesets" \
|
||||||
|
--jq ".[] | select(.name == \"${RULESET_NAME}\") | .id" 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -z "$RULESET_ID" ]; then
|
||||||
|
echo "Branch \`${BRANCH}\` is not frozen (no ruleset found)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
gh api "repos/${REPO}/rulesets/${RULESET_ID}" -X DELETE --silent 2>/dev/null
|
||||||
|
|
||||||
|
echo "Unfrozen \`${BRANCH}\` — ruleset #${RULESET_ID} deleted" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/ruleset.json
|
||||||
6
.github/workflows/changelog-validation.yml
vendored
6
.github/workflows/changelog-validation.yml
vendored
@@ -9,19 +9,17 @@
|
|||||||
# INGROUP: MokoStandards.CI
|
# INGROUP: MokoStandards.CI
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/changelog-validation.yml.template
|
# PATH: /templates/workflows/shared/changelog-validation.yml.template
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Validates CHANGELOG.md format and version consistency
|
# BRIEF: Validates CHANGELOG.md format and version consistency
|
||||||
# NOTE: Deployed to .github/workflows/changelog-validation.yml in governed repos.
|
# NOTE: Deployed to .github/workflows/changelog-validation.yml in governed repos.
|
||||||
|
|
||||||
name: Changelog Validation
|
name: Changelog Validation
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 'dev/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
11
.github/workflows/ci-joomla.yml
vendored
11
.github/workflows/ci-joomla.yml
vendored
@@ -9,24 +9,17 @@
|
|||||||
# INGROUP: MokoStandards.CI
|
# INGROUP: MokoStandards.CI
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/joomla/ci-joomla.yml.template
|
# PATH: /templates/workflows/joomla/ci-joomla.yml.template
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: CI workflow for Joomla extensions — lint, validate, test
|
# BRIEF: CI workflow for Joomla extensions — lint, validate, test
|
||||||
# NOTE: Deployed to .github/workflows/ci-joomla.yml in governed Joomla extension repos.
|
# NOTE: Deployed to .github/workflows/ci-joomla.yml in governed Joomla extension repos.
|
||||||
|
|
||||||
name: Joomla Extension CI
|
name: Joomla Extension CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- dev/**
|
|
||||||
- rc/**
|
|
||||||
- version/**
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- dev/**
|
- 'dev/**'
|
||||||
- rc/**
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
9
.github/workflows/codeql-analysis.yml
vendored
9
.github/workflows/codeql-analysis.yml
vendored
@@ -21,14 +21,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- dev/**
|
- version/*
|
||||||
- rc/**
|
|
||||||
- version/**
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- dev/**
|
|
||||||
- rc/**
|
|
||||||
schedule:
|
schedule:
|
||||||
# Weekly on Monday at 06:00 UTC
|
# Weekly on Monday at 06:00 UTC
|
||||||
- cron: '0 6 * * 1'
|
- cron: '0 6 * * 1'
|
||||||
|
|||||||
2
.github/workflows/deploy-manual.yml
vendored
2
.github/workflows/deploy-manual.yml
vendored
@@ -7,7 +7,7 @@
|
|||||||
# INGROUP: MokoStandards.Deploy
|
# INGROUP: MokoStandards.Deploy
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/joomla/deploy-manual.yml.template
|
# PATH: /templates/workflows/joomla/deploy-manual.yml.template
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Manual SFTP deploy to dev server for Joomla repos
|
# BRIEF: Manual SFTP deploy to dev server for Joomla repos
|
||||||
# NOTE: Joomla repos use update.xml for distribution. This is for manual
|
# NOTE: Joomla repos use update.xml for distribution. This is for manual
|
||||||
# dev server testing only — triggered via workflow_dispatch.
|
# dev server testing only — triggered via workflow_dispatch.
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
# INGROUP: MokoStandards.Firewall
|
# INGROUP: MokoStandards.Firewall
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/enterprise-firewall-setup.yml.template
|
# PATH: /templates/workflows/shared/enterprise-firewall-setup.yml.template
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Enterprise firewall configuration — generates outbound allow-rules including SFTP deployment server
|
# BRIEF: Enterprise firewall configuration — generates outbound allow-rules including SFTP deployment server
|
||||||
# NOTE: Reads DEV_FTP_HOST / DEV_FTP_PORT variables to include SFTP egress rules alongside HTTPS rules.
|
# NOTE: Reads DEV_FTP_HOST / DEV_FTP_PORT variables to include SFTP egress rules alongside HTTPS rules.
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v6
|
||||||
|
|||||||
2
.github/workflows/repo_health.yml
vendored
2
.github/workflows/repo_health.yml
vendored
@@ -10,7 +10,7 @@
|
|||||||
# INGROUP: MokoStandards.Validation
|
# INGROUP: MokoStandards.Validation
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /.github/workflows/repo_health.yml
|
# PATH: /.github/workflows/repo_health.yml
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Enforces repository guardrails by validating release configuration, scripts governance, tooling availability, and core repository health artifacts.
|
# BRIEF: Enforces repository guardrails by validating release configuration, scripts governance, tooling availability, and core repository health artifacts.
|
||||||
# NOTE: Field is user-managed.
|
# NOTE: Field is user-managed.
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|||||||
6
.github/workflows/repository-cleanup.yml
vendored
6
.github/workflows/repository-cleanup.yml
vendored
@@ -9,7 +9,7 @@
|
|||||||
# INGROUP: MokoStandards.Maintenance
|
# INGROUP: MokoStandards.Maintenance
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/repository-cleanup.yml.template
|
# PATH: /templates/workflows/shared/repository-cleanup.yml.template
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Recurring repository maintenance — labels, branches, workflows, logs, doc indexes
|
# BRIEF: Recurring repository maintenance — labels, branches, workflows, logs, doc indexes
|
||||||
# NOTE: Synced via bulk-repo-sync to .github/workflows/repository-cleanup.yml in all governed repos.
|
# NOTE: Synced via bulk-repo-sync to .github/workflows/repository-cleanup.yml in all governed repos.
|
||||||
# Runs on the 1st and 15th of each month at 6:00 AM UTC, and on manual dispatch.
|
# Runs on the 1st and 15th of each month at 6:00 AM UTC, and on manual dispatch.
|
||||||
@@ -154,6 +154,10 @@ jobs:
|
|||||||
".github/workflows/auto-version-branch.yml"
|
".github/workflows/auto-version-branch.yml"
|
||||||
".github/workflows/publish-to-mokodolibarr.yml"
|
".github/workflows/publish-to-mokodolibarr.yml"
|
||||||
".github/workflows/ci.yml"
|
".github/workflows/ci.yml"
|
||||||
|
".github/workflows/deploy-rs.yml"
|
||||||
|
"sftp-config.json"
|
||||||
|
"sftp-config.json.template"
|
||||||
|
"scripts/sftp-config"
|
||||||
)
|
)
|
||||||
|
|
||||||
DELETED=0
|
DELETED=0
|
||||||
|
|||||||
2
.github/workflows/standards-compliance.yml
vendored
2
.github/workflows/standards-compliance.yml
vendored
@@ -5,7 +5,7 @@
|
|||||||
# INGROUP: MokoStandards.Compliance
|
# INGROUP: MokoStandards.Compliance
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /.github/workflows/standards-compliance.yml
|
# PATH: /.github/workflows/standards-compliance.yml
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: MokoStandards compliance validation workflow
|
# BRIEF: MokoStandards compliance validation workflow
|
||||||
# NOTE: Validates repository structure, documentation, and coding standards
|
# NOTE: Validates repository structure, documentation, and coding standards
|
||||||
|
|
||||||
|
|||||||
10
.github/workflows/sync-version-on-merge.yml
vendored
10
.github/workflows/sync-version-on-merge.yml
vendored
@@ -9,7 +9,7 @@
|
|||||||
# INGROUP: MokoStandards.Automation
|
# INGROUP: MokoStandards.Automation
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/sync-version-on-merge.yml.template
|
# PATH: /templates/workflows/shared/sync-version-on-merge.yml.template
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Auto-bump patch version on every push to main and propagate to all file headers
|
# BRIEF: Auto-bump patch version on every push to main and propagate to all file headers
|
||||||
# NOTE: Synced via bulk-repo-sync to .github/workflows/sync-version-on-merge.yml in all governed repos.
|
# NOTE: Synced via bulk-repo-sync to .github/workflows/sync-version-on-merge.yml in all governed repos.
|
||||||
# README.md is the single source of truth for the repository version.
|
# README.md is the single source of truth for the repository version.
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
name: Sync Version from README
|
name: Sync Version from README
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
pull_request:
|
||||||
|
types: [closed]
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- master
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
dry_run:
|
dry_run:
|
||||||
@@ -39,6 +39,8 @@ jobs:
|
|||||||
sync-version:
|
sync-version:
|
||||||
name: Propagate README version
|
name: Propagate README version
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: >-
|
||||||
|
github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -65,7 +67,7 @@ jobs:
|
|||||||
composer install --no-dev --no-interaction --quiet
|
composer install --no-dev --no-interaction --quiet
|
||||||
|
|
||||||
- name: Auto-bump patch version
|
- name: Auto-bump patch version
|
||||||
if: ${{ github.event_name == 'push' && github.actor != 'github-actions[bot]' }}
|
if: ${{ github.event_name != 'workflow_dispatch' && github.actor != 'github-actions[bot]' }}
|
||||||
run: |
|
run: |
|
||||||
if git diff --name-only HEAD~1 HEAD 2>/dev/null | grep -q '^README\.md$'; then
|
if git diff --name-only HEAD~1 HEAD 2>/dev/null | grep -q '^README\.md$'; then
|
||||||
echo "README.md changed in this push — skipping auto-bump"
|
echo "README.md changed in this push — skipping auto-bump"
|
||||||
|
|||||||
57
.github/workflows/update-server.yml
vendored
57
.github/workflows/update-server.yml
vendored
@@ -7,7 +7,7 @@
|
|||||||
# INGROUP: MokoStandards.Joomla
|
# INGROUP: MokoStandards.Joomla
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/joomla/update-server.yml.template
|
# PATH: /templates/workflows/joomla/update-server.yml.template
|
||||||
# VERSION: 03.09.03
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Update Joomla update server XML feed with stable/rc/dev entries
|
# BRIEF: Update Joomla update server XML feed with stable/rc/dev entries
|
||||||
#
|
#
|
||||||
# Writes updates.xml with multiple <update> entries:
|
# Writes updates.xml with multiple <update> entries:
|
||||||
@@ -20,7 +20,8 @@
|
|||||||
name: Update Joomla Update Server XML Feed
|
name: Update Joomla Update Server XML Feed
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
pull_request:
|
||||||
|
types: [closed]
|
||||||
branches:
|
branches:
|
||||||
- 'dev/**'
|
- 'dev/**'
|
||||||
- 'alpha/**'
|
- 'alpha/**'
|
||||||
@@ -53,6 +54,8 @@ jobs:
|
|||||||
update-xml:
|
update-xml:
|
||||||
name: Update updates.xml
|
name: Update updates.xml
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: >-
|
||||||
|
github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -108,22 +111,35 @@ jobs:
|
|||||||
STABILITY="stable"
|
STABILITY="stable"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Parse manifest
|
# Parse manifest (portable — no grep -P)
|
||||||
MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
|
MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
|
||||||
if [ -z "$MANIFEST" ]; then
|
if [ -z "$MANIFEST" ]; then
|
||||||
echo "No Joomla manifest found — skipping"
|
echo "No Joomla manifest found — skipping"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
EXT_NAME=$(grep -oP '<name>\K[^<]+' "$MANIFEST" 2>/dev/null | head -1 || echo "${{ github.event.repository.name }}")
|
# Extract fields using sed (works on all runners)
|
||||||
EXT_TYPE=$(grep -oP '<extension[^>]+type="\K[^"]+' "$MANIFEST" 2>/dev/null || echo "component")
|
EXT_NAME=$(sed -n 's/.*<name>\([^<]*\)<\/name>.*/\1/p' "$MANIFEST" | head -1)
|
||||||
EXT_ELEMENT=$(grep -oP '<element>\K[^<]+' "$MANIFEST" 2>/dev/null | head -1 || basename "$MANIFEST" .xml)
|
EXT_TYPE=$(sed -n 's/.*<extension[^>]*type="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
|
||||||
EXT_CLIENT=$(grep -oP '<extension[^>]+client="\K[^"]+' "$MANIFEST" 2>/dev/null || echo "")
|
EXT_ELEMENT=$(sed -n 's/.*<element>\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" | head -1)
|
||||||
EXT_FOLDER=$(grep -oP '<extension[^>]+group="\K[^"]+' "$MANIFEST" 2>/dev/null || echo "")
|
EXT_CLIENT=$(sed -n 's/.*<extension[^>]*client="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
|
||||||
TARGET_PLATFORM=$(grep -oP '<targetplatform[^/]*/>' "$MANIFEST" 2>/dev/null | head -1 || echo "")
|
EXT_FOLDER=$(sed -n 's/.*<extension[^>]*group="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
|
||||||
PHP_MINIMUM=$(grep -oP '<php_minimum>\K[^<]+' "$MANIFEST" 2>/dev/null | head -1 || echo "")
|
EXT_VERSION=$(sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" | head -1)
|
||||||
|
TARGET_PLATFORM=$(sed -n 's/.*\(<targetplatform[^/]*\/>\).*/\1/p' "$MANIFEST" | head -1)
|
||||||
|
PHP_MINIMUM=$(sed -n 's/.*<php_minimum>\([^<]*\)<\/php_minimum>.*/\1/p' "$MANIFEST" | head -1)
|
||||||
|
|
||||||
|
# Fallbacks
|
||||||
|
[ -z "$EXT_NAME" ] && EXT_NAME="${{ github.event.repository.name }}"
|
||||||
|
[ -z "$EXT_TYPE" ] && EXT_TYPE="component"
|
||||||
|
|
||||||
|
# Templates and modules don't have <element> — derive from <name>
|
||||||
|
if [ -z "$EXT_ELEMENT" ]; then
|
||||||
|
EXT_ELEMENT=$(echo "$EXT_NAME" | tr '[:upper:]' '[:lower:]' | tr -d ' ')
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use manifest version if README version is empty
|
||||||
|
[ "$VERSION" = "0.0.0" ] && [ -n "$EXT_VERSION" ] && VERSION="$EXT_VERSION"
|
||||||
|
|
||||||
[ -z "$EXT_ELEMENT" ] && EXT_ELEMENT=$(basename "$MANIFEST" .xml)
|
|
||||||
[ -z "$TARGET_PLATFORM" ] && TARGET_PLATFORM=$(printf '<targetplatform name="joomla" version="5.*" %s>' "/")
|
[ -z "$TARGET_PLATFORM" ] && TARGET_PLATFORM=$(printf '<targetplatform name="joomla" version="5.*" %s>' "/")
|
||||||
|
|
||||||
CLIENT_TAG=""
|
CLIENT_TAG=""
|
||||||
@@ -160,24 +176,31 @@ jobs:
|
|||||||
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}"
|
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}"
|
||||||
INFO_URL="https://github.com/${REPO}"
|
INFO_URL="https://github.com/${REPO}"
|
||||||
|
|
||||||
# ── Build install-ready ZIP ─────────────────────────────────
|
# ── Build install packages (ZIP + tar.gz) ───────────────────
|
||||||
SOURCE_DIR="src"
|
SOURCE_DIR="src"
|
||||||
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
||||||
if [ -d "$SOURCE_DIR" ]; then
|
if [ -d "$SOURCE_DIR" ]; then
|
||||||
|
EXCLUDES=".ftpignore sftp-config* *.ppk *.pem *.key .env*"
|
||||||
|
TAR_NAME="${EXT_ELEMENT}-${DISPLAY_VERSION}.tar.gz"
|
||||||
|
|
||||||
cd "$SOURCE_DIR"
|
cd "$SOURCE_DIR"
|
||||||
zip -r "/tmp/${PACKAGE_NAME}" . -x '.ftpignore'
|
zip -r "/tmp/${PACKAGE_NAME}" . -x $EXCLUDES
|
||||||
cd ..
|
cd ..
|
||||||
|
tar -czf "/tmp/${TAR_NAME}" -C "$SOURCE_DIR" \
|
||||||
|
--exclude='.ftpignore' --exclude='sftp-config*' \
|
||||||
|
--exclude='*.ppk' --exclude='*.pem' --exclude='*.key' --exclude='.env*' .
|
||||||
|
|
||||||
SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1)
|
SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1)
|
||||||
|
|
||||||
# Ensure draft release exists for this major
|
# Ensure release exists
|
||||||
gh release view "$RELEASE_TAG" --json tagName > /dev/null 2>&1 || \
|
gh release view "$RELEASE_TAG" --json tagName > /dev/null 2>&1 || \
|
||||||
gh release create "$RELEASE_TAG" --title "${RELEASE_TAG} (${DISPLAY_VERSION})" --notes "${STABILITY} release" --prerelease --target main 2>/dev/null || true
|
gh release create "$RELEASE_TAG" --title "${RELEASE_TAG} (${DISPLAY_VERSION})" --notes "${STABILITY} release" --prerelease --target main 2>/dev/null || true
|
||||||
|
|
||||||
# Upload ZIP to the major release
|
# Upload both formats
|
||||||
gh release upload "$RELEASE_TAG" "/tmp/${PACKAGE_NAME}" --clobber 2>/dev/null || true
|
gh release upload "$RELEASE_TAG" "/tmp/${PACKAGE_NAME}" --clobber 2>/dev/null || true
|
||||||
|
gh release upload "$RELEASE_TAG" "/tmp/${TAR_NAME}" --clobber 2>/dev/null || true
|
||||||
|
|
||||||
echo "Package: ${PACKAGE_NAME} (SHA: ${SHA256})" >> $GITHUB_STEP_SUMMARY
|
echo "Packages: ${PACKAGE_NAME} + ${TAR_NAME} (SHA: ${SHA256})" >> $GITHUB_STEP_SUMMARY
|
||||||
else
|
else
|
||||||
SHA256=""
|
SHA256=""
|
||||||
fi
|
fi
|
||||||
@@ -197,7 +220,9 @@ jobs:
|
|||||||
NEW_ENTRY="${NEW_ENTRY} </tags>\n"
|
NEW_ENTRY="${NEW_ENTRY} </tags>\n"
|
||||||
NEW_ENTRY="${NEW_ENTRY} <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>\n"
|
NEW_ENTRY="${NEW_ENTRY} <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>\n"
|
||||||
NEW_ENTRY="${NEW_ENTRY} <downloads>\n"
|
NEW_ENTRY="${NEW_ENTRY} <downloads>\n"
|
||||||
|
TAR_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${EXT_ELEMENT}-${DISPLAY_VERSION}.tar.gz"
|
||||||
NEW_ENTRY="${NEW_ENTRY} <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>\n"
|
NEW_ENTRY="${NEW_ENTRY} <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>\n"
|
||||||
|
NEW_ENTRY="${NEW_ENTRY} <downloadurl type=\"full\" format=\"tar.gz\">${TAR_URL}</downloadurl>\n"
|
||||||
NEW_ENTRY="${NEW_ENTRY} </downloads>\n"
|
NEW_ENTRY="${NEW_ENTRY} </downloads>\n"
|
||||||
[ -n "$SHA256" ] && NEW_ENTRY="${NEW_ENTRY} <sha256>sha256:${SHA256}</sha256>\n"
|
[ -n "$SHA256" ] && NEW_ENTRY="${NEW_ENTRY} <sha256>sha256:${SHA256}</sha256>\n"
|
||||||
NEW_ENTRY="${NEW_ENTRY} ${TARGET_PLATFORM}\n"
|
NEW_ENTRY="${NEW_ENTRY} ${TARGET_PLATFORM}\n"
|
||||||
|
|||||||
183
updates.xml
183
updates.xml
@@ -1,184 +1,21 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
||||||
|
|
||||||
This file is part of a Moko Consulting project.
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
# FILE INFORMATION
|
|
||||||
DEFGROUP: Joomla.Template.Update
|
|
||||||
INGROUP: MokoCassiopeia
|
|
||||||
REPO: https://github.com/mokoconsulting-tech/MokoCassiopeia
|
|
||||||
PATH: ./updates.xml
|
|
||||||
VERSION: 03.09.05
|
|
||||||
BRIEF: Update manifest XML — stable, rc, and development channels
|
|
||||||
-->
|
|
||||||
|
|
||||||
<updates>
|
<updates>
|
||||||
|
|
||||||
<!-- ══════════════════════════════════════════════════════════════
|
|
||||||
STABLE — production releases from main branch
|
|
||||||
══════════════════════════════════════════════════════════════ -->
|
|
||||||
<update>
|
<update>
|
||||||
<name>MokoCassiopeia</name>
|
<name></name>
|
||||||
<description>Moko Consulting's site template based on Cassiopeia.</description>
|
<description> update</description>
|
||||||
<element>mokocassiopeia</element>
|
<element></element>
|
||||||
<type>template</type>
|
<type>component</type>
|
||||||
<client>site</client>
|
<version></version>
|
||||||
|
|
||||||
<version>03.09.07</version>
|
|
||||||
<creationDate>2026-04-07</creationDate>
|
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
|
||||||
<copyright>(C)GNU General Public License Version 3 - 2026 Moko Consulting</copyright>
|
|
||||||
|
|
||||||
<infourl title='MokoCassiopeia'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/v03</infourl>
|
|
||||||
|
|
||||||
<downloads>
|
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/v03/mokocassiopeia-03.09.07.zip</downloadurl>
|
|
||||||
</downloads>
|
|
||||||
<sha256>16a7ac98dd6e26144618a4ba534ea8fae0d115ec8373712743ab6daff0960916</sha256>
|
|
||||||
|
|
||||||
<tags>
|
<tags>
|
||||||
<tag>stable</tag>
|
<tag>stable</tag>
|
||||||
</tags>
|
</tags>
|
||||||
|
<infourl title="">https://github.com/mokoconsulting-tech/MokoCassiopeia</infourl>
|
||||||
<maintainer>Moko Consulting</maintainer>
|
|
||||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
|
||||||
|
|
||||||
<targetplatform name='joomla' version='(5|6)\..*'/>
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<!-- ══════════════════════════════════════════════════════════════
|
|
||||||
RC — release candidates for testing and validation
|
|
||||||
══════════════════════════════════════════════════════════════ -->
|
|
||||||
<update>
|
|
||||||
<name>MokoCassiopeia</name>
|
|
||||||
<description>MokoCassiopeia release candidate — testing only.</description>
|
|
||||||
<element>mokocassiopeia</element>
|
|
||||||
<type>template</type>
|
|
||||||
<client>site</client>
|
|
||||||
|
|
||||||
<version>03.09.07</version>
|
|
||||||
<creationDate>2026-04-07</creationDate>
|
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
|
||||||
<copyright>(C)GNU General Public License Version 3 - 2026 Moko Consulting</copyright>
|
|
||||||
|
|
||||||
<infourl title='MokoCassiopeia RC'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/release-candidate</infourl>
|
|
||||||
|
|
||||||
<downloads>
|
<downloads>
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/release-candidate/mokocassiopeia-rc.zip</downloadurl>
|
<downloadurl type="full" format="zip">https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/v/-.zip</downloadurl>
|
||||||
|
<downloadurl type="full" format="tar.gz">https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/v/-.tar.gz</downloadurl>
|
||||||
</downloads>
|
</downloads>
|
||||||
<sha256>31e660078e728e8c9177b5a2d75efd89fea1fd4e9320d77444ab8fe28d3b354d</sha256>
|
<targetplatform name="joomla" version="5.*" />
|
||||||
|
|
||||||
<tags>
|
|
||||||
<tag>rc</tag>
|
|
||||||
</tags>
|
|
||||||
|
|
||||||
<maintainer>Moko Consulting</maintainer>
|
<maintainer>Moko Consulting</maintainer>
|
||||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
||||||
|
|
||||||
<targetplatform name='joomla' version='(5|6)\..*'/>
|
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<!-- ══════════════════════════════════════════════════════════════
|
|
||||||
DEVELOPMENT — latest dev branch builds, not for production
|
|
||||||
══════════════════════════════════════════════════════════════ -->
|
|
||||||
<update>
|
|
||||||
<name>MokoCassiopeia</name>
|
|
||||||
<description>MokoCassiopeia development build — unstable.</description>
|
|
||||||
<element>mokocassiopeia</element>
|
|
||||||
<type>template</type>
|
|
||||||
<client>site</client>
|
|
||||||
|
|
||||||
<version>03.09.08</version>
|
|
||||||
<creationDate>2026-04-07</creationDate>
|
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
|
||||||
<copyright>(C)GNU General Public License Version 3 - 2026 Moko Consulting</copyright>
|
|
||||||
|
|
||||||
<infourl title='MokoCassiopeia Dev'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/development</infourl>
|
|
||||||
|
|
||||||
<downloads>
|
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/development/mokocassiopeia-03.09.08-dev.zip</downloadurl>
|
|
||||||
</downloads>
|
|
||||||
<sha256>ecff187531e65a40ae958ae91fff74da0c8856d1cc13e17a6e3d6905806b189e</sha256>
|
|
||||||
|
|
||||||
<tags>
|
|
||||||
<tag>development</tag>
|
|
||||||
</tags>
|
|
||||||
|
|
||||||
<maintainer>Moko Consulting</maintainer>
|
|
||||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
|
||||||
|
|
||||||
<targetplatform name='joomla' version='(5|6)\..*'/>
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<!-- ══════════════════════════════════════════════════════════════
|
|
||||||
ALPHA — early testing, expect breaking changes
|
|
||||||
══════════════════════════════════════════════════════════════ -->
|
|
||||||
<update>
|
|
||||||
<name>MokoCassiopeia</name>
|
|
||||||
<description>MokoCassiopeia alpha build — early testing.</description>
|
|
||||||
<element>mokocassiopeia</element>
|
|
||||||
<type>template</type>
|
|
||||||
<client>site</client>
|
|
||||||
|
|
||||||
<version>03.09.07</version>
|
|
||||||
<creationDate>2026-04-07</creationDate>
|
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
|
||||||
<copyright>(C)GNU General Public License Version 3 - 2026 Moko Consulting</copyright>
|
|
||||||
|
|
||||||
<infourl title='MokoCassiopeia Alpha'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/alpha</infourl>
|
|
||||||
|
|
||||||
<downloads>
|
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/alpha/mokocassiopeia-03.09.07-alpha.zip</downloadurl>
|
|
||||||
</downloads>
|
|
||||||
<sha256>1a32180f8b26749bf5daf0602262e33464bcb3a042a8ff51ec2844cdeef2f9e5</sha256>
|
|
||||||
|
|
||||||
<tags>
|
|
||||||
<tag>alpha</tag>
|
|
||||||
</tags>
|
|
||||||
|
|
||||||
<maintainer>Moko Consulting</maintainer>
|
|
||||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
|
||||||
|
|
||||||
<targetplatform name='joomla' version='(5|6)\..*'/>
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<!-- ══════════════════════════════════════════════════════════════
|
|
||||||
BETA — feature complete, testing for stability
|
|
||||||
══════════════════════════════════════════════════════════════ -->
|
|
||||||
<update>
|
|
||||||
<name>MokoCassiopeia</name>
|
|
||||||
<description>MokoCassiopeia beta build — feature complete, stability testing.</description>
|
|
||||||
<element>mokocassiopeia</element>
|
|
||||||
<type>template</type>
|
|
||||||
<client>site</client>
|
|
||||||
|
|
||||||
<version>03.09.07</version>
|
|
||||||
<creationDate>2026-04-07</creationDate>
|
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
|
||||||
<copyright>(C)GNU General Public License Version 3 - 2026 Moko Consulting</copyright>
|
|
||||||
|
|
||||||
<infourl title='MokoCassiopeia Beta'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/beta</infourl>
|
|
||||||
|
|
||||||
<downloads>
|
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/beta/mokocassiopeia-03.09.07-beta.zip</downloadurl>
|
|
||||||
</downloads>
|
|
||||||
<sha256>1a32180f8b26749bf5daf0602262e33464bcb3a042a8ff51ec2844cdeef2f9e5</sha256>
|
|
||||||
|
|
||||||
<tags>
|
|
||||||
<tag>beta</tag>
|
|
||||||
</tags>
|
|
||||||
|
|
||||||
<maintainer>Moko Consulting</maintainer>
|
|
||||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
|
||||||
|
|
||||||
<targetplatform name='joomla' version='(5|6)\..*'/>
|
|
||||||
</update>
|
|
||||||
|
|
||||||
</updates>
|
</updates>
|
||||||
|
|||||||
Reference in New Issue
Block a user