Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f2494de8b9 | |||
| 8d9653e0c9 | |||
| a3288c0042 | |||
| 203324a40b | |||
| f32fda306a | |||
| c38f5752b6 | |||
| 1b4984ed18 | |||
| ee8fc55d03 | |||
| f93d9c3e73 | |||
| 71cc1b6465 | |||
| b51ebf5534 | |||
| e9a0be9471 | |||
| 1cf063e08e | |||
| e3349bc043 | |||
| fb9e9ddc48 | |||
| d6e0036a0b | |||
| 6350b9cae7 | |||
| 009bdf3bcf | |||
| 08aebca9b2 | |||
| 7b74e09e2b | |||
| 1771a719c8 | |||
| adc1172829 | |||
| be63ddd8ec | |||
| 0055b7eaaf | |||
| faedeea34a | |||
| e070cb99f5 | |||
| 41bc58a8d0 | |||
| 8d53b2c80f | |||
| f781e0d9ae | |||
| ffa262f22b | |||
| b16b31c1de | |||
| 12a34619f2 | |||
| d69def86df | |||
| b4d843981b | |||
|
|
3de10bd2a2 | ||
| e9536a6998 |
345
.github/workflows/auto-release.yml
vendored
345
.github/workflows/auto-release.yml
vendored
@@ -5,7 +5,7 @@
|
|||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: MokoStandards.Release
|
# INGROUP: MokoStandards.Release
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
|
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||||
# PATH: /templates/workflows/joomla/auto-release.yml.template
|
# PATH: /templates/workflows/joomla/auto-release.yml.template
|
||||||
# VERSION: 04.06.00
|
# 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
|
||||||
@@ -22,13 +22,15 @@
|
|||||||
# | 4. Update [VERSION: XX.YY.ZZ] badges in markdown files |
|
# | 4. Update [VERSION: XX.YY.ZZ] badges in markdown files |
|
||||||
# | 5. Write updates.xml (Joomla update server XML) |
|
# | 5. Write updates.xml (Joomla update server XML) |
|
||||||
# | 6. Create git tag vXX.YY.ZZ |
|
# | 6. Create git tag vXX.YY.ZZ |
|
||||||
# | 7a. Patch: update existing GitHub Release for this minor |
|
# | 7a. Patch: update existing Gitea Release for this minor |
|
||||||
# | 8. Build ZIP, upload asset, write SHA-256 to updates.xml |
|
# | 8. Build ZIP, upload asset, write SHA-256 to updates.xml |
|
||||||
# | |
|
# | |
|
||||||
# | Every version change: archives main -> version/XX.YY branch |
|
# | Every version change: archives main -> version/XX.YY branch |
|
||||||
# | Patch 00 = development (no release). First release = patch 01. |
|
# | All patches release (including 00). Patch 00/01 = full pipeline. |
|
||||||
# | First release only (patch == 01): |
|
# | First release only (patch == 01): |
|
||||||
# | 7b. Create new GitHub Release |
|
# | 7b. Create new Gitea Release |
|
||||||
|
# | |
|
||||||
|
# | GitHub mirror: stable/rc releases only (continue-on-error) |
|
||||||
# | |
|
# | |
|
||||||
# +========================================================================+
|
# +========================================================================+
|
||||||
|
|
||||||
@@ -46,6 +48,9 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
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 }}
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -61,19 +66,21 @@ jobs:
|
|||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GA_TOKEN || github.token }}
|
token: ${{ secrets.GA_TOKEN }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set authenticated push URL
|
|
||||||
run: git remote set-url origin "https://jmiller:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
|
||||||
|
|
||||||
- name: Setup MokoStandards tools
|
- name: Setup MokoStandards tools
|
||||||
env:
|
env:
|
||||||
GA_TOKEN: ${{ secrets.GA_TOKEN || github.token }}
|
MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GA_TOKEN || github.token }}"}}'
|
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
||||||
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN }}"}}'
|
||||||
run: |
|
run: |
|
||||||
git clone --depth 1 --branch version/04 --quiet \
|
# Ensure PHP + Composer are available
|
||||||
"https://x-access-token:${GH_TOKEN}@git.mokoconsulting.tech/MokoConsulting/MokoStandards-API.git" \
|
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
|
||||||
|
git clone --depth 1 --branch main --quiet \
|
||||||
|
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \
|
||||||
/tmp/mokostandards-api
|
/tmp/mokostandards-api
|
||||||
cd /tmp/mokostandards-api
|
cd /tmp/mokostandards-api
|
||||||
composer install --no-dev --no-interaction --quiet
|
composer install --no-dev --no-interaction --quiet
|
||||||
@@ -99,20 +106,15 @@ jobs:
|
|||||||
echo "branch=version/${MAJOR}" >> "$GITHUB_OUTPUT"
|
echo "branch=version/${MAJOR}" >> "$GITHUB_OUTPUT"
|
||||||
echo "minor=$MINOR" >> "$GITHUB_OUTPUT"
|
echo "minor=$MINOR" >> "$GITHUB_OUTPUT"
|
||||||
echo "major=$MAJOR" >> "$GITHUB_OUTPUT"
|
echo "major=$MAJOR" >> "$GITHUB_OUTPUT"
|
||||||
echo "release_tag=v${MAJOR}" >> "$GITHUB_OUTPUT"
|
echo "release_tag=stable" >> "$GITHUB_OUTPUT"
|
||||||
if [ "$PATCH" = "00" ]; then
|
echo "stability=stable" >> "$GITHUB_OUTPUT"
|
||||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||||
echo "is_minor=false" >> "$GITHUB_OUTPUT"
|
if [ "$PATCH" = "00" ] || [ "$PATCH" = "01" ]; then
|
||||||
echo "Version: $VERSION (patch 00 = development — skipping release)"
|
echo "is_minor=true" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Version: $VERSION (first release for this minor — full pipeline)"
|
||||||
else
|
else
|
||||||
echo "skip=false" >> "$GITHUB_OUTPUT"
|
echo "is_minor=false" >> "$GITHUB_OUTPUT"
|
||||||
if [ "$PATCH" = "01" ]; then
|
echo "Version: $VERSION (patch — platform version + badges only)"
|
||||||
echo "is_minor=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Version: $VERSION (first release — full pipeline)"
|
|
||||||
else
|
|
||||||
echo "is_minor=false" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Version: $VERSION (patch — platform version + badges only)"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Check if already released
|
- name: Check if already released
|
||||||
@@ -131,11 +133,8 @@ jobs:
|
|||||||
echo "tag_exists=$TAG_EXISTS" >> "$GITHUB_OUTPUT"
|
echo "tag_exists=$TAG_EXISTS" >> "$GITHUB_OUTPUT"
|
||||||
echo "branch_exists=$BRANCH_EXISTS" >> "$GITHUB_OUTPUT"
|
echo "branch_exists=$BRANCH_EXISTS" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
if [ "$TAG_EXISTS" = "true" ] && [ "$BRANCH_EXISTS" = "true" ]; then
|
# Tag and branch may persist across patch releases — never skip
|
||||||
echo "already_released=true" >> "$GITHUB_OUTPUT"
|
echo "already_released=false" >> "$GITHUB_OUTPUT"
|
||||||
else
|
|
||||||
echo "already_released=false" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -- SANITY CHECKS -------------------------------------------------------
|
# -- SANITY CHECKS -------------------------------------------------------
|
||||||
- name: "Sanity: Pre-release validation"
|
- name: "Sanity: Pre-release validation"
|
||||||
@@ -291,9 +290,15 @@ jobs:
|
|||||||
[ -z "$EXT_NAME" ] && EXT_NAME="${{ github.event.repository.name }}"
|
[ -z "$EXT_NAME" ] && EXT_NAME="${{ github.event.repository.name }}"
|
||||||
[ -z "$EXT_TYPE" ] && EXT_TYPE="component"
|
[ -z "$EXT_TYPE" ] && EXT_TYPE="component"
|
||||||
|
|
||||||
# Templates/modules don't have <element> — derive from <name> (lowercased)
|
# Derive element if not in manifest:
|
||||||
|
# 1. Try XML filename (e.g. mokowaas.xml → mokowaas)
|
||||||
|
# 2. Fall back to repo name (lowercased)
|
||||||
if [ -z "$EXT_ELEMENT" ]; then
|
if [ -z "$EXT_ELEMENT" ]; then
|
||||||
EXT_ELEMENT=$(echo "$EXT_NAME" | tr '[:upper:]' '[:lower:]' | tr -d ' ')
|
EXT_ELEMENT=$(basename "$MANIFEST" .xml | tr '[:upper:]' '[:lower:]')
|
||||||
|
# If filename is generic (templateDetails, manifest), use repo name
|
||||||
|
case "$EXT_ELEMENT" in
|
||||||
|
templatedetails|manifest|*.xml) EXT_ELEMENT=$(echo "${{ github.event.repository.name }}" | tr '[:upper:]' '[:lower:]' | tr -d ' -') ;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build client tag: plugins and frontend modules need <client>site</client>
|
# Build client tag: plugins and frontend modules need <client>site</client>
|
||||||
@@ -312,7 +317,7 @@ jobs:
|
|||||||
|
|
||||||
# Build targetplatform (fallback to Joomla 5 if not in manifest)
|
# Build targetplatform (fallback to Joomla 5 if not in manifest)
|
||||||
if [ -z "$TARGET_PLATFORM" ]; then
|
if [ -z "$TARGET_PLATFORM" ]; then
|
||||||
TARGET_PLATFORM=$(printf '<targetplatform name="joomla" version="5.*" %s>' "/")
|
TARGET_PLATFORM=$(printf '<targetplatform name="joomla" version="((5.[0-9])|(6.[0-9]))" %s>' "/")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build php_minimum tag
|
# Build php_minimum tag
|
||||||
@@ -321,11 +326,12 @@ jobs:
|
|||||||
PHP_TAG="<php_minimum>${PHP_MINIMUM}</php_minimum>"
|
PHP_TAG="<php_minimum>${PHP_MINIMUM}</php_minimum>"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DOWNLOAD_URL="https://git.mokoconsulting.tech/${{ github.repository }}/releases/download/v${VERSION}/${EXT_ELEMENT}-${VERSION}.zip"
|
DOWNLOAD_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/stable/${EXT_ELEMENT}-${VERSION}.zip"
|
||||||
INFO_URL="https://git.mokoconsulting.tech/${{ github.repository }}/releases/tag/v${VERSION}"
|
INFO_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/stable"
|
||||||
|
|
||||||
# -- Build stable entry to temp file ─────────────────────────
|
# -- Build update entry for a given stability tag
|
||||||
{
|
build_entry() {
|
||||||
|
local TAG_NAME="$1"
|
||||||
printf '%s\n' ' <update>'
|
printf '%s\n' ' <update>'
|
||||||
printf '%s\n' " <name>${EXT_NAME}</name>"
|
printf '%s\n' " <name>${EXT_NAME}</name>"
|
||||||
printf '%s\n' " <description>${EXT_NAME} update</description>"
|
printf '%s\n' " <description>${EXT_NAME} update</description>"
|
||||||
@@ -334,9 +340,7 @@ jobs:
|
|||||||
printf '%s\n' " <version>${VERSION}</version>"
|
printf '%s\n' " <version>${VERSION}</version>"
|
||||||
[ -n "$CLIENT_TAG" ] && printf '%s\n' " ${CLIENT_TAG}"
|
[ -n "$CLIENT_TAG" ] && printf '%s\n' " ${CLIENT_TAG}"
|
||||||
[ -n "$FOLDER_TAG" ] && printf '%s\n' " ${FOLDER_TAG}"
|
[ -n "$FOLDER_TAG" ] && printf '%s\n' " ${FOLDER_TAG}"
|
||||||
printf '%s\n' ' <tags>'
|
printf '%s\n' " <tags><tag>${TAG_NAME}</tag></tags>"
|
||||||
printf '%s\n' ' <tag>stable</tag>'
|
|
||||||
printf '%s\n' ' </tags>'
|
|
||||||
printf '%s\n' " <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>"
|
printf '%s\n' " <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>"
|
||||||
printf '%s\n' ' <downloads>'
|
printf '%s\n' ' <downloads>'
|
||||||
printf '%s\n' " <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>"
|
printf '%s\n' " <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>"
|
||||||
@@ -346,35 +350,27 @@ jobs:
|
|||||||
printf '%s\n' ' <maintainer>Moko Consulting</maintainer>'
|
printf '%s\n' ' <maintainer>Moko Consulting</maintainer>'
|
||||||
printf '%s\n' ' <maintainerurl>https://mokoconsulting.tech</maintainerurl>'
|
printf '%s\n' ' <maintainerurl>https://mokoconsulting.tech</maintainerurl>'
|
||||||
printf '%s\n' ' </update>'
|
printf '%s\n' ' </update>'
|
||||||
} > /tmp/stable_entry.xml
|
}
|
||||||
|
|
||||||
# -- Write updates.xml preserving dev/rc entries ──────────────
|
|
||||||
# Extract existing entries for other stability levels
|
|
||||||
# Order reflects release workflow: development → alpha → beta → rc → stable
|
|
||||||
if [ -f "updates.xml" ]; then
|
|
||||||
printf 'import re, sys\n' > /tmp/extract.py
|
|
||||||
printf 'with open("updates.xml") as f: c = f.read()\n' >> /tmp/extract.py
|
|
||||||
printf 'tag = sys.argv[1]\n' >> /tmp/extract.py
|
|
||||||
printf 'm = re.search(r"( <update>.*?<tag>" + re.escape(tag) + r"</tag>.*?</update>)", c, re.DOTALL)\n' >> /tmp/extract.py
|
|
||||||
printf 'if m: print(m.group(1))\n' >> /tmp/extract.py
|
|
||||||
fi
|
|
||||||
DEV_ENTRY=$(python3 /tmp/extract.py development 2>/dev/null || true)
|
|
||||||
ALPHA_ENTRY=$(python3 /tmp/extract.py alpha 2>/dev/null || true)
|
|
||||||
BETA_ENTRY=$(python3 /tmp/extract.py beta 2>/dev/null || true)
|
|
||||||
RC_ENTRY=$(python3 /tmp/extract.py rc 2>/dev/null || true)
|
|
||||||
|
|
||||||
|
# -- Write updates.xml with cascading channels
|
||||||
|
# Stable release updates ALL channels (development, alpha, beta, rc, stable)
|
||||||
{
|
{
|
||||||
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
|
printf '%s\n' "<?xml version='1.0' encoding='UTF-8'?>"
|
||||||
|
printf '%s\n' "<!-- Copyright (C) $(date +%Y) Moko Consulting <hello@mokoconsulting.tech>"
|
||||||
|
printf '%s\n' " SPDX-License-Identifier: GPL-3.0-or-later"
|
||||||
|
printf '%s\n' " VERSION: ${VERSION}"
|
||||||
|
printf '%s\n' " -->"
|
||||||
|
printf '%s\n' ""
|
||||||
printf '%s\n' '<updates>'
|
printf '%s\n' '<updates>'
|
||||||
[ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY"
|
build_entry "development"
|
||||||
[ -n "$ALPHA_ENTRY" ] && echo "$ALPHA_ENTRY"
|
build_entry "alpha"
|
||||||
[ -n "$BETA_ENTRY" ] && echo "$BETA_ENTRY"
|
build_entry "beta"
|
||||||
[ -n "$RC_ENTRY" ] && echo "$RC_ENTRY"
|
build_entry "rc"
|
||||||
cat /tmp/stable_entry.xml
|
build_entry "stable"
|
||||||
printf '%s\n' '</updates>'
|
printf '%s\n' '</updates>'
|
||||||
} > updates.xml
|
} > updates.xml
|
||||||
|
|
||||||
echo "updates.xml: ${VERSION} (stable + rc/dev preserved)" >> $GITHUB_STEP_SUMMARY
|
echo "updates.xml: ${VERSION} (all channels updated to stable)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
# -- Commit all changes ---------------------------------------------------
|
# -- Commit all changes ---------------------------------------------------
|
||||||
- name: Commit release changes
|
- name: Commit release changes
|
||||||
@@ -389,10 +385,12 @@ jobs:
|
|||||||
VERSION="${{ steps.version.outputs.version }}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||||
git config --local user.name "gitea-actions[bot]"
|
git config --local user.name "gitea-actions[bot]"
|
||||||
|
# Set push URL with token for branch-protected repos
|
||||||
|
git remote set-url origin "https://jmiller:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
||||||
git add -A
|
git add -A
|
||||||
git commit -m "chore(release): build ${VERSION} [skip ci]" \
|
git commit -m "chore(release): build ${VERSION} [skip ci]" \
|
||||||
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>"
|
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>"
|
||||||
git push
|
git push -u origin HEAD
|
||||||
|
|
||||||
# -- STEP 6: Create tag ---------------------------------------------------
|
# -- STEP 6: Create tag ---------------------------------------------------
|
||||||
- name: "Step 6: Create git tag"
|
- name: "Step 6: Create git tag"
|
||||||
@@ -412,69 +410,75 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
echo "Tag: ${TAG}" >> $GITHUB_STEP_SUMMARY
|
echo "Tag: ${TAG}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
# -- STEP 7: Create or update GitHub Release ------------------------------
|
# -- STEP 7: Create or update Gitea Release --------------------------------
|
||||||
- name: "Step 7: GitHub Release"
|
- name: "Step 7: Gitea Release"
|
||||||
if: >-
|
if: >-
|
||||||
steps.version.outputs.skip != 'true' &&
|
steps.version.outputs.skip != 'true'
|
||||||
steps.check.outputs.tag_exists != 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GA_TOKEN || github.token }}
|
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
||||||
BRANCH="${{ steps.version.outputs.branch }}"
|
BRANCH="${{ steps.version.outputs.branch }}"
|
||||||
MAJOR="${{ steps.version.outputs.major }}"
|
MAJOR="${{ steps.version.outputs.major }}"
|
||||||
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
|
||||||
NOTES=$(php /tmp/mokostandards-api/cli/release_notes.php --path . --version "$VERSION" 2>/dev/null)
|
NOTES=$(php /tmp/mokostandards-api/cli/release_notes.php --path . --version "$VERSION" 2>/dev/null)
|
||||||
[ -z "$NOTES" ] && NOTES="Release ${VERSION}"
|
[ -z "$NOTES" ] && NOTES="Release ${VERSION}"
|
||||||
echo "$NOTES" > /tmp/release_notes.md
|
|
||||||
|
|
||||||
# Check if the major release already exists
|
# Check if the major release already exists
|
||||||
EXISTING=$(gh release view "$RELEASE_TAG" --json tagName -q .tagName 2>/dev/null || true)
|
EXISTING=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
"${API_BASE}/releases/tags/${RELEASE_TAG}" 2>/dev/null || true)
|
||||||
|
EXISTING_ID=$(echo "$EXISTING" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('id',''))" 2>/dev/null || true)
|
||||||
|
|
||||||
if [ -z "$EXISTING" ]; then
|
if [ -z "$EXISTING_ID" ]; then
|
||||||
# First release for this major
|
# First release for this major
|
||||||
gh release create "$RELEASE_TAG" \
|
curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
--title "v${MAJOR} (latest: ${VERSION})" \
|
-H "Content-Type: application/json" \
|
||||||
--notes-file /tmp/release_notes.md \
|
"${API_BASE}/releases" \
|
||||||
--target "$BRANCH"
|
-d "$(python3 -c "import json; print(json.dumps({
|
||||||
|
'tag_name': '${RELEASE_TAG}',
|
||||||
|
'name': 'v${MAJOR} (latest: ${VERSION})',
|
||||||
|
'body': '''${NOTES}''',
|
||||||
|
'target_commitish': '${BRANCH}'
|
||||||
|
}))")"
|
||||||
echo "Release created: ${RELEASE_TAG} (${VERSION})" >> $GITHUB_STEP_SUMMARY
|
echo "Release created: ${RELEASE_TAG} (${VERSION})" >> $GITHUB_STEP_SUMMARY
|
||||||
else
|
else
|
||||||
# Append version notes to existing major release
|
# Append version notes to existing major release
|
||||||
CURRENT_NOTES=$(gh release view "$RELEASE_TAG" --json body -q .body 2>/dev/null || true)
|
CURRENT_BODY=$(echo "$EXISTING" | python3 -c "import sys,json; print(json.load(sys.stdin).get('body',''))" 2>/dev/null || true)
|
||||||
{
|
UPDATED_BODY="${CURRENT_BODY}
|
||||||
echo "$CURRENT_NOTES"
|
|
||||||
echo ""
|
|
||||||
echo "---"
|
|
||||||
echo "### ${VERSION}"
|
|
||||||
echo ""
|
|
||||||
cat /tmp/release_notes.md
|
|
||||||
} > /tmp/updated_notes.md
|
|
||||||
|
|
||||||
gh release edit "$RELEASE_TAG" \
|
---
|
||||||
--title "v${MAJOR} (latest: ${VERSION})" \
|
### ${VERSION}
|
||||||
--notes-file /tmp/updated_notes.md
|
|
||||||
|
${NOTES}"
|
||||||
|
|
||||||
|
curl -sf -X PATCH -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${API_BASE}/releases/${EXISTING_ID}" \
|
||||||
|
-d "$(python3 -c "import json,sys; print(json.dumps({
|
||||||
|
'name': 'v${MAJOR} (latest: ${VERSION})',
|
||||||
|
'body': sys.stdin.read()
|
||||||
|
}))" <<< "$UPDATED_BODY")"
|
||||||
echo "Release updated: ${RELEASE_TAG} -> ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
echo "Release updated: ${RELEASE_TAG} -> ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# -- STEP 8: Build Joomla install ZIP + SHA-256 checksum ------------------
|
# -- STEP 8: Build Joomla install ZIP + SHA-256 checksum ------------------
|
||||||
# Every patch builds an install-ready ZIP and uploads it to the minor release.
|
|
||||||
# Result: one Release per minor version with a ZIP for each patch.
|
|
||||||
- name: "Step 8: Build Joomla package and update checksum"
|
- name: "Step 8: Build Joomla package and update checksum"
|
||||||
if: >-
|
if: >-
|
||||||
steps.version.outputs.skip != 'true'
|
steps.version.outputs.skip != 'true'
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GA_TOKEN || github.token }}
|
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
||||||
REPO="${{ github.repository }}"
|
REPO="${{ github.repository }}"
|
||||||
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
|
||||||
# All ZIPs upload to the major release tag (vXX)
|
# All ZIPs upload to the major release tag (vXX)
|
||||||
gh release view "$RELEASE_TAG" --json tagName > /dev/null 2>&1 || {
|
RELEASE_JSON=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
"${API_BASE}/releases/tags/${RELEASE_TAG}" 2>/dev/null || true)
|
||||||
|
RELEASE_ID=$(echo "$RELEASE_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||||
|
if [ -z "$RELEASE_ID" ]; then
|
||||||
echo "No release ${RELEASE_TAG} found — skipping ZIP upload"
|
echo "No release ${RELEASE_TAG} found — skipping ZIP upload"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
fi
|
||||||
|
|
||||||
# Find extension element name from manifest
|
# Find extension element name from manifest
|
||||||
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)
|
||||||
@@ -508,27 +512,109 @@ jobs:
|
|||||||
SHA256_ZIP=$(sha256sum "/tmp/${ZIP_NAME}" | cut -d' ' -f1)
|
SHA256_ZIP=$(sha256sum "/tmp/${ZIP_NAME}" | cut -d' ' -f1)
|
||||||
SHA256_TAR=$(sha256sum "/tmp/${TAR_NAME}" | cut -d' ' -f1)
|
SHA256_TAR=$(sha256sum "/tmp/${TAR_NAME}" | cut -d' ' -f1)
|
||||||
|
|
||||||
|
# -- Delete existing assets with same name before uploading ------
|
||||||
|
ASSETS=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
"${API_BASE}/releases/${RELEASE_ID}/assets" 2>/dev/null || echo "[]")
|
||||||
|
for ASSET_NAME in "$ZIP_NAME" "$TAR_NAME"; do
|
||||||
|
ASSET_ID=$(echo "$ASSETS" | python3 -c "
|
||||||
|
import sys,json
|
||||||
|
assets = json.load(sys.stdin)
|
||||||
|
for a in assets:
|
||||||
|
if a['name'] == '${ASSET_NAME}':
|
||||||
|
print(a['id']); break
|
||||||
|
" 2>/dev/null || true)
|
||||||
|
if [ -n "$ASSET_ID" ]; then
|
||||||
|
curl -sf -X DELETE -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
"${API_BASE}/releases/${RELEASE_ID}/assets/${ASSET_ID}" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# -- Upload both to release tag ----------------------------------
|
# -- Upload both to release tag ----------------------------------
|
||||||
gh release upload "$RELEASE_TAG" "/tmp/${ZIP_NAME}" --clobber 2>/dev/null || true
|
curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
gh release upload "$RELEASE_TAG" "/tmp/${TAR_NAME}" --clobber 2>/dev/null || true
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @"/tmp/${ZIP_NAME}" \
|
||||||
|
"${API_BASE}/releases/${RELEASE_ID}/assets?name=${ZIP_NAME}" > /dev/null 2>&1 || true
|
||||||
|
|
||||||
|
curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @"/tmp/${TAR_NAME}" \
|
||||||
|
"${API_BASE}/releases/${RELEASE_ID}/assets?name=${TAR_NAME}" > /dev/null 2>&1 || true
|
||||||
|
|
||||||
# -- Update updates.xml with both download formats ---------------
|
# -- Update updates.xml with both download formats ---------------
|
||||||
if [ -f "updates.xml" ]; then
|
if [ -f "updates.xml" ]; then
|
||||||
ZIP_URL="https://git.mokoconsulting.tech/${{ github.repository }}/releases/download/${RELEASE_TAG}/${ZIP_NAME}"
|
ZIP_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${ZIP_NAME}"
|
||||||
TAR_URL="https://git.mokoconsulting.tech/${{ github.repository }}/releases/download/${RELEASE_TAG}/${TAR_NAME}"
|
TAR_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${TAR_NAME}"
|
||||||
|
|
||||||
# Replace downloads block with both formats + SHA
|
# Use Python to update only the stable entry's downloads + sha256
|
||||||
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
|
export PY_ZIP_URL="$ZIP_URL" PY_TAR_URL="$TAR_URL" PY_SHA="$SHA256_ZIP"
|
||||||
if grep -q '<sha256>' updates.xml; then
|
python3 << 'PYEOF'
|
||||||
sed -i "s|<sha256>.*</sha256>|<sha256>${SHA256_ZIP}</sha256>|" updates.xml
|
import re, os
|
||||||
else
|
|
||||||
sed -i "s|</downloads>|</downloads>\n <sha256>${SHA256_ZIP}</sha256>|" updates.xml
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
with open("updates.xml") as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
zip_url = os.environ["PY_ZIP_URL"]
|
||||||
|
tar_url = os.environ["PY_TAR_URL"]
|
||||||
|
sha = os.environ["PY_SHA"]
|
||||||
|
|
||||||
|
# Find the stable update block and replace its downloads + sha256
|
||||||
|
def replace_stable(m):
|
||||||
|
block = m.group(0)
|
||||||
|
# Replace downloads block
|
||||||
|
new_downloads = (
|
||||||
|
" <downloads>\n"
|
||||||
|
f" <downloadurl type=\"full\" format=\"zip\">{zip_url}</downloadurl>\n"
|
||||||
|
" </downloads>"
|
||||||
|
)
|
||||||
|
block = re.sub(r' <downloads>.*?</downloads>', new_downloads, block, flags=re.DOTALL)
|
||||||
|
# Add or replace sha256
|
||||||
|
if '<sha256>' in block:
|
||||||
|
block = re.sub(r' <sha256>.*?</sha256>', f' <sha256>{sha}</sha256>', block)
|
||||||
|
else:
|
||||||
|
block = block.replace('</downloads>', f'</downloads>\n <sha256>{sha}</sha256>')
|
||||||
|
return block
|
||||||
|
|
||||||
|
content = re.sub(
|
||||||
|
r' <update>.*?<tag>stable</tag>.*?</update>',
|
||||||
|
replace_stable,
|
||||||
|
content,
|
||||||
|
flags=re.DOTALL
|
||||||
|
)
|
||||||
|
|
||||||
|
with open("updates.xml", "w") as f:
|
||||||
|
f.write(content)
|
||||||
|
PYEOF
|
||||||
|
|
||||||
|
CURRENT_BRANCH="${{ github.ref_name }}"
|
||||||
git add updates.xml
|
git add updates.xml
|
||||||
git commit -m "chore(release): ZIP + tar.gz for ${VERSION} [skip ci]" \
|
git commit -m "chore(release): ZIP + tar.gz for ${VERSION} [skip ci]" \
|
||||||
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>" || true
|
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>" || true
|
||||||
git push || true
|
git push || true
|
||||||
|
|
||||||
|
# Sync updates.xml to main via direct API (always runs — may be on version/XX branch)
|
||||||
|
GA_TOKEN="${{ secrets.GA_TOKEN }}"
|
||||||
|
API="${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}"
|
||||||
|
|
||||||
|
FILE_SHA=$(curl -sf -H "Authorization: token ${GA_TOKEN}" \
|
||||||
|
"${API}/contents/updates.xml?ref=main" | jq -r '.sha // empty')
|
||||||
|
|
||||||
|
if [ -n "$FILE_SHA" ]; then
|
||||||
|
CONTENT=$(base64 -w0 updates.xml)
|
||||||
|
curl -sf -X PUT -H "Authorization: token ${GA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${API}/contents/updates.xml" \
|
||||||
|
-d "$(jq -n \
|
||||||
|
--arg content "$CONTENT" \
|
||||||
|
--arg sha "$FILE_SHA" \
|
||||||
|
--arg msg "chore: sync updates.xml ${VERSION} [skip ci]" \
|
||||||
|
--arg branch "main" \
|
||||||
|
'{content: $content, sha: $sha, message: $msg, branch: $branch}'
|
||||||
|
)" > /dev/null 2>&1 \
|
||||||
|
&& echo "updates.xml synced to main via API" \
|
||||||
|
|| echo "WARNING: failed to sync updates.xml to main"
|
||||||
|
else
|
||||||
|
echo "WARNING: could not get updates.xml SHA from main"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "### Joomla Packages" >> $GITHUB_STEP_SUMMARY
|
echo "### Joomla Packages" >> $GITHUB_STEP_SUMMARY
|
||||||
@@ -538,7 +624,50 @@ jobs:
|
|||||||
echo "| \`${ZIP_NAME}\` | ${ZIP_SIZE} | \`${SHA256_ZIP}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| \`${ZIP_NAME}\` | ${ZIP_SIZE} | \`${SHA256_ZIP}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| \`${TAR_NAME}\` | ${TAR_SIZE} | \`${SHA256_TAR}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| \`${TAR_NAME}\` | ${TAR_SIZE} | \`${SHA256_TAR}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Release | \`${RELEASE_TAG}\` | |" >> $GITHUB_STEP_SUMMARY
|
echo "| Release | \`${RELEASE_TAG}\` | |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Download | [${PACKAGE_NAME}](https://git.mokoconsulting.tech/${{ github.repository }}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}) |" >> $GITHUB_STEP_SUMMARY
|
echo "| Download | [${ZIP_NAME}](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${ZIP_NAME}) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
|
||||||
|
- name: "Step 9: Mirror release to GitHub"
|
||||||
|
if: >-
|
||||||
|
steps.version.outputs.skip != 'true' &&
|
||||||
|
steps.version.outputs.stability == 'stable' &&
|
||||||
|
secrets.GH_TOKEN != ''
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
||||||
|
MAJOR="${{ steps.version.outputs.major }}"
|
||||||
|
BRANCH="${{ steps.version.outputs.branch }}"
|
||||||
|
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
||||||
|
|
||||||
|
NOTES=$(php /tmp/mokostandards-api/cli/release_notes.php --path . --version "$VERSION" 2>/dev/null || true)
|
||||||
|
[ -z "$NOTES" ] && NOTES="Release ${VERSION}"
|
||||||
|
echo "$NOTES" > /tmp/release_notes.md
|
||||||
|
|
||||||
|
EXISTING=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}/releases/tags/$RELEASE_TAG" 2>/dev/null | jq -r ".tag_name // empty" || true)
|
||||||
|
|
||||||
|
if [ -z "$EXISTING" ]; then
|
||||||
|
gh release create "$RELEASE_TAG" \
|
||||||
|
--repo "$GH_REPO" \
|
||||||
|
--title "v${MAJOR} (latest: ${VERSION})" \
|
||||||
|
--notes-file /tmp/release_notes.md \
|
||||||
|
--target "$BRANCH" || true
|
||||||
|
else
|
||||||
|
gh release edit "$RELEASE_TAG" \
|
||||||
|
--repo "$GH_REPO" \
|
||||||
|
--title "v${MAJOR} (latest: ${VERSION})" || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Upload assets to GitHub mirror
|
||||||
|
for PKG in /tmp/${EXT_ELEMENT:-pkg}-${VERSION}.*; do
|
||||||
|
if [ -f "$PKG" ]; then
|
||||||
|
_RELID=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}/releases/tags/$RELEASE_TAG" 2>/dev/null | jq -r ".id // empty")
|
||||||
|
[ -n "$_RELID" ] && curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" -H "Content-Type: application/octet-stream" "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}/releases/${_RELID}/assets?name=$(basename $PKG)" --data-binary "@$PKG" > /dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "GitHub mirror updated: ${GH_REPO} ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
# -- Summary --------------------------------------------------------------
|
# -- Summary --------------------------------------------------------------
|
||||||
- name: Pipeline Summary
|
- name: Pipeline Summary
|
||||||
@@ -559,5 +688,5 @@ jobs:
|
|||||||
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Release | [View](https://github.com/${{ github.repository }}/releases/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
|
fi
|
||||||
|
|||||||
284
.github/workflows/update-server.yml
vendored
284
.github/workflows/update-server.yml
vendored
@@ -5,7 +5,7 @@
|
|||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: MokoStandards.Joomla
|
# INGROUP: MokoStandards.Joomla
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
|
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||||
# PATH: /templates/workflows/joomla/update-server.yml.template
|
# PATH: /templates/workflows/joomla/update-server.yml.template
|
||||||
# VERSION: 04.06.00
|
# 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
|
||||||
@@ -13,16 +13,27 @@
|
|||||||
# Writes updates.xml with multiple <update> entries:
|
# Writes updates.xml with multiple <update> entries:
|
||||||
# - <tag>stable</tag> on push to main (from auto-release)
|
# - <tag>stable</tag> on push to main (from auto-release)
|
||||||
# - <tag>rc</tag> on push to rc/**
|
# - <tag>rc</tag> on push to rc/**
|
||||||
# - <tag>development</tag> on push to dev/**
|
# - <tag>development</tag> on push to dev or dev/**
|
||||||
#
|
#
|
||||||
# Joomla filters by user's "Minimum Stability" setting.
|
# Joomla filters by user's "Minimum Stability" setting.
|
||||||
|
|
||||||
name: Update Joomla Update Server XML Feed
|
name: Update Joomla Update Server XML Feed
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'dev'
|
||||||
|
- 'dev/**'
|
||||||
|
- 'alpha/**'
|
||||||
|
- 'beta/**'
|
||||||
|
- 'rc/**'
|
||||||
|
paths:
|
||||||
|
- 'src/**'
|
||||||
|
- 'htdocs/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [closed]
|
types: [closed]
|
||||||
branches:
|
branches:
|
||||||
|
- 'dev'
|
||||||
- 'dev/**'
|
- 'dev/**'
|
||||||
- 'alpha/**'
|
- 'alpha/**'
|
||||||
- 'beta/**'
|
- 'beta/**'
|
||||||
@@ -46,6 +57,9 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
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 }}
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -55,45 +69,49 @@ jobs:
|
|||||||
name: Update updates.xml
|
name: Update updates.xml
|
||||||
runs-on: release
|
runs-on: release
|
||||||
if: >-
|
if: >-
|
||||||
github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
|
github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' || github.event_name == 'push'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GA_TOKEN || github.token }}
|
token: ${{ secrets.GA_TOKEN }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup MokoStandards tools
|
- name: Setup MokoStandards tools
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GA_TOKEN || github.token }}
|
MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GA_TOKEN || github.token }}"}}'
|
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
||||||
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN }}"}}'
|
||||||
run: |
|
run: |
|
||||||
git clone --depth 1 --branch version/04 --quiet \
|
if ! command -v composer &> /dev/null; then
|
||||||
"https://x-access-token:${GH_TOKEN}@git.mokoconsulting.tech/MokoConsulting/MokoStandards.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/mokostandards 2>/dev/null || true
|
fi
|
||||||
if [ -d "/tmp/mokostandards" ] && [ -f "/tmp/mokostandards/composer.json" ]; then
|
git clone --depth 1 --branch main --quiet \
|
||||||
cd /tmp/mokostandards && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
|
"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
|
fi
|
||||||
|
|
||||||
- name: Generate updates.xml entry
|
- name: Generate updates.xml entry
|
||||||
|
id: update
|
||||||
run: |
|
run: |
|
||||||
BRANCH="${{ github.ref_name }}"
|
BRANCH="${{ github.ref_name }}"
|
||||||
REPO="${{ github.repository }}"
|
REPO="${{ github.repository }}"
|
||||||
VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null || echo "0.0.0")
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
VERSION=$(php /tmp/mokostandards-api/cli/version_read.php --path . 2>/dev/null || echo "0.0.0")
|
||||||
|
|
||||||
# Auto-bump patch on alpha/beta/rc branches (not dev — dev bumps manually)
|
# Auto-bump patch on all branches (dev, alpha, beta, rc)
|
||||||
if [[ "$BRANCH" != dev/* ]]; then
|
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
git config --local user.name "gitea-actions[bot]"
|
||||||
git config --local user.name "gitea-actions[bot]"
|
BUMPED=$(php /tmp/mokostandards-api/cli/version_bump.php --path . 2>/dev/null || true)
|
||||||
BUMPED=$(php /tmp/mokostandards/api/cli/version_bump.php --path . 2>/dev/null || true)
|
if [ -n "$BUMPED" ]; then
|
||||||
if [ -n "$BUMPED" ]; then
|
VERSION=$(php /tmp/mokostandards-api/cli/version_read.php --path . 2>/dev/null || echo "$VERSION")
|
||||||
VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null || echo "$VERSION")
|
git add -A
|
||||||
git add -A
|
git commit -m "chore(version): auto-bump patch ${VERSION} [skip ci]" \
|
||||||
git commit -m "chore(version): auto-bump patch ${VERSION} [skip ci]" \
|
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>" 2>/dev/null || true
|
||||||
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>" 2>/dev/null || true
|
git push 2>/dev/null || true
|
||||||
git push 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Determine stability from branch or input
|
# Determine stability from branch or input
|
||||||
@@ -105,12 +123,14 @@ jobs:
|
|||||||
STABILITY="beta"
|
STABILITY="beta"
|
||||||
elif [[ "$BRANCH" == alpha/* ]]; then
|
elif [[ "$BRANCH" == alpha/* ]]; then
|
||||||
STABILITY="alpha"
|
STABILITY="alpha"
|
||||||
elif [[ "$BRANCH" == dev/* ]]; then
|
elif [[ "$BRANCH" == dev/* ]] || [[ "$BRANCH" == "dev" ]]; then
|
||||||
STABILITY="development"
|
STABILITY="development"
|
||||||
else
|
else
|
||||||
STABILITY="stable"
|
STABILITY="stable"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
# Parse manifest (portable — no grep -P)
|
# 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
|
||||||
@@ -132,15 +152,18 @@ jobs:
|
|||||||
[ -z "$EXT_NAME" ] && EXT_NAME="${{ github.event.repository.name }}"
|
[ -z "$EXT_NAME" ] && EXT_NAME="${{ github.event.repository.name }}"
|
||||||
[ -z "$EXT_TYPE" ] && EXT_TYPE="component"
|
[ -z "$EXT_TYPE" ] && EXT_TYPE="component"
|
||||||
|
|
||||||
# Templates and modules don't have <element> — derive from <name>
|
# Derive element if not in manifest: try XML filename, then repo name
|
||||||
if [ -z "$EXT_ELEMENT" ]; then
|
if [ -z "$EXT_ELEMENT" ]; then
|
||||||
EXT_ELEMENT=$(echo "$EXT_NAME" | tr '[:upper:]' '[:lower:]' | tr -d ' ')
|
EXT_ELEMENT=$(basename "$MANIFEST" .xml | tr '[:upper:]' '[:lower:]')
|
||||||
|
case "$EXT_ELEMENT" in
|
||||||
|
templatedetails|manifest|*.xml) EXT_ELEMENT=$(echo "${{ github.event.repository.name }}" | tr '[:upper:]' '[:lower:]' | tr -d ' -') ;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use manifest version if README version is empty
|
# Use manifest version if README version is empty
|
||||||
[ "$VERSION" = "0.0.0" ] && [ -n "$EXT_VERSION" ] && VERSION="$EXT_VERSION"
|
[ "$VERSION" = "0.0.0" ] && [ -n "$EXT_VERSION" ] && VERSION="$EXT_VERSION"
|
||||||
|
|
||||||
[ -z "$TARGET_PLATFORM" ] && TARGET_PLATFORM=$(printf '<targetplatform name="joomla" version="5.*" %s>' "/")
|
[ -z "$TARGET_PLATFORM" ] && TARGET_PLATFORM=$(printf '<targetplatform name="joomla" version="((5.[0-9])|(6.[0-9]))" %s>' "/")
|
||||||
|
|
||||||
CLIENT_TAG=""
|
CLIENT_TAG=""
|
||||||
[ -n "$EXT_CLIENT" ] && CLIENT_TAG="<client>${EXT_CLIENT}</client>"
|
[ -n "$EXT_CLIENT" ] && CLIENT_TAG="<client>${EXT_CLIENT}</client>"
|
||||||
@@ -173,10 +196,10 @@ jobs:
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
PACKAGE_NAME="${EXT_ELEMENT}-${DISPLAY_VERSION}.zip"
|
PACKAGE_NAME="${EXT_ELEMENT}-${DISPLAY_VERSION}.zip"
|
||||||
DOWNLOAD_URL="https://git.mokoconsulting.tech/${{ github.repository }}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}"
|
DOWNLOAD_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}"
|
||||||
INFO_URL="https://github.com/${REPO}"
|
INFO_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
|
||||||
# ── Build install packages (ZIP + tar.gz) ───────────────────
|
# -- 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
|
||||||
@@ -192,20 +215,62 @@ jobs:
|
|||||||
|
|
||||||
SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1)
|
SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1)
|
||||||
|
|
||||||
# Ensure release exists
|
# Ensure release exists on Gitea
|
||||||
gh release view "$RELEASE_TAG" --json tagName > /dev/null 2>&1 || \
|
RELEASE_JSON=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
gh release create "$RELEASE_TAG" --title "${RELEASE_TAG} (${DISPLAY_VERSION})" --notes "${STABILITY} release" --prerelease --target main 2>/dev/null || true
|
"${API_BASE}/releases/tags/${RELEASE_TAG}" 2>/dev/null || true)
|
||||||
|
RELEASE_ID=$(echo "$RELEASE_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||||
|
|
||||||
# Upload both formats
|
if [ -z "$RELEASE_ID" ]; then
|
||||||
gh release upload "$RELEASE_TAG" "/tmp/${PACKAGE_NAME}" --clobber 2>/dev/null || true
|
# Create release
|
||||||
gh release upload "$RELEASE_TAG" "/tmp/${TAR_NAME}" --clobber 2>/dev/null || true
|
RELEASE_JSON=$(curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${API_BASE}/releases" \
|
||||||
|
-d "$(python3 -c "import json; print(json.dumps({
|
||||||
|
'tag_name': '${RELEASE_TAG}',
|
||||||
|
'name': '${RELEASE_TAG} (${DISPLAY_VERSION})',
|
||||||
|
'body': '${STABILITY} release',
|
||||||
|
'prerelease': True,
|
||||||
|
'target_commitish': 'main'
|
||||||
|
}))")" 2>/dev/null || true)
|
||||||
|
RELEASE_ID=$(echo "$RELEASE_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$RELEASE_ID" ]; then
|
||||||
|
# Delete existing assets with same name before uploading
|
||||||
|
ASSETS=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
"${API_BASE}/releases/${RELEASE_ID}/assets" 2>/dev/null || echo "[]")
|
||||||
|
for ASSET_FILE in "$PACKAGE_NAME" "$TAR_NAME"; do
|
||||||
|
ASSET_ID=$(echo "$ASSETS" | python3 -c "
|
||||||
|
import sys,json
|
||||||
|
assets = json.load(sys.stdin)
|
||||||
|
for a in assets:
|
||||||
|
if a['name'] == '${ASSET_FILE}':
|
||||||
|
print(a['id']); break
|
||||||
|
" 2>/dev/null || true)
|
||||||
|
if [ -n "$ASSET_ID" ]; then
|
||||||
|
curl -sf -X DELETE -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
"${API_BASE}/releases/${RELEASE_ID}/assets/${ASSET_ID}" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Upload both formats
|
||||||
|
curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @"/tmp/${PACKAGE_NAME}" \
|
||||||
|
"${API_BASE}/releases/${RELEASE_ID}/assets?name=${PACKAGE_NAME}" > /dev/null 2>&1 || true
|
||||||
|
|
||||||
|
curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @"/tmp/${TAR_NAME}" \
|
||||||
|
"${API_BASE}/releases/${RELEASE_ID}/assets?name=${TAR_NAME}" > /dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Packages: ${PACKAGE_NAME} + ${TAR_NAME} (SHA: ${SHA256})" >> $GITHUB_STEP_SUMMARY
|
echo "Packages: ${PACKAGE_NAME} + ${TAR_NAME} (SHA: ${SHA256})" >> $GITHUB_STEP_SUMMARY
|
||||||
else
|
else
|
||||||
SHA256=""
|
SHA256=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Build the new entry ───────────────────────────────────────
|
# -- Build the new entry -----------------------------------------
|
||||||
NEW_ENTRY=""
|
NEW_ENTRY=""
|
||||||
NEW_ENTRY="${NEW_ENTRY} <update>\n"
|
NEW_ENTRY="${NEW_ENTRY} <update>\n"
|
||||||
NEW_ENTRY="${NEW_ENTRY} <name>${EXT_NAME}</name>\n"
|
NEW_ENTRY="${NEW_ENTRY} <name>${EXT_NAME}</name>\n"
|
||||||
@@ -220,40 +285,76 @@ 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://git.mokoconsulting.tech/${{ github.repository }}/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>\n"
|
||||||
NEW_ENTRY="${NEW_ENTRY} ${TARGET_PLATFORM}\n"
|
NEW_ENTRY="${NEW_ENTRY} ${TARGET_PLATFORM}\n"
|
||||||
[ -n "$PHP_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${PHP_TAG}\n"
|
[ -n "$PHP_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${PHP_TAG}\n"
|
||||||
NEW_ENTRY="${NEW_ENTRY} <maintainer>Moko Consulting</maintainer>\n"
|
NEW_ENTRY="${NEW_ENTRY} <maintainer>Moko Consulting</maintainer>\n"
|
||||||
NEW_ENTRY="${NEW_ENTRY} <maintainerurl>https://mokoconsulting.tech</maintainerurl>\n"
|
NEW_ENTRY="${NEW_ENTRY} <maintainerurl>https://mokoconsulting.tech</maintainerurl>\n"
|
||||||
NEW_ENTRY="${NEW_ENTRY} </update>"
|
NEW_ENTRY="${NEW_ENTRY} </update>"
|
||||||
|
|
||||||
# ── Write new entry to temp file ───────────────────────────────
|
# -- Write new entry to temp file --------------------------------
|
||||||
printf '%b' "$NEW_ENTRY" > /tmp/new_entry.xml
|
printf '%b' "$NEW_ENTRY" > /tmp/new_entry.xml
|
||||||
|
|
||||||
# ── Merge into updates.xml ─────────────────────────────────────
|
# -- Merge into updates.xml (only update this stability channel) -
|
||||||
|
# Cascading update: each stability level updates itself and all lower levels
|
||||||
|
# stable → all | rc → rc,beta,alpha,dev | beta → beta,alpha,dev | alpha → alpha,dev | dev → dev
|
||||||
|
CASCADE_MAP="stable:development,alpha,beta,rc,stable rc:development,alpha,beta,rc beta:development,alpha,beta alpha:development,alpha development:development"
|
||||||
|
TARGETS=""
|
||||||
|
for entry in $CASCADE_MAP; do
|
||||||
|
key="${entry%%:*}"
|
||||||
|
vals="${entry#*:}"
|
||||||
|
if [ "$key" = "${STABILITY}" ]; then
|
||||||
|
TARGETS="$vals"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -z "$TARGETS" ] && TARGETS="${STABILITY}"
|
||||||
|
|
||||||
if [ ! -f "updates.xml" ]; then
|
if [ ! -f "updates.xml" ]; then
|
||||||
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>' > updates.xml
|
printf '%s\n' "<?xml version='1.0' encoding='UTF-8'?>" > updates.xml
|
||||||
|
printf '%s\n' "<!-- Copyright (C) $(date +%Y) Moko Consulting <hello@mokoconsulting.tech>" >> updates.xml
|
||||||
|
printf '%s\n' " SPDX-License-Identifier: GPL-3.0-or-later" >> updates.xml
|
||||||
|
printf '%s\n' " VERSION: ${VERSION}" >> updates.xml
|
||||||
|
printf '%s\n' " -->" >> updates.xml
|
||||||
|
printf '%s\n' "" >> updates.xml
|
||||||
printf '%s\n' '<updates>' >> updates.xml
|
printf '%s\n' '<updates>' >> updates.xml
|
||||||
cat /tmp/new_entry.xml >> updates.xml
|
cat /tmp/new_entry.xml >> updates.xml
|
||||||
printf '\n%s\n' '</updates>' >> updates.xml
|
printf '\n%s\n' '</updates>' >> updates.xml
|
||||||
else
|
else
|
||||||
# Remove existing entry for this stability, insert new one
|
# Replace each cascading channel with the new entry (different tag)
|
||||||
printf 'import re\nstability = "%s"\n' "${STABILITY}" > /tmp/merge_xml.py
|
export PY_TARGETS="$TARGETS"
|
||||||
printf 'with open("updates.xml") as f: content = f.read()\n' >> /tmp/merge_xml.py
|
python3 << PYEOF
|
||||||
printf 'with open("/tmp/new_entry.xml") as f: new_entry = f.read()\n' >> /tmp/merge_xml.py
|
import re, os
|
||||||
printf 'pattern = r" <update>.*?<tag>" + re.escape(stability) + r"</tag>.*?</update>\\n?"\n' >> /tmp/merge_xml.py
|
targets = os.environ["PY_TARGETS"].split(",")
|
||||||
printf 'content = re.sub(pattern, "", content, flags=re.DOTALL)\n' >> /tmp/merge_xml.py
|
stability = "${STABILITY}"
|
||||||
printf 'content = content.replace("</updates>", new_entry + "\\n</updates>")\n' >> /tmp/merge_xml.py
|
with open("updates.xml") as f:
|
||||||
printf 'content = re.sub(r"\\n{3,}", "\\n\\n", content)\n' >> /tmp/merge_xml.py
|
content = f.read()
|
||||||
printf 'with open("updates.xml", "w") as f: f.write(content)\n' >> /tmp/merge_xml.py
|
with open("/tmp/new_entry.xml") as f:
|
||||||
python3 /tmp/merge_xml.py 2>/dev/null || {
|
new_entry_template = f.read()
|
||||||
|
for tag in targets:
|
||||||
|
tag = tag.strip()
|
||||||
|
# Build entry with this tag
|
||||||
|
new_entry = re.sub(r"<tag>[^<]*</tag>", f"<tag>{tag}</tag>", new_entry_template)
|
||||||
|
# Remove existing entry for this tag
|
||||||
|
pattern = r" <update>.*?<tag>" + re.escape(tag) + r"</tag>.*?</update>\n?"
|
||||||
|
content = re.sub(pattern, "", content, flags=re.DOTALL)
|
||||||
|
# Insert before </updates>
|
||||||
|
content = content.replace("</updates>", new_entry + "\n</updates>")
|
||||||
|
content = re.sub(r"\n{3,}", "\n\n", content)
|
||||||
|
with open("updates.xml", "w") as f:
|
||||||
|
f.write(content)
|
||||||
|
PYEOF
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
# Fallback: rebuild keeping other stability entries
|
# Fallback: rebuild keeping other stability entries
|
||||||
{
|
{
|
||||||
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
|
printf '%s\n' "<?xml version='1.0' encoding='UTF-8'?>"
|
||||||
|
printf '%s\n' "<!-- Copyright (C) $(date +%Y) Moko Consulting <hello@mokoconsulting.tech>"
|
||||||
|
printf '%s\n' " SPDX-License-Identifier: GPL-3.0-or-later"
|
||||||
|
printf '%s\n' " VERSION: ${VERSION}"
|
||||||
|
printf '%s\n' " -->"
|
||||||
|
printf '%s\n' ""
|
||||||
printf '%s\n' '<updates>'
|
printf '%s\n' '<updates>'
|
||||||
for TAG in stable rc development; do
|
for TAG in stable rc development; do
|
||||||
[ "$TAG" = "${STABILITY}" ] && continue
|
[ "$TAG" = "${STABILITY}" ] && continue
|
||||||
@@ -265,7 +366,7 @@ jobs:
|
|||||||
printf '\n%s\n' '</updates>'
|
printf '\n%s\n' '</updates>'
|
||||||
} > /tmp/updates_new.xml
|
} > /tmp/updates_new.xml
|
||||||
mv /tmp/updates_new.xml updates.xml
|
mv /tmp/updates_new.xml updates.xml
|
||||||
}
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Commit
|
# Commit
|
||||||
@@ -278,8 +379,55 @@ jobs:
|
|||||||
git push
|
git push
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -- Sync updates.xml to main (for non-main branches) ----------------------
|
||||||
|
- name: Sync updates.xml to main
|
||||||
|
if: github.ref_name != 'main'
|
||||||
|
run: |
|
||||||
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
GA_TOKEN="${{ secrets.GA_TOKEN }}"
|
||||||
|
|
||||||
|
FILE_SHA=$(curl -sf -H "Authorization: token ${GA_TOKEN}" \
|
||||||
|
"${API_BASE}/contents/updates.xml?ref=main" | python3 -c "import sys,json; print(json.load(sys.stdin).get('sha',''))" 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -n "$FILE_SHA" ] && [ -f "updates.xml" ]; then
|
||||||
|
CONTENT=$(base64 -w0 updates.xml)
|
||||||
|
curl -sf -X PUT -H "Authorization: token ${GA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${API_BASE}/contents/updates.xml" \
|
||||||
|
-d "$(python3 -c "import json; print(json.dumps({
|
||||||
|
'content': '${CONTENT}',
|
||||||
|
'sha': '${FILE_SHA}',
|
||||||
|
'message': 'chore: sync updates.xml from ${STABILITY} [skip ci]',
|
||||||
|
'branch': 'main'
|
||||||
|
}))")" > /dev/null 2>&1 \
|
||||||
|
&& echo "updates.xml synced to main (${STABILITY})" >> $GITHUB_STEP_SUMMARY \
|
||||||
|
|| echo "WARNING: failed to sync updates.xml to main" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "WARNING: could not get updates.xml SHA from main" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -- Mirror to GitHub (stable and rc only) --------------------------------
|
||||||
|
- name: Mirror release to GitHub
|
||||||
|
if: >-
|
||||||
|
(steps.update.outputs.stability == 'stable' || steps.update.outputs.stability == 'rc') &&
|
||||||
|
secrets.GH_TOKEN != ''
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
run: |
|
||||||
|
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
||||||
|
STABILITY="${{ steps.update.outputs.stability }}"
|
||||||
|
echo "GitHub mirror sync for ${STABILITY} — ${GH_REPO}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
# Mirror packages if they exist
|
||||||
|
for PKG in /tmp/*.zip /tmp/*.tar.gz; do
|
||||||
|
if [ -f "$PKG" ]; then
|
||||||
|
_RELID=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}/releases/tags/${RELEASE_TAG}" 2>/dev/null | jq -r ".id // empty")
|
||||||
|
[ -n "$_RELID" ] && curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" -H "Content-Type: application/octet-stream" "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}/releases/${_RELID}/assets?name=$(basename $PKG)" --data-binary "@$PKG" > /dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
- name: SFTP deploy to dev server
|
- name: SFTP deploy to dev server
|
||||||
if: contains(github.ref, 'dev/')
|
if: contains(github.ref, 'dev/') || github.ref == 'refs/heads/dev'
|
||||||
env:
|
env:
|
||||||
DEV_HOST: ${{ vars.DEV_FTP_HOST }}
|
DEV_HOST: ${{ vars.DEV_FTP_HOST }}
|
||||||
DEV_PATH: ${{ vars.DEV_FTP_PATH }}
|
DEV_PATH: ${{ vars.DEV_FTP_PATH }}
|
||||||
@@ -288,15 +436,15 @@ jobs:
|
|||||||
DEV_PORT: ${{ vars.DEV_FTP_PORT }}
|
DEV_PORT: ${{ vars.DEV_FTP_PORT }}
|
||||||
DEV_KEY: ${{ secrets.DEV_FTP_KEY }}
|
DEV_KEY: ${{ secrets.DEV_FTP_KEY }}
|
||||||
DEV_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
|
DEV_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
|
||||||
GH_TOKEN: ${{ secrets.GA_TOKEN || github.token }}
|
|
||||||
run: |
|
run: |
|
||||||
# ── Permission check: admin or maintain role required ──────
|
# -- Permission check: admin or maintain role required --------
|
||||||
ACTOR="${{ github.actor }}"
|
ACTOR="${{ github.actor }}"
|
||||||
REPO="${{ github.repository }}"
|
REPO="${{ github.repository }}"
|
||||||
PERMISSION=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" "${{GITEA_URL:-https://git.mokoconsulting.tech}}/api/v1/repos/${{ github.repository }}/collaborators/${ACTOR}/permission" 2>/dev/null \
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
2>/dev/null | jq -r '.permission' || \
|
|
||||||
curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" "${{GITEA_URL:-https://git.mokoconsulting.tech}}/api/v1/repos/${{ github.repository }}/collaborators/${ACTOR}" 2>/dev/null \
|
PERMISSION=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
|
||||||
2>/dev/null | jq -r '.role' || echo "read")
|
"${API_BASE}/collaborators/${ACTOR}/permission" 2>/dev/null | \
|
||||||
|
python3 -c "import sys,json; print(json.load(sys.stdin).get('permission','read'))" 2>/dev/null || echo "read")
|
||||||
case "$PERMISSION" in
|
case "$PERMISSION" in
|
||||||
admin|maintain|write) ;;
|
admin|maintain|write) ;;
|
||||||
*)
|
*)
|
||||||
@@ -324,11 +472,11 @@ jobs:
|
|||||||
printf ',"password":"%s"}' "$DEV_PASS" >> /tmp/sftp-config.json
|
printf ',"password":"%s"}' "$DEV_PASS" >> /tmp/sftp-config.json
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PLATFORM=$(php /tmp/mokostandards/api/cli/platform_detect.php --path . 2>/dev/null || true)
|
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
|
if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards-api/deploy/deploy-joomla.php" ]; then
|
||||||
php /tmp/mokostandards/api/deploy/deploy-joomla.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
|
php /tmp/mokostandards-api/deploy/deploy-joomla.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
|
||||||
elif [ -f "/tmp/mokostandards/api/deploy/deploy-sftp.php" ]; then
|
elif [ -f "/tmp/mokostandards-api/deploy/deploy-sftp.php" ]; then
|
||||||
php /tmp/mokostandards/api/deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
|
php /tmp/mokostandards-api/deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
|
||||||
fi
|
fi
|
||||||
rm -f /tmp/deploy_key /tmp/sftp-config.json
|
rm -f /tmp/deploy_key /tmp/sftp-config.json
|
||||||
echo "SFTP deploy to dev complete" >> $GITHUB_STEP_SUMMARY
|
echo "SFTP deploy to dev complete" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
INGROUP: MokoOnyx.Documentation
|
INGROUP: MokoOnyx.Documentation
|
||||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx
|
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx
|
||||||
FILE: ./README.md
|
FILE: ./README.md
|
||||||
VERSION: 01.00.26
|
VERSION: 01.00.19
|
||||||
BRIEF: Documentation for MokoOnyx template
|
BRIEF: Documentation for MokoOnyx template
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.1",
|
"ext-zip": "*",
|
||||||
"ext-zip": "*"
|
"mokoconsulting-tech/enterprise": "dev-version/04",
|
||||||
|
"php": ">=8.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mokoconsulting-tech/enterprise": "^4.0"
|
"mokoconsulting-tech/enterprise": "^4.0"
|
||||||
|
|||||||
144
package-lock.json
generated
144
package-lock.json
generated
@@ -1,144 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "mokoonyx-build",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"name": "mokoonyx-build",
|
|
||||||
"devDependencies": {
|
|
||||||
"clean-css": "^5.3.3",
|
|
||||||
"terser": "^5.39.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
|
||||||
"version": "0.3.13",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
|
||||||
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.24"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/resolve-uri": {
|
|
||||||
"version": "3.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
|
||||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/source-map": {
|
|
||||||
"version": "0.3.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
|
|
||||||
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.25"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
|
||||||
"version": "1.5.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
|
||||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
|
||||||
"version": "0.3.31",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
|
||||||
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/resolve-uri": "^3.1.0",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/acorn": {
|
|
||||||
"version": "8.16.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
|
||||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"acorn": "bin/acorn"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/buffer-from": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/clean-css": {
|
|
||||||
"version": "5.3.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
|
|
||||||
"integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"source-map": "~0.6.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/commander": {
|
|
||||||
"version": "2.20.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/source-map": {
|
|
||||||
"version": "0.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/source-map-support": {
|
|
||||||
"version": "0.5.21",
|
|
||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
|
||||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"buffer-from": "^1.0.0",
|
|
||||||
"source-map": "^0.6.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/terser": {
|
|
||||||
"version": "5.46.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.46.2.tgz",
|
|
||||||
"integrity": "sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "BSD-2-Clause",
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/source-map": "^0.3.3",
|
|
||||||
"acorn": "^8.15.0",
|
|
||||||
"commander": "^2.20.0",
|
|
||||||
"source-map-support": "~0.5.20"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"terser": "bin/terser"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -25,9 +25,8 @@ $headerClass = htmlspecialchars($params->get('header_class', ''), ENT_COMPAT, 'U
|
|||||||
if ($params->get('backgroundimage')) {
|
if ($params->get('backgroundimage')) {
|
||||||
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
|
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
|
||||||
$wa = $app->getDocument()->getWebAssetManager();
|
$wa = $app->getDocument()->getWebAssetManager();
|
||||||
$bgUrl = Uri::root(true) . '/' . HTMLHelper::_('cleanImageURL', $params->get('backgroundimage'))->url;
|
|
||||||
$wa->addInlineStyle(
|
$wa->addInlineStyle(
|
||||||
'#' . $modId . '{--hero-bg-image: url("' . $bgUrl . '"); background-image: var(--hero-bg-image);}',
|
'#' . $modId . '{background-image: url("' . Uri::root(true) . '/' . HTMLHelper::_('cleanImageURL', $params->get('backgroundimage'))->url . '");}',
|
||||||
['name' => $modId]
|
['name' => $modId]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,34 +101,26 @@ form {
|
|||||||
width: 280px;
|
width: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.drawer-toggle-left,
|
.drawer-toggle-left{
|
||||||
.drawer-toggle-left.btn {
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
z-index: 1050;
|
z-index: 1050;
|
||||||
background-color: var(--accent-color, var(--color-primary, #2a69b8)) !important;
|
background-color: var(--nav-bg-color);
|
||||||
color: var(--accent-color-text, #fff) !important;
|
color: var(--nav-text-color, gray);
|
||||||
border-color: var(--accent-color, var(--color-primary, #2a69b8)) !important;
|
|
||||||
padding-left: .5rem;
|
padding-left: .5rem;
|
||||||
padding-right: .5rem;
|
padding-right: .5rem;
|
||||||
border-top-left-radius: 0 !important;
|
|
||||||
border-bottom-left-radius: 0 !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button.drawer-toggle-right,
|
.drawer-toggle-right{
|
||||||
.drawer-toggle-right.btn {
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
z-index: 1050;
|
z-index: 1050;
|
||||||
background-color: var(--accent-color, var(--color-primary, #2a69b8)) !important;
|
background-color: var(--nav-bg-color);
|
||||||
color: var(--accent-color-text, #fff) !important;
|
color: var(--nav-text-color, gray);
|
||||||
border-color: var(--accent-color, var(--color-primary, #2a69b8)) !important;
|
|
||||||
padding-left: .5rem;
|
padding-left: .5rem;
|
||||||
padding-right: .5rem;
|
padding-right: .5rem;
|
||||||
border-top-right-radius: 0 !important;
|
|
||||||
border-bottom-right-radius: 0 !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
@@ -13631,14 +13623,12 @@ a.navbar-brand {
|
|||||||
.btn-primary {
|
.btn-primary {
|
||||||
background-color: var(--color-primary, #112855);
|
background-color: var(--color-primary, #112855);
|
||||||
border-color: var(--color-primary, #112855);
|
border-color: var(--color-primary, #112855);
|
||||||
color: #000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary:active,
|
.btn-primary:active,
|
||||||
.btn-primary:focus {
|
.btn-primary:focus {
|
||||||
background-color: var(--color-active);
|
background-color: var(--color-active);
|
||||||
border-color: var(--color-active);
|
border-color: var(--color-active);
|
||||||
color: #000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-group {
|
.btn-group {
|
||||||
@@ -13935,22 +13925,13 @@ meter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── HERO WRAPPER (module wrapper, full-width centering container) ── */
|
/* ── HERO CARD BASE ── */
|
||||||
.hero {
|
.hero {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: var(--hero-justify, center);
|
justify-content: center;
|
||||||
align-items: var(--hero-align, center);
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: var(--hero-min-height, 75vh);
|
min-height: var(--banner-min-height, 60vh);
|
||||||
background-image: var(--hero-bg-image, none);
|
|
||||||
background-repeat: var(--hero-bg-repeat, no-repeat);
|
|
||||||
background-attachment: var(--hero-bg-attachment, fixed);
|
|
||||||
background-position: var(--hero-bg-position, center);
|
|
||||||
background-size: var(--hero-bg-size, cover);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── HERO CARD BASE (the .card inside the hero wrapper) ── */
|
|
||||||
.hero .card {
|
|
||||||
max-width: var(--hero-card-max-width, 600px);
|
max-width: var(--hero-card-max-width, 600px);
|
||||||
padding: var(--hero-card-padding-y, 3rem) var(--hero-card-padding-x, 2rem);
|
padding: var(--hero-card-padding-y, 3rem) var(--hero-card-padding-x, 2rem);
|
||||||
background-color: var(--hero-card-bg, var(--hero-primary-bg-color, #0d1e3a));
|
background-color: var(--hero-card-bg, var(--hero-primary-bg-color, #0d1e3a));
|
||||||
@@ -13959,21 +13940,23 @@ meter {
|
|||||||
background-position: center;
|
background-position: center;
|
||||||
color: var(--hero-card-color, var(--hero-primary-color, #f1f5f9));
|
color: var(--hero-card-color, var(--hero-primary-color, #f1f5f9));
|
||||||
border-radius: var(--hero-card-border-radius, .5rem);
|
border-radius: var(--hero-card-border-radius, .5rem);
|
||||||
text-align: var(--hero-card-text-align, center);
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
border: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── PRIMARY VARIANT ── */
|
.hero .card {
|
||||||
.hero#primary .card {
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── PRIMARY VARIANT (uses default card vars) ── */
|
||||||
|
.hero#primary {
|
||||||
background-color: var(--hero-card-bg, #0d1e3a);
|
background-color: var(--hero-card-bg, #0d1e3a);
|
||||||
background-image: var(--hero-card-overlay, none);
|
background-image: var(--hero-card-overlay, none);
|
||||||
color: var(--hero-card-color, #f1f5f9);
|
color: var(--hero-card-color, #f1f5f9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── SECONDARY / ALTERNATIVE VARIANT ── */
|
/* ── SECONDARY / ALTERNATIVE VARIANT ── */
|
||||||
.hero#secondary .card {
|
.hero#secondary {
|
||||||
max-width: var(--hero-alt-card-max-width, 600px);
|
max-width: var(--hero-alt-card-max-width, 600px);
|
||||||
padding: var(--hero-alt-card-padding-y, 3rem) var(--hero-alt-card-padding-x, 2rem);
|
padding: var(--hero-alt-card-padding-y, 3rem) var(--hero-alt-card-padding-x, 2rem);
|
||||||
background-color: var(--hero-alt-card-bg, #080f1e);
|
background-color: var(--hero-alt-card-bg, #080f1e);
|
||||||
@@ -13995,14 +13978,14 @@ meter {
|
|||||||
background-image: none;
|
background-image: none;
|
||||||
}
|
}
|
||||||
.hero {
|
.hero {
|
||||||
min-height: 100vh;
|
|
||||||
min-height: 100dvh;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.hero .card {
|
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
min-height: 100dvh;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16988,14 +16971,11 @@ body:not(.has-sidebar-right) .site-grid .container-component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
--bs-btn-color: #000;
|
|
||||||
--bs-btn-bg: #333;
|
--bs-btn-bg: #333;
|
||||||
--bs-btn-border-color: #333;
|
--bs-btn-border-color: #333;
|
||||||
--bs-btn-hover-color: #000;
|
|
||||||
--bs-btn-hover-bg: #555;
|
--bs-btn-hover-bg: #555;
|
||||||
--bs-btn-hover-border-color: #555;
|
--bs-btn-hover-border-color: #555;
|
||||||
--bs-btn-focus-shadow-rgb: 49, 132, 253;
|
--bs-btn-focus-shadow-rgb: 49, 132, 253;
|
||||||
--bs-btn-active-color: #000;
|
|
||||||
--bs-btn-active-bg: #555;
|
--bs-btn-active-bg: #555;
|
||||||
--bs-btn-active-border-color: #555;
|
--bs-btn-active-border-color: #555;
|
||||||
--bs-btn-disabled-bg: #A0A0A0;
|
--bs-btn-disabled-bg: #A0A0A0;
|
||||||
@@ -18981,7 +18961,7 @@ nav[data-toggle=toc] .nav-link.active+ul{
|
|||||||
|
|
||||||
/* ===== BOOTSTRAP & JOOMLA BUTTONS ===== */
|
/* ===== BOOTSTRAP & JOOMLA BUTTONS ===== */
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
--btn-color: #000;
|
--btn-color: white;
|
||||||
--btn-bg: var(--color-primary, #112855);
|
--btn-bg: var(--color-primary, #112855);
|
||||||
--btn-border-color: var(--color-primary, #112855);
|
--btn-border-color: var(--color-primary, #112855);
|
||||||
--btn-hover-bg: color-mix(in srgb, var(--color-primary, #112855) 85%, black);
|
--btn-hover-bg: color-mix(in srgb, var(--color-primary, #112855) 85%, black);
|
||||||
|
|||||||
@@ -39,13 +39,13 @@
|
|||||||
</server>
|
</server>
|
||||||
</updateservers>
|
</updateservers>
|
||||||
<name>MokoOnyx</name>
|
<name>MokoOnyx</name>
|
||||||
<version>01.00.25</version>
|
<version>01.00.18</version>
|
||||||
<scriptfile>script.php</scriptfile>
|
<scriptfile>script.php</scriptfile>
|
||||||
<creationDate>2026-04-15</creationDate>
|
<creationDate>2026-04-15</creationDate>
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
<author>Jonathan Miller || Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
<copyright>(C)GNU General Public License Version 3 - 2026 Moko Consulting</copyright>
|
<copyright>(C)GNU General Public License Version 3 - 2026 Moko Consulting</copyright>
|
||||||
<description><![CDATA[<div style="padding:1rem;border:2px solid #059669;border-radius:8px;background:#ecfdf5;margin-bottom:1rem;"> <h3 style="color:#065f46;margin:0 0 .5rem;">Migrating from MokoCassiopeia?</h3> <p style="margin:0 0 .75rem;">MokoOnyx automatically imports your MokoCassiopeia settings on first use. To trigger the migration:</p> <ol style="margin:0 0 .75rem 1.5rem;"> <li>Install MokoOnyx via <strong>System → Install → Extensions</strong></li> <li>Go to <strong>System → Site Templates</strong> and set <strong>MokoOnyx</strong> as your default template</li> <li><strong>Visit any page on your site</strong> — the migration runs automatically on first page load</li> <li>Check <strong>administrator/logs/mokoonyx_migrate.log.php</strong> to confirm migration completed</li> <li>Uninstall MokoCassiopeia from <strong>Extensions → Manage</strong></li> </ol> <p style="margin:0;font-size:.9em;color:#065f46;"> <strong>What gets migrated:</strong> template style params, custom colour palettes (light.custom.css, dark.custom.css), user.css, user.js, and update server URL. To re-run the migration, delete <code>templates/mokoonyx/.migrated</code> and reload any page. </p></div> <p><img src="https://img.shields.io/gitea/v/release/MokoConsulting/MokoOnyx?gitea_url=https%3A%2F%2Fgit.mokoconsulting.tech&logo=gitea&logoColor=white&label=version" alt="Version" /> <img src="https://img.shields.io/badge/license-GPL--3.0--or--later-green.svg?logo=gnu&logoColor=white" alt="License" /> <img src="https://img.shields.io/badge/Joomla-5.x%20%7C%206.x-red.svg?logo=joomla&logoColor=white" alt="Joomla" /> <img src="https://img.shields.io/badge/PHP-8.1%2B-777BB4.svg?logo=php&logoColor=white" alt="PHP" /></p> <h3>MokoOnyx</h3> <p> <strong>MokoOnyx</strong> (formerly MokoCassiopeia) is a modern, lightweight enhancement layer built on Joomla's Cassiopeia template. It adds Font Awesome 7, Bootstrap 5 helpers, automatic Table of Contents, advanced Dark Mode theming, and optional Google Tag Manager / GA4 integration — all with minimal core overrides for maximum upgrade compatibility. </p> <h4>Custom Colour Themes</h4> <p> Copy <code>templates/mokoonyx/templates/light.custom.css</code> to <code>media/templates/site/mokoonyx/css/theme/light.custom.css</code> (or dark equivalent), customise the CSS variables, then select "Custom" in the Theme tab. </p> <h4>Custom CSS & JavaScript</h4> <ul> <li><code>media/templates/site/mokoonyx/css/user.css</code> — custom CSS overrides</li> <li><code>media/templates/site/mokoonyx/js/user.js</code> — custom JavaScript</li> </ul> <p>These files survive template updates.</p> <h4>CSS Variables Reference</h4> <p>For a complete list of CSS variables, see the <a href="https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx" target="_blank">MokoOnyx repository documentation</a>.</p>]]></description>
|
<description><![CDATA[<div style="padding:1rem;border:2px solid #059669;border-radius:8px;background:#ecfdf5;margin-bottom:1rem;"> <h3 style="color:#065f46;margin:0 0 .5rem;">Migrating from MokoCassiopeia?</h3> <p style="margin:0 0 .75rem;">MokoOnyx automatically imports your MokoCassiopeia settings on first use. To trigger the migration:</p> <ol style="margin:0 0 .75rem 1.5rem;"> <li>Install MokoOnyx via <strong>System → Install → Extensions</strong></li> <li>Go to <strong>System → Site Templates</strong> and set <strong>MokoOnyx</strong> as your default template</li> <li><strong>Visit any page on your site</strong> — the migration runs automatically on first page load</li> <li>Check <strong>administrator/logs/mokoonyx_migrate.log.php</strong> to confirm migration completed</li> <li>Uninstall MokoCassiopeia from <strong>Extensions → Manage</strong></li> </ol> <p style="margin:0;font-size:.9em;color:#065f46;"> <strong>What gets migrated:</strong> template style params, custom colour palettes (light.custom.css, dark.custom.css), user.css, user.js, and update server URL. To re-run the migration, delete <code>templates/mokoonyx/.migrated</code> and reload any page. </p></div> <p><img src="https://img.shields.io/gitea/v/release/MokoConsulting/MokoOnyx?gitea_url=https%3A%2F%2Fgit.mokoconsulting.tech&logo=gitea&logoColor=white&label=version" alt="Version" /> <img src="https://img.shields.io/badge/license-GPL--3.0--or--later-green.svg?logo=gnu&logoColor=white" alt="License" /> <img src="https://img.shields.io/badge/Joomla-5.x%20%7C%206.x-red.svg?logo=joomla&logoColor=white" alt="Joomla" /> <img src="https://img.shields.io/badge/PHP-8.1%2B-777BB4.svg?logo=php&logoColor=white" alt="PHP" /></p> <h3>MokoOnyx</h3> <p> <strong>MokoOnyx</strong> (formerly MokoCassiopeia) is a modern, lightweight enhancement layer built on Joomla's Cassiopeia template. It adds Font Awesome 7, Bootstrap 5 helpers, automatic Table of Contents, advanced Dark Mode theming, and optional Google Tag Manager / GA4 integration — all with minimal core overrides for maximum upgrade compatibility. </p> <h4>Custom Colour Themes</h4> <p> Copy <code>templates/mokoonyx/templates/light.custom.css</code> to <code>media/templates/site/mokoonyx/css/theme/light.custom.css</code> (or dark equivalent), customise the CSS variables, then select "Custom" in the Theme tab. </p> <h4>Custom CSS & JavaScript</h4> <ul> <li><code>media/templates/site/mokoonyx/css/user.css</code> — custom CSS overrides</li> <li><code>media/templates/site/mokoonyx/js/user.js</code> — custom JavaScript</li> </ul> <p>These files survive template updates.</p>]]></description>
|
||||||
<inheritable>1</inheritable>
|
<inheritable>1</inheritable>
|
||||||
<files>
|
<files>
|
||||||
<filename>component.php</filename>
|
<filename>component.php</filename>
|
||||||
@@ -327,11 +327,51 @@
|
|||||||
</field>
|
</field>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<!-- CSS Variables: see repo documentation -->
|
<!-- CSS Variables reference tab -->
|
||||||
<fieldset name="css_variables" label="TPL_MOKOONYX_CSS_VARS_FIELDSET_LABEL">
|
<fieldset name="css_variables" label="TPL_MOKOONYX_CSS_VARS_FIELDSET_LABEL">
|
||||||
<field name="css_vars_docs_link" type="note"
|
<field name="css_vars_intro" type="note" description="TPL_MOKOONYX_CSS_VARS_INTRO" />
|
||||||
description="For a full list of CSS variables and theming options, see the <a href='https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx' target='_blank'>MokoOnyx documentation</a>."
|
<field name="css_vars_brand" type="note" label="TPL_MOKOONYX_CSS_VARS_BRAND_LABEL" description="TPL_MOKOONYX_CSS_VARS_BRAND_DESC" class="alert alert-light" />
|
||||||
class="alert alert-info" />
|
<field name="css_vars_links" type="note" label="TPL_MOKOONYX_CSS_VARS_LINKS_LABEL" description="TPL_MOKOONYX_CSS_VARS_LINKS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_typography" type="note" label="TPL_MOKOONYX_CSS_VARS_TYPO_LABEL" description="TPL_MOKOONYX_CSS_VARS_TYPO_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_nav" type="note" label="TPL_MOKOONYX_CSS_VARS_NAV_LABEL" description="TPL_MOKOONYX_CSS_VARS_NAV_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_layout" type="note" label="TPL_MOKOONYX_CSS_VARS_LAYOUT_LABEL" description="TPL_MOKOONYX_CSS_VARS_LAYOUT_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_breakpoints" type="note" label="TPL_MOKOONYX_CSS_VARS_BP_LABEL" description="TPL_MOKOONYX_CSS_VARS_BP_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_bootstrap" type="note" label="TPL_MOKOONYX_CSS_VARS_BS_LABEL" description="TPL_MOKOONYX_CSS_VARS_BS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_bootstrap_states" type="note" label="TPL_MOKOONYX_CSS_VARS_BS_STATES_LABEL" description="TPL_MOKOONYX_CSS_VARS_BS_STATES_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_alert_list" type="note" label="TPL_MOKOONYX_CSS_VARS_ALERT_LIST_LABEL" description="TPL_MOKOONYX_CSS_VARS_ALERT_LIST_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_colors" type="note" label="TPL_MOKOONYX_CSS_VARS_COLORS_LABEL" description="TPL_MOKOONYX_CSS_VARS_COLORS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_hero" type="note" label="TPL_MOKOONYX_CSS_VARS_HERO_LABEL" description="TPL_MOKOONYX_CSS_VARS_HERO_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_hero_variants" type="note" label="TPL_MOKOONYX_CSS_VARS_HERO_VARIANTS_LABEL" description="TPL_MOKOONYX_CSS_VARS_HERO_VARIANTS_DESC" class="alert alert-info" />
|
||||||
|
<field name="css_vars_block_colors" type="note" label="TPL_MOKOONYX_CSS_VARS_BLOCK_COLORS_LABEL" description="TPL_MOKOONYX_CSS_VARS_BLOCK_COLORS_DESC" class="alert alert-info" />
|
||||||
|
<field name="css_vars_header" type="note" label="TPL_MOKOONYX_CSS_VARS_HEADER_LABEL" description="TPL_MOKOONYX_CSS_VARS_HEADER_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_containers" type="note" label="TPL_MOKOONYX_CSS_VARS_CONTAINERS_LABEL" description="TPL_MOKOONYX_CSS_VARS_CONTAINERS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_borders" type="note" label="TPL_MOKOONYX_CSS_VARS_BORDERS_LABEL" description="TPL_MOKOONYX_CSS_VARS_BORDERS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_shadows" type="note" label="TPL_MOKOONYX_CSS_VARS_SHADOWS_LABEL" description="TPL_MOKOONYX_CSS_VARS_SHADOWS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_forms" type="note" label="TPL_MOKOONYX_CSS_VARS_FORMS_LABEL" description="TPL_MOKOONYX_CSS_VARS_FORMS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_buttons" type="note" label="TPL_MOKOONYX_CSS_VARS_BUTTONS_LABEL" description="TPL_MOKOONYX_CSS_VARS_BUTTONS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_cards" type="note" label="TPL_MOKOONYX_CSS_VARS_CARDS_LABEL" description="TPL_MOKOONYX_CSS_VARS_CARDS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_accordion" type="note" label="TPL_MOKOONYX_CSS_VARS_ACCORDION_LABEL" description="TPL_MOKOONYX_CSS_VARS_ACCORDION_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_alert_base" type="note" label="TPL_MOKOONYX_CSS_VARS_ALERT_BASE_LABEL" description="TPL_MOKOONYX_CSS_VARS_ALERT_BASE_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_badge" type="note" label="TPL_MOKOONYX_CSS_VARS_BADGE_LABEL" description="TPL_MOKOONYX_CSS_VARS_BADGE_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_breadcrumb" type="note" label="TPL_MOKOONYX_CSS_VARS_BREADCRUMB_LABEL" description="TPL_MOKOONYX_CSS_VARS_BREADCRUMB_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_dropdown_menu" type="note" label="TPL_MOKOONYX_CSS_VARS_DROPDOWN_MENU_LABEL" description="TPL_MOKOONYX_CSS_VARS_DROPDOWN_MENU_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_list_group" type="note" label="TPL_MOKOONYX_CSS_VARS_LIST_GROUP_LABEL" description="TPL_MOKOONYX_CSS_VARS_LIST_GROUP_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_modal" type="note" label="TPL_MOKOONYX_CSS_VARS_MODAL_LABEL" description="TPL_MOKOONYX_CSS_VARS_MODAL_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_backdrop" type="note" label="TPL_MOKOONYX_CSS_VARS_BACKDROP_LABEL" description="TPL_MOKOONYX_CSS_VARS_BACKDROP_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_nav_tabs" type="note" label="TPL_MOKOONYX_CSS_VARS_NAV_TABS_LABEL" description="TPL_MOKOONYX_CSS_VARS_NAV_TABS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_nav_pills" type="note" label="TPL_MOKOONYX_CSS_VARS_NAV_PILLS_LABEL" description="TPL_MOKOONYX_CSS_VARS_NAV_PILLS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_pagination" type="note" label="TPL_MOKOONYX_CSS_VARS_PAGINATION_LABEL" description="TPL_MOKOONYX_CSS_VARS_PAGINATION_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_popover" type="note" label="TPL_MOKOONYX_CSS_VARS_POPOVER_LABEL" description="TPL_MOKOONYX_CSS_VARS_POPOVER_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_progress" type="note" label="TPL_MOKOONYX_CSS_VARS_PROGRESS_LABEL" description="TPL_MOKOONYX_CSS_VARS_PROGRESS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_spinner" type="note" label="TPL_MOKOONYX_CSS_VARS_SPINNER_LABEL" description="TPL_MOKOONYX_CSS_VARS_SPINNER_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_table" type="note" label="TPL_MOKOONYX_CSS_VARS_TABLE_LABEL" description="TPL_MOKOONYX_CSS_VARS_TABLE_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_toast" type="note" label="TPL_MOKOONYX_CSS_VARS_TOAST_LABEL" description="TPL_MOKOONYX_CSS_VARS_TOAST_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_tooltip" type="note" label="TPL_MOKOONYX_CSS_VARS_TOOLTIP_LABEL" description="TPL_MOKOONYX_CSS_VARS_TOOLTIP_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_components" type="note" label="TPL_MOKOONYX_CSS_VARS_COMPONENTS_LABEL" description="TPL_MOKOONYX_CSS_VARS_COMPONENTS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_offcanvas" type="note" label="TPL_MOKOONYX_CSS_VARS_OFFCANVAS_LABEL" description="TPL_MOKOONYX_CSS_VARS_OFFCANVAS_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_virtuemart" type="note" label="TPL_MOKOONYX_CSS_VARS_VM_LABEL" description="TPL_MOKOONYX_CSS_VARS_VM_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_gable" type="note" label="TPL_MOKOONYX_CSS_VARS_GABLE_LABEL" description="TPL_MOKOONYX_CSS_VARS_GABLE_DESC" class="alert alert-light" />
|
||||||
|
<field name="css_vars_footer" type="note" label="TPL_MOKOONYX_CSS_VARS_FOOTER_LABEL" description="TPL_MOKOONYX_CSS_VARS_FOOTER_DESC" class="alert alert-light" />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fields>
|
</fields>
|
||||||
</config>
|
</config>
|
||||||
|
|||||||
Reference in New Issue
Block a user