Compare commits

...

27 Commits

Author SHA1 Message Date
jmiller cf02738930 chore: remove update-server docs [skip ci] 2026-06-05 00:55:10 +00:00
jmiller 455d4c8a19 chore: remove update-server docs [skip ci] 2026-06-05 00:55:09 +00:00
jmiller 8286d493b9 chore: remove update-server docs [skip ci] 2026-06-05 00:55:08 +00:00
jmiller b740152d67 Merge pull request 'ci: pre-installed /opt/moko-platform on runner' (#244) from dev into main
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
2026-06-04 23:43:57 +00:00
Jonathan Miller 9dab9f1ef6 ci: use pre-installed /opt/moko-platform on runner, fallback to clone
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Universal: Auto Version Bump / Version Bump (push) Failing after 3s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (pull_request) Blocked by required conditions
Generic: Repo Health / Report Issues (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 37s
Universal: Build & Release / Build & Release Pipeline (pull_request) Failing after 5s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 38s
All workflows check for /opt/moko-platform first (updated by cron
every 6h). Falls back to fresh clone if not available.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-04 18:43:03 -05:00
Jonathan Miller c61d32709c chore: remove deprecated update-server.yml workflow [skip ci]
Authored-by: Moko Consulting
2026-06-04 18:42:33 -05:00
gitea-actions[bot] a59091e348 chore(release): build 09.25.00 [skip ci] 2026-06-04 23:03:39 +00:00
jmiller ee3d58c20f Merge pull request 'ci: remove updates.xml workflow steps, use CLI version_bump for pre-release' (#243) from dev into main
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 35s
2026-06-04 23:03:26 +00:00
Jonathan Miller 2b137f9041 Merge remote-tracking branch 'origin/main' into dev
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (pull_request) Blocked by required conditions
Generic: Repo Health / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 5s
Universal: Auto Version Bump / Version Bump (push) Failing after 4s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request_target) Successful in 10s
Generic: Repo Health / Access control (push) Successful in 2s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 34s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 35s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 10s
# Conflicts:
#	.mokogitea/workflows/pre-release.yml
#	CHANGELOG.md
2026-06-04 18:02:23 -05:00
gitea-actions[bot] 54a27c0a8f chore(release): build 09.24.00 [skip ci] 2026-06-04 16:29:58 +00:00
jmiller 5754fae5a8 Merge pull request 'feat: --skip-update-stream flag + CI workflow updates' (#227) from dev into main
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 39s
feat: --skip-update-stream flag + CI workflow updates
2026-06-04 16:29:47 +00:00
gitea-actions[bot] ab3c0a3a8d fix: ensure all pre-releases marked prerelease=true [skip ci] 2026-06-04 16:10:52 +00:00
jmiller eb3689cff6 chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-06-04 15:58:05 +00:00
jmiller 7338a3da2e chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-06-04 15:40:31 +00:00
jmiller 0a0e1f11e0 docs: add Dolibarr Update Server standards [skip ci] 2026-06-04 15:39:23 +00:00
jmiller c3a3ab3f62 docs: add Joomla Update Server standards [skip ci] 2026-06-04 15:38:29 +00:00
jmiller 556ac85a63 chore: remove static updates.xml.template - now served dynamically [skip ci] 2026-06-04 15:36:21 +00:00
jmiller c1a145480c chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-06-04 15:31:53 +00:00
jmiller ab7b6cfba1 chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-06-04 15:18:43 +00:00
gitea-actions[bot] 2d6155d655 chore: sync pre-release workflow — auto RC on PR to main [skip ci] 2026-06-04 14:45:48 +00:00
jmiller 65215cdc4c chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-06-04 14:23:09 +00:00
jmiller 8c87cf1e74 chore: sync .mokogitea/workflows/repo-health.yml from moko-platform [skip ci] 2026-06-04 13:46:56 +00:00
Jonathan Miller 59d3524615 feat(ci): auto-file Gitea issues when CI gates fail
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m19s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Add ci-issue-reporter.sh shared script that creates or updates issues
via the Gitea API with dedup (searches open issues by ci-auto label).
Integrated into ci-platform, repo-health, and pr-check workflows.

Also fix push_files.php: getFileContent() → getFileContents() with
base64 decode to match the MokoGiteaAdapter interface.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 15:42:04 -05:00
Jonathan Miller 8058baef95 feat(cli): detect src/ entry-point in Joomla package sub-extensions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 35s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
When building a Joomla package, sub-package directories that contain a
src/ folder with a Joomla manifest XML (e.g. git submodules of full
repos) now zip src/ instead of the repo root. This avoids bundling
README, CI config, and other repo-level files into extension packages.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 10:10:40 -05:00
Jonathan Miller df2efa4838 Merge fix/cli-banner-stderr: route all decorative CLI output to stderr
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 33s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Properly fixes the root cause that b53846f worked around — instead of
adding --quiet flags to individual callers, all CliFramework display
methods now write to stderr via display(), keeping stdout clean for
machine-readable data in all CLI scripts.

Authored-by: Moko Consulting
2026-06-02 10:07:34 -05:00
Jonathan Miller 76bc91a383 fix: route all decorative CLI output to stderr
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
All display methods (banner, progress, section, status, log, table,
summary box, divider, step) now write to stderr via a new display()
helper. This ensures stdout is reserved for machine-readable data,
fixing CI pipelines that capture CLI output with $() or redirect to
$GITHUB_OUTPUT.

Root cause: version_read.php banner was written to stdout, so
  VERSION=$(php version_read.php --path .)
captured the box-drawing characters along with the version string,
corrupting $GITHUB_OUTPUT and breaking downstream release steps.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 10:01:16 -05:00
Jonathan Miller b53846f6f4 fix: prevent version_read banner from corrupting XML manifests
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 38s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
- Add --quiet flag to version_read.php call in version_auto_bump.php
  so the CliFramework banner doesn't pollute stdout
- Parse version output by matching XX.YY.ZZ pattern instead of
  blindly taking the first line
- Add version format validation in version_set_platform.php to reject
  non-XX.YY.ZZ values before writing to XML files

Root cause: exec() captured the decorative banner output from
version_read.php and version_set_platform.php's regex replacement
injected it into <version> tags across all Joomla manifests.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 09:01:19 -05:00
41 changed files with 636 additions and 932 deletions
+68 -66
View File
@@ -1,66 +1,68 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.mokogitea/workflows/auto-bump.yml
# VERSION: 09.23.00
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
name: "Universal: Auto Version Bump"
on:
push:
branches:
- dev
- rc
- 'feature/**'
- 'patch/**'
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
permissions:
contents: write
jobs:
bump:
name: Version Bump
runs-on: release
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
!contains(github.event.head_commit.message, '[skip bump]') &&
!startsWith(github.event.head_commit.message, 'Merge pull request')
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup moko-platform tools
run: |
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
if [ -d "/opt/moko-platform/cli" ]; then
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
else
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
fi
- name: Bump version
run: |
php ${MOKO_CLI}/version_auto_bump.php \
--path . --branch "${GITHUB_REF_NAME}" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.mokogitea/workflows/auto-bump.yml
# VERSION: 09.23.00
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
name: "Universal: Auto Version Bump"
on:
push:
branches:
- dev
- rc
- 'feature/**'
- 'patch/**'
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
permissions:
contents: write
jobs:
bump:
name: Version Bump
runs-on: release
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
!contains(github.event.head_commit.message, '[skip bump]') &&
!startsWith(github.event.head_commit.message, 'Merge pull request')
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup moko-platform tools
run: |
if [ -f "/opt/moko-platform/cli/version_bump.php" ] && [ -f "/opt/moko-platform/vendor/autoload.php" ]; then
echo "Using pre-installed /opt/moko-platform"
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
else
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
fi
- name: Bump version
run: |
php ${MOKO_CLI}/version_auto_bump.php \
--path . --branch "${GITHUB_REF_NAME}" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
+68 -25
View File
@@ -71,20 +71,26 @@ jobs:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
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
if [ -f "/opt/moko-platform/cli/version_bump.php" ] && [ -f "/opt/moko-platform/vendor/autoload.php" ]; then
echo "Using pre-installed /opt/moko-platform"
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
else
echo "Falling back to fresh clone"
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api
composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
fi
# Always fetch latest CLI tools — never use stale cache from previous runs
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api
composer install --no-dev --no-interaction --quiet
- name: Rename branch to rc
run: |
php /tmp/moko-platform-api/cli/branch_rename.php \
php ${MOKO_CLI}/branch_rename.php \
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
@@ -100,7 +106,7 @@ jobs:
- name: Publish RC release
run: |
php /tmp/moko-platform-api/cli/release_publish.php \
php ${MOKO_CLI}/release_publish.php \
--path . --stability rc --bump minor --branch rc \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--skip-update-stream
@@ -151,26 +157,63 @@ jobs:
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
run: |
# Ensure PHP + Composer are available
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
if [ -f "/opt/moko-platform/cli/version_bump.php" ] && [ -f "/opt/moko-platform/vendor/autoload.php" ]; then
echo "Using pre-installed /opt/moko-platform"
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
else
echo "Falling back to fresh clone"
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api
composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
fi
# Always fetch latest CLI tools — never use stale cache from previous runs
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api
composer install --no-dev --no-interaction --quiet
- name: "Publish stable release"
run: |
php /tmp/moko-platform-api/cli/release_publish.php \
php ${MOKO_CLI}/release_publish.php \
--path . --stability stable --bump minor --branch main \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--skip-update-stream
- name: Update release notes from CHANGELOG.md
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
# Extract [Unreleased] section from changelog
if [ -f "CHANGELOG.md" ]; then
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
[ -z "$NOTES" ] && NOTES="Stable release"
else
NOTES="Stable release"
fi
# Update release body via API
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${API_BASE}/releases/tags/stable" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -n "$RELEASE_ID" ]; then
python3 -c "
import json, urllib.request
body = open('/dev/stdin').read()
payload = json.dumps({'body': body}).encode()
req = urllib.request.Request(
'${API_BASE}/releases/${RELEASE_ID}',
data=payload, method='PATCH',
headers={
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
'Content-Type': 'application/json'
})
urllib.request.urlopen(req)
" <<< "$NOTES"
echo "Release notes updated from CHANGELOG.md"
fi
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
- name: "Step 9: Mirror release to GitHub"
if: >-
@@ -182,7 +225,7 @@ jobs:
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php /tmp/moko-platform-api/cli/release_mirror.php \
php ${MOKO_CLI}/release_mirror.php \
--version "$VERSION" --tag "$RELEASE_TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
@@ -256,7 +299,7 @@ jobs:
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php /tmp/moko-platform-api/cli/version_reset_dev.php \
php ${MOKO_CLI}/version_reset_dev.php \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
--branch dev --path . 2>&1 || true
+49
View File
@@ -412,6 +412,12 @@ jobs:
if: always()
steps:
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: automation/ci-issue-reporter.sh
sparse-checkout-cone-mode: false
- name: Check gate results
run: |
{
@@ -437,3 +443,46 @@ jobs:
echo "::error::One or more CI gates failed"
exit 1
fi
- name: "File issues for failed gates"
if: >-
always() &&
(needs.code-quality.result == 'failure' ||
needs.tests.result == 'failure' ||
needs.self-health.result == 'failure' ||
needs.governance.result == 'failure' ||
needs.templates.result == 'failure')
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
chmod +x automation/ci-issue-reporter.sh
REPORTER="./automation/ci-issue-reporter.sh"
WF="Platform CI"
report_gate() {
local gate="$1" result="$2" details="$3"
if [ "$result" = "failure" ]; then
"$REPORTER" --gate "$gate" --details "$details" --workflow "$WF" --severity error
fi
}
report_gate "Code Quality" \
"${{ needs.code-quality.result }}" \
"PHPCS (PSR-12), PHPStan, or PHP syntax checks failed. Run \`composer check\` locally to reproduce."
report_gate "Unit Tests" \
"${{ needs.tests.result }}" \
"PHPUnit tests failed on one or more PHP versions (8.1, 8.2, 8.3). Run \`vendor/bin/phpunit --testdox\` locally."
report_gate "Self-Health" \
"${{ needs.self-health.result }}" \
"Self-health score fell below the 80% threshold. Run \`php bin/moko health -- --path .\` locally."
report_gate "Governance" \
"${{ needs.governance.result }}" \
"Governance checks failed (license headers, secrets, or version consistency). Check the CI run summary for specifics."
report_gate "Template Integrity" \
"${{ needs.templates.result }}" \
"Workflow or gitignore templates failed YAML validation or are missing required entries."
+1 -1
View File
@@ -5,7 +5,7 @@
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Automation
# VERSION: 09.23.00
# VERSION: 09.25.00
# BRIEF: Auto-create feature branch when an issue is opened
name: "Universal: Issue Branch"
+82 -25
View File
@@ -7,7 +7,7 @@
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 09.23.00
# VERSION: 05.01.00
# BRIEF: Manual pre-release -- builds dev/alpha/beta/rc packages from any branch
name: "Universal: Pre-Release"
@@ -17,6 +17,10 @@ on:
types: [closed]
branches:
- dev
pull_request_target:
types: [synchronize, opened, reopened]
branches:
- main
workflow_dispatch:
inputs:
stability:
@@ -43,7 +47,8 @@ jobs:
runs-on: release
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev')
(github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev') ||
(github.event_name == 'pull_request_target' && github.event.pull_request.base.ref == 'main')
steps:
- name: Checkout
@@ -51,22 +56,29 @@ jobs:
with:
fetch-depth: 0
token: ${{ secrets.MOKOGITEA_TOKEN }}
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || '' }}
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
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
# Use pre-installed /opt/moko-platform if available (updated by cron every 6h)
if [ -f “/opt/moko-platform/cli/version_bump.php” ] && [ -f “/opt/moko-platform/vendor/autoload.php” ]; then
echo “Using pre-installed /opt/moko-platform”
echo “MOKO_CLI=/opt/moko-platform/cli” >> “$GITHUB_ENV”
else
echo “Falling back to fresh clone”
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
“https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git” \
/tmp/moko-platform-api
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
echo “MOKO_CLI=/tmp/moko-platform-api/cli” >> “$GITHUB_ENV”
fi
# Always fetch latest CLI tools — never use stale cache from previous runs
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
- name: Detect platform
id: platform
@@ -76,31 +88,40 @@ jobs:
- name: Resolve metadata and bump version
id: meta
run: |
STABILITY="${{ inputs.stability || 'development' }}"
# Auto-detect stability: RC for PRs targeting main, else use input or default to development
if [ "${{ github.event_name }}" = "pull_request_target" ] && [ "${{ github.event.pull_request.base.ref }}" = "main" ]; then
STABILITY="release-candidate"
else
STABILITY="${{ inputs.stability || 'development' }}"
fi
case "$STABILITY" in
development) TAG="development" ;;
alpha) TAG="alpha" ;;
beta) TAG="beta" ;;
release-candidate) TAG="release-candidate" ;;
development) SUFFIX="-dev"; TAG="development" ;;
alpha) SUFFIX="-alpha"; TAG="alpha" ;;
beta) SUFFIX="-beta"; TAG="beta" ;;
release-candidate) SUFFIX="-rc"; TAG="release-candidate" ;;
esac
# Bump version: patch for dev/alpha/beta, minor for RC
# Bump version via CLI: patch for dev/alpha/beta, minor for RC
case "$STABILITY" in
release-candidate) php ${MOKO_CLI}/version_bump.php --path . --minor 2>/dev/null || true ;;
*) php ${MOKO_CLI}/version_bump.php --path . 2>/dev/null || true ;;
release-candidate) BUMP="minor" ;;
*) BUMP="patch" ;;
esac
# Set stability suffix and fix consistency
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo '00.00.01')
php ${MOKO_CLI}/version_bump.php --path . $([ "$BUMP" = "minor" ] && echo "--minor") 2>/dev/null || true
# Set stability suffix and verify consistency
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "00.00.01")
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
php ${MOKO_CLI}/version_set_platform.php \
--path . --version "$VERSION" --branch "${{ github.ref_name }}" --stability "$STABILITY" 2>/dev/null || true
php ${MOKO_CLI}/version_check.php --path . --fix 2>/dev/null || true
# Read final version with suffix
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null)
[ -z "$VERSION" ] && VERSION="00.00.01"
# Append suffix for output
if [ -n "$SUFFIX" ]; then
VERSION="${VERSION}${SUFFIX}"
fi
# Commit version bump
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
@@ -125,11 +146,12 @@ jobs:
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "zip_name=${ZIP_NAME}" >> "$GITHUB_OUTPUT"
echo "ext_element=${EXT_ELEMENT}" >> "$GITHUB_OUTPUT"
echo "=== Pre-Release: ${EXT_ELEMENT} ${VERSION} ==="
echo "=== Pre-Release: ${EXT_ELEMENT} ${VERSION}${SUFFIX} ==="
- name: Create release
id: release
@@ -142,6 +164,41 @@ jobs:
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --branch dev --prerelease
- name: Update release notes from CHANGELOG.md
run: |
TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
# Extract [Unreleased] section from changelog (everything between [Unreleased] and next ## heading)
if [ -f "CHANGELOG.md" ]; then
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
[ -z "$NOTES" ] && NOTES="Release ${VERSION}"
else
NOTES="Release ${VERSION}"
fi
# Update release body via API
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${API_BASE}/releases/tags/${TAG}" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -n "$RELEASE_ID" ]; then
python3 -c "
import json, urllib.request
body = open('/dev/stdin').read()
payload = json.dumps({'body': body}).encode()
req = urllib.request.Request(
'${API_BASE}/releases/${RELEASE_ID}',
data=payload, method='PATCH',
headers={
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
'Content-Type': 'application/json'
})
urllib.request.urlopen(req)
" <<< "$NOTES"
echo "Release notes updated from CHANGELOG.md"
fi
- name: Build package and upload
id: package
run: |
-302
View File
@@ -1,302 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /templates/workflows/update-server.yml
# VERSION: 09.23.00
# BRIEF: Pre-release build + update server XML for dev/alpha/beta/rc branches
#
# Thin wrapper around moko-platform CLI tools.
# Builds packages, updates updates.xml, and optionally deploys via SFTP.
#
# Joomla filters update entries by the user's "Minimum Stability" setting.
name: "Update Server"
on:
push:
branches:
- 'dev'
- 'dev/**'
- 'alpha/**'
- 'beta/**'
- 'rc/**'
paths:
- 'src/**'
- 'htdocs/**'
pull_request:
types: [closed]
branches:
- 'dev'
- 'dev/**'
- 'alpha/**'
- 'beta/**'
- 'rc/**'
paths:
- 'src/**'
- 'htdocs/**'
workflow_dispatch:
inputs:
stability:
description: 'Stability tag'
required: true
default: 'development'
type: choice
options:
- development
- alpha
- beta
- rc
- stable
env:
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:
contents: write
jobs:
update-xml:
name: Update Server
runs-on: release
if: >-
github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' || github.event_name == 'push'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 0
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
COMPOSER_AUTH: '{"http-basic":{"git.mokoconsulting.tech":{"username":"token","password":"${{ secrets.MOKOGITEA_TOKEN }}"}}}'
run: |
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
# Always fetch latest CLI tools — never use stale cache from previous runs
rm -rf /tmp/moko-platform
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform 2>/dev/null || true
if [ -d "/tmp/moko-platform" ] && [ -f "/tmp/moko-platform/composer.json" ]; then
cd /tmp/moko-platform && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
fi
echo "MOKO_CLI=/tmp/moko-platform/cli" >> "$GITHUB_ENV"
- name: Detect platform
id: platform
run: php ${MOKO_CLI}/manifest_read.php --path . --github-output
- name: Resolve stability and bump version
id: meta
run: |
BRANCH="${{ github.ref_name }}"
# Configure git for bot pushes
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
# Determine stability from branch or manual input
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
STABILITY="${{ inputs.stability }}"
elif [[ "$BRANCH" == rc/* ]]; then
STABILITY="rc"
elif [[ "$BRANCH" == beta/* ]]; then
STABILITY="beta"
elif [[ "$BRANCH" == alpha/* ]]; then
STABILITY="alpha"
else
STABILITY="development"
fi
# Gitea release tag per stability
case "$STABILITY" in
development) TAG="development" ;;
alpha) TAG="alpha" ;;
beta) TAG="beta" ;;
rc) TAG="release-candidate" ;;
*) TAG="stable" ;;
esac
# Bump patch, set platform suffix, fix consistency — version_bump preserves suffix
php ${MOKO_CLI}/version_set_platform.php \
--path . --version "$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo '00.00.01')" \
--branch "$BRANCH" --stability "$STABILITY" 2>/dev/null || true
php ${MOKO_CLI}/version_bump.php --path . 2>/dev/null || true
php ${MOKO_CLI}/version_check.php --path . --fix 2>/dev/null || true
# Read final version (includes suffix, e.g. 01.02.15-dev)
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "00.00.01")
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
# Commit version bump if changed
git add -A
git diff --cached --quiet || {
git commit -m "chore(version): auto-bump ${VERSION} [skip ci]" \
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>"
git push
}
- name: Create release and upload package
id: package
run: |
VERSION="${{ steps.meta.outputs.version }}"
TAG="${{ steps.meta.outputs.tag }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
# Create or update Gitea release
php ${MOKO_CLI}/release_create.php \
--path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --branch "${{ github.ref_name }}" --prerelease
# Build package and upload
php ${MOKO_CLI}/release_package.php \
--path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --output /tmp || true
- name: Update updates.xml
if: steps.platform.outputs.platform == 'joomla'
run: |
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
SHA256="${{ steps.package.outputs.sha256_zip }}"
if [ ! -f "updates.xml" ]; then
echo "No updates.xml — skipping"
exit 0
fi
SHA_FLAG=""
[ -n "$SHA256" ] && SHA_FLAG="--sha ${SHA256}"
php ${MOKO_CLI}/updates_xml_build.php \
--path . --version "${VERSION}" --stability "${STABILITY}" \
--gitea-url "${GITEA_URL}" --org "${GITEA_ORG}" --repo "${GITEA_REPO}" \
${SHA_FLAG}
# Commit and push updates.xml
git add updates.xml
git diff --cached --quiet || {
git commit -m "chore: update ${STABILITY} channel ${VERSION} [skip ci]"
git push
}
- name: Sync updates.xml to main
if: github.ref_name != 'main' && steps.platform.outputs.platform == 'joomla'
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
GITEA_TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
FILE_SHA=$(curl -sf -H "Authorization: token ${GITEA_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
python3 -c "
import base64, json, urllib.request, sys
with open('updates.xml', 'rb') as f:
content = base64.b64encode(f.read()).decode()
payload = json.dumps({
'content': content,
'sha': '${FILE_SHA}',
'message': 'chore: sync updates.xml from ${{ steps.meta.outputs.stability }} [skip ci]',
'branch': 'main'
}).encode()
req = urllib.request.Request(
'${API_BASE}/contents/updates.xml',
data=payload, method='PUT',
headers={
'Authorization': 'token ${GITEA_TOKEN}',
'Content-Type': 'application/json'
})
try:
urllib.request.urlopen(req)
print('updates.xml synced to main')
except Exception as e:
print(f'WARNING: sync to main failed: {e}', file=sys.stderr)
"
fi
- name: SFTP deploy to dev server
if: contains(github.ref, 'dev/') || github.ref == 'refs/heads/dev'
env:
DEV_HOST: ${{ vars.DEV_FTP_HOST }}
DEV_PATH: ${{ vars.DEV_FTP_PATH }}
DEV_SUFFIX: ${{ vars.DEV_FTP_SUFFIX }}
DEV_USER: ${{ vars.DEV_FTP_USERNAME }}
DEV_PORT: ${{ vars.DEV_FTP_PORT }}
DEV_KEY: ${{ secrets.DEV_FTP_KEY }}
DEV_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
run: |
# Permission check: admin or maintain role required
ACTOR="${{ github.actor }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
PERMISSION=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${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
admin|maintain|write) ;;
*)
echo "Deploy denied: ${ACTOR} has '${PERMISSION}' — requires admin, maintain, or write"
exit 0
;;
esac
[ -z "$DEV_HOST" ] || [ -z "$DEV_PATH" ] && { echo "DEV FTP not configured — skipping SFTP"; exit 0; }
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
[ ! -d "$SOURCE_DIR" ] && exit 0
PORT="${DEV_PORT:-22}"
REMOTE="${DEV_PATH%/}"
[ -n "$DEV_SUFFIX" ] && REMOTE="${REMOTE}/${DEV_SUFFIX#/}"
printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \
"$DEV_HOST" "$PORT" "$DEV_USER" "$REMOTE" > /tmp/sftp-config.json
if [ -n "$DEV_KEY" ]; then
echo "$DEV_KEY" > /tmp/deploy_key && chmod 600 /tmp/deploy_key
printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json
else
printf ',"password":"%s"}' "$DEV_PASS" >> /tmp/sftp-config.json
fi
PLATFORM=$(php ${MOKO_CLI}/platform_detect.php --path . 2>/dev/null || true)
if [ "$PLATFORM" = "waas-component" ] && [ -f "${MOKO_CLI}/../deploy/deploy-joomla.php" ]; then
php ${MOKO_CLI}/../deploy/deploy-joomla.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
elif [ -f "${MOKO_CLI}/../deploy/deploy-sftp.php" ]; then
php ${MOKO_CLI}/../deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
fi
rm -f /tmp/deploy_key /tmp/sftp-config.json
echo "SFTP deploy to dev complete" >> $GITHUB_STEP_SUMMARY
- name: Summary
if: always()
run: |
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
DISPLAY="${VERSION}"
echo "## Update Server" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Stability | \`${STABILITY}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${DISPLAY}\` |" >> $GITHUB_STEP_SUMMARY
+3 -7
View File
@@ -10,9 +10,11 @@ BRIEF: Release changelog
-->
# Changelog
## [Unreleased]
## [09.25.00] --- 2026-06-04
## [09.23] --- 2026-05-31
## [09.22] --- 2026-05-31
@@ -30,9 +32,3 @@ BRIEF: Release changelog
## [09.21] --- 2026-05-30
## [09.20] --- 2026-05-30
## [09.19] --- 2026-05-30
## [09.18] --- 2026-05-30
## [09.17] --- 2026-05-30
+1 -1
View File
@@ -6,7 +6,7 @@ DEFGROUP: MokoPlatform.Root
INGROUP: MokoPlatform
REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
PATH: /README.md
VERSION: 09.23.00
VERSION: 09.25.00
BRIEF: Project overview and documentation
-->
+237
View File
@@ -0,0 +1,237 @@
#!/usr/bin/env bash
# ============================================================================
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Automation.CI
# INGROUP: moko-platform.Automation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /automation/ci-issue-reporter.sh
# VERSION: 09.23.00
# BRIEF: Creates or updates a Gitea issue when a CI gate fails.
# Deduplicates by searching open issues with the "ci-auto" label
# whose title matches the gate. If a matching issue exists, a comment
# is appended instead of opening a duplicate.
# ============================================================================
set -euo pipefail
# ── Defaults ────────────────────────────────────────────────────────────────
GITEA_URL="${GITEA_URL:-https://git.mokoconsulting.tech}"
GITEA_TOKEN="${GITEA_TOKEN:-}"
REPO="${GITHUB_REPOSITORY:-}"
RUN_URL="${GITHUB_SERVER_URL:-${GITEA_URL}}/${REPO}/actions/runs/${GITHUB_RUN_ID:-0}"
LABEL_NAME="ci-auto"
LABEL_COLOR="#e11d48"
GATE=""
DETAILS=""
SEVERITY="error"
WORKFLOW=""
# ── Parse arguments ─────────────────────────────────────────────────────────
usage() {
cat <<EOF
Usage: ci-issue-reporter.sh --gate NAME --details TEXT [OPTIONS]
Required:
--gate CI gate name (e.g. "Code Quality", "Self-Health")
--details Human-readable failure description
Optional:
--severity "error" (default) or "warning"
--workflow Workflow name for the issue title
--repo owner/repo (default: \$GITHUB_REPOSITORY)
--run-url URL to the CI run (auto-detected from env)
--token Gitea API token (default: \$GITEA_TOKEN)
--url Gitea base URL (default: \$GITEA_URL)
EOF
exit 1
}
while [[ $# -gt 0 ]]; do
case "$1" in
--gate) GATE="$2"; shift 2 ;;
--details) DETAILS="$2"; shift 2 ;;
--severity) SEVERITY="$2"; shift 2 ;;
--workflow) WORKFLOW="$2"; shift 2 ;;
--repo) REPO="$2"; shift 2 ;;
--run-url) RUN_URL="$2"; shift 2 ;;
--token) GITEA_TOKEN="$2"; shift 2 ;;
--url) GITEA_URL="$2"; shift 2 ;;
-h|--help) usage ;;
*) echo "Unknown option: $1"; usage ;;
esac
done
[[ -z "$GATE" ]] && { echo "ERROR: --gate is required"; usage; }
[[ -z "$DETAILS" ]] && { echo "ERROR: --details is required"; usage; }
[[ -z "$GITEA_TOKEN" ]] && { echo "ERROR: GITEA_TOKEN not set"; exit 1; }
[[ -z "$REPO" ]] && { echo "ERROR: GITHUB_REPOSITORY not set"; exit 1; }
API="${GITEA_URL}/api/v1/repos/${REPO}"
# ── Build title ─────────────────────────────────────────────────────────────
if [[ -n "$WORKFLOW" ]]; then
TITLE="[CI] ${WORKFLOW}: ${GATE} failed"
else
TITLE="[CI] ${GATE} failed"
fi
# ── Ensure label exists ─────────────────────────────────────────────────────
ensure_label() {
local exists
exists=$(curl -sf -o /dev/null -w '%{http_code}' \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/labels" 2>/dev/null || echo "000")
if [[ "$exists" == "200" ]]; then
# Check if label already exists
local found
found=$(curl -sf \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/labels" 2>/dev/null \
| grep -o "\"name\":\"${LABEL_NAME}\"" || true)
if [[ -z "$found" ]]; then
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/labels" \
-d "{\"name\":\"${LABEL_NAME}\",\"color\":\"${LABEL_COLOR}\",\"description\":\"Auto-created by CI issue reporter\"}" \
> /dev/null 2>&1 || true
fi
fi
}
# ── Search for existing open issue ──────────────────────────────────────────
find_existing_issue() {
# URL-encode the gate name for the query
local query
query=$(printf '%s' "[CI] ${GATE}" | sed 's/ /%20/g; s/\[/%5B/g; s/\]/%5D/g')
local response
response=$(curl -sf \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/issues?type=issues&state=open&labels=${LABEL_NAME}&q=${query}&limit=5" \
2>/dev/null || echo "[]")
# Extract the first matching issue number
echo "$response" \
| grep -oP '"number":\s*\K[0-9]+' \
| head -1
}
# ── Build issue body ────────────────────────────────────────────────────────
build_body() {
local severity_badge
if [[ "$SEVERITY" == "error" ]]; then
severity_badge="**Severity:** Error"
else
severity_badge="**Severity:** Warning"
fi
cat <<BODY
## CI Gate Failure: ${GATE}
${severity_badge}
**Workflow:** ${WORKFLOW:-unknown}
**Branch:** ${GITHUB_REF_NAME:-unknown}
**Commit:** \`${GITHUB_SHA:0:8}\`
**Run:** [View CI run](${RUN_URL})
### Details
${DETAILS}
### Resolution
Fix the issue described above and push a new commit. This issue will be closed automatically when the gate passes, or can be closed manually.
---
*Auto-created by [ci-issue-reporter](${GITEA_URL}/${REPO}/src/branch/main/automation/ci-issue-reporter.sh)*
BODY
}
# ── Build comment body (for existing issues) ────────────────────────────────
build_comment() {
cat <<COMMENT
### CI failure recurrence
**Branch:** ${GITHUB_REF_NAME:-unknown}
**Commit:** \`${GITHUB_SHA:0:8}\`
**Run:** [View CI run](${RUN_URL})
${DETAILS}
COMMENT
}
# ── Main ────────────────────────────────────────────────────────────────────
ensure_label
EXISTING=$(find_existing_issue)
if [[ -n "$EXISTING" ]]; then
# Append comment to existing issue
COMMENT_BODY=$(build_comment)
COMMENT_JSON=$(printf '%s' "$COMMENT_BODY" | python3 -c "
import sys, json
print(json.dumps({'body': sys.stdin.read()}))" 2>/dev/null)
HTTP=$(curl -sf -o /dev/null -w '%{http_code}' -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues/${EXISTING}/comments" \
-d "${COMMENT_JSON}" 2>/dev/null || echo "000")
if [[ "$HTTP" == "201" ]]; then
echo "Commented on existing issue #${EXISTING}"
else
echo "WARNING: Failed to comment on issue #${EXISTING} (HTTP ${HTTP})"
fi
else
# Create new issue
ISSUE_BODY=$(build_body)
ISSUE_JSON=$(python3 -c "
import sys, json
body = sys.stdin.read()
print(json.dumps({
'title': sys.argv[1],
'body': body,
'labels': []
}))" "$TITLE" <<< "$ISSUE_BODY" 2>/dev/null)
# Create the issue
RESPONSE=$(curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues" \
-d "${ISSUE_JSON}" 2>/dev/null || echo "{}")
ISSUE_NUM=$(echo "$RESPONSE" | grep -oP '"number":\s*\K[0-9]+' | head -1)
if [[ -n "$ISSUE_NUM" ]]; then
# Apply label (separate call — more reliable across Gitea versions)
LABEL_ID=$(curl -sf \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/labels" 2>/dev/null \
| grep -oP "\"id\":\s*\K[0-9]+(?=[^}]*\"name\":\s*\"${LABEL_NAME}\")" \
| head -1 || true)
if [[ -n "$LABEL_ID" ]]; then
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues/${ISSUE_NUM}/labels" \
-d "{\"labels\":[${LABEL_ID}]}" \
> /dev/null 2>&1 || true
fi
echo "Created issue #${ISSUE_NUM}: ${TITLE}"
else
echo "WARNING: Failed to create issue"
echo "Response: ${RESPONSE}"
fi
fi
+2 -1
View File
@@ -230,7 +230,8 @@ class PushFiles extends CliFramework
{
// Read platform from repo's .mokogitea/manifest.xml via API
try {
$manifestData = $this->adapter->getFileContent($org, $repo, '.mokogitea/manifest.xml', 'main');
$fileInfo = $this->adapter->getFileContents($org, $repo, '.mokogitea/manifest.xml', 'main');
$manifestData = isset($fileInfo['content']) ? base64_decode($fileInfo['content']) : '';
if (!empty($manifestData)) {
$xml = @simplexml_load_string($manifestData);
if ($xml !== false) {
+1 -1
View File
@@ -10,7 +10,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/branch_rename.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Rename a git branch via Gitea API (create new, update PR, delete old)
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/bulk_workflow_push.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Push a workflow file to all governed repos via the Gitea Contents API
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/bulk_workflow_trigger.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Trigger a workflow across multiple repos at once
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/client_dashboard.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Generate unified client dashboard HTML
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/client_inventory.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Discover and list all client-waas repos with their server configuration status
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/client_provision.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Provision a new client environment end-to-end
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/grafana_dashboard.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Manage Grafana dashboards via API
*/
+1 -1
View File
@@ -10,7 +10,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/joomla_build.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Build a Joomla extension ZIP from manifest — all types supported
* NOTE: Called by pre-release and auto-release workflows.
*/
+1 -1
View File
@@ -10,7 +10,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/manifest_read.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Parse .manifest.xml and output requested field(s) for CI consumption
*/
+1 -1
View File
@@ -10,7 +10,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/release_cascade.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: DEPRECATED — cascade behavior removed. Each release stream is independent.
*/
+20 -1
View File
@@ -230,12 +230,31 @@ class ReleasePackageCli extends CliFramework
$subName = basename($pkgDir);
$subZipPath = "{$outputDir}/{$subName}.zip";
// If sub-package is a full repo checkout (e.g. git submodule),
// look for a src/ subdirectory containing a Joomla manifest XML
// and zip that instead of the repo root.
$subSourceDir = $pkgDir;
$srcCandidate = "{$pkgDir}/src";
if (is_dir($srcCandidate)) {
$srcManifests = array_merge(
glob("{$srcCandidate}/*.xml") ?: [],
glob("{$srcCandidate}/pkg_*.xml") ?: []
);
foreach ($srcManifests as $mf) {
if (strpos(file_get_contents($mf) ?: '', '<extension') !== false) {
$subSourceDir = $srcCandidate;
echo " Sub-package {$subName}: using src/ entry-point\n";
break;
}
}
}
$subZip = new \ZipArchive();
if ($subZip->open($subZipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
$this->log('ERROR', "Failed to create sub-package ZIP: {$subZipPath}");
continue;
}
$this->addDirToZip($subZip, $pkgDir, '', $this->excludePatterns);
$this->addDirToZip($subZip, $subSourceDir, '', $this->excludePatterns);
$subZip->close();
$zip->addFile($subZipPath, "packages/{$subName}.zip");
+1 -1
View File
@@ -10,7 +10,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/release_publish.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Publish a release and create copies for all lesser stability streams.
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/scaffold_client.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Scaffold a new client-waas repo from Template-Client-WaaS with pre-configured settings
*/
+1 -1
View File
@@ -10,7 +10,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/updates_xml_sync.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Sync updates.xml to target branches via Gitea API
* NOTE: Called by pre-release and auto-release workflows after updates.xml
* is modified on the current branch. Pushes the file to other branches
+12 -4
View File
@@ -10,7 +10,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/version_auto_bump.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Auto patch-bump, set stability suffix, and commit — single CLI replacing inline workflow bash
*/
@@ -109,10 +109,18 @@ class VersionAutoBumpCli extends CliFramework
echo "{$line}\n";
}
// Step 2: Read version
// Step 2: Read version (--quiet suppresses banner so only the version is output)
$versionOutput = [];
exec("{$php} {$cli}/version_read.php --path " . escapeshellarg($path) . " 2>&1", $versionOutput, $versionRc);
$version = trim($versionOutput[0] ?? '');
exec("{$php} {$cli}/version_read.php --path " . escapeshellarg($path) . " --quiet 2>&1", $versionOutput, $versionRc);
// Take the last non-empty line — the version is always the final output
$version = '';
foreach (array_reverse($versionOutput) as $line) {
$line = trim($line);
if (preg_match('/^\d{2}\.\d{2}\.\d{2}/', $line)) {
$version = $line;
break;
}
}
if (empty($version)) {
echo "No version found — skipping\n";
+1 -1
View File
@@ -10,7 +10,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/version_check.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Validate version consistency across README, manifests, and sub-packages
*/
+6
View File
@@ -53,6 +53,12 @@ class VersionSetPlatformCli extends CliFramework
// Strip any existing suffix(es) before applying the correct one
$version = preg_replace('/(-(dev|alpha|beta|rc))+$/', '', $version);
// Validate version format — must be XX.YY.ZZ to prevent XML corruption
if (!preg_match('/^\d{2}\.\d{2}\.\d{2}$/', $version)) {
$this->log('ERROR', "Invalid version format: '{$version}' — expected XX.YY.ZZ");
return 1;
}
// Append stability suffix for non-stable releases
$stabilitySuffixMap = [
'stable' => '',
+1 -1
View File
@@ -10,7 +10,7 @@
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/wiki_sync.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Sync select wiki pages from moko-platform to all template repos
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: MokoPlatform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /deploy/backup-before-deploy.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Snapshot Joomla directories before deployment for rollback capability
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: MokoPlatform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /deploy/deploy-dolibarr.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Deploy Dolibarr module files to a remote server via SFTP/rsync
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: MokoPlatform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /deploy/health-check.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Post-deploy health check — verify a Joomla site is responding correctly
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: MokoPlatform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /deploy/rollback-joomla.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Rollback a Joomla deployment by restoring from a pre-deploy snapshot
*/
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: MokoPlatform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /deploy/sync-joomla.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Sync Joomla site directories between two servers via rsync over SSH
*/
+63 -47
View File
@@ -141,6 +141,26 @@ abstract class CliFramework
/** @var float Script start time for elapsed-time reporting. */
private float $startTime;
// =========================================================================
// Display output — all decorative output goes to stderr
// =========================================================================
/**
* Write decorative/diagnostic output to stderr.
*
* All non-data output (banners, progress bars, section headers, status
* lines, log messages) MUST use this method so that stdout is reserved
* for machine-readable data. This ensures that shell captures like
* VERSION=$(php version_read.php --path .)
* only receive the actual data, not decorative text.
*
* @since 04.00.16
*/
protected function display(string $text): void
{
fwrite(STDERR, $text);
}
// =========================================================================
// Constructor
// =========================================================================
@@ -326,14 +346,14 @@ abstract class CliFramework
protected function printHelp(): void
{
$w = $this->termWidth();
echo $this->c(self::C_BOLD . self::C_CYAN, $this->scriptName);
$this->display($this->c(self::C_BOLD . self::C_CYAN, $this->scriptName));
if ($this->description !== '') {
echo ' — ' . $this->description;
$this->display(' — ' . $this->description);
}
echo "\n";
echo $this->c(self::C_DIM, str_repeat(self::BOX_H, $w)) . "\n\n";
echo $this->c(self::C_BOLD, 'Usage:') . " php {$this->scriptName}.php [options]\n\n";
echo $this->c(self::C_BOLD, 'Options:') . "\n";
$this->display("\n");
$this->display($this->c(self::C_DIM, str_repeat(self::BOX_H, $w)) . "\n\n");
$this->display($this->c(self::C_BOLD, 'Usage:') . " php {$this->scriptName}.php [options]\n\n");
$this->display($this->c(self::C_BOLD, 'Options:') . "\n");
$builtIn = [
'--help' => ['desc' => 'Show this help message', 'default' => null],
@@ -348,16 +368,16 @@ abstract class CliFramework
$hint = ($default !== null && $default !== false)
? $this->c(self::C_DIM, " (default: {$default})")
: '';
printf(
$this->display(sprintf(
" %s%-22s%s%s%s\n",
self::C_CYAN,
$name,
self::C_RESET,
$def['desc'],
$hint
);
));
}
echo "\n";
$this->display("\n");
}
// =========================================================================
@@ -378,23 +398,23 @@ abstract class CliFramework
$titleLine = $this->padRight($titleStyled, $inner, strlen($titleRaw));
$descLine = ($desc !== '') ? $this->padRight(" {$desc}", $inner) : null;
echo "\n";
echo $this->c(
$this->display("\n");
$this->display($this->c(
self::C_CYAN,
self::BOX_TL . str_repeat(self::BOX_H, $inner) . self::BOX_TR
) . "\n";
echo $this->c(self::C_CYAN, self::BOX_V)
) . "\n");
$this->display($this->c(self::C_CYAN, self::BOX_V)
. $this->c(self::C_BOLD, $titleLine)
. $this->c(self::C_CYAN, self::BOX_V) . "\n";
. $this->c(self::C_CYAN, self::BOX_V) . "\n");
if ($descLine !== null) {
echo $this->c(self::C_CYAN, self::BOX_V)
$this->display($this->c(self::C_CYAN, self::BOX_V)
. $this->c(self::C_DIM, $descLine)
. $this->c(self::C_CYAN, self::BOX_V) . "\n";
. $this->c(self::C_CYAN, self::BOX_V) . "\n");
}
echo $this->c(
$this->display($this->c(
self::C_CYAN,
self::BOX_BL . str_repeat(self::BOX_H, $inner) . self::BOX_BR
) . "\n\n";
) . "\n\n");
}
/** Print the dry-run notice box. */
@@ -403,18 +423,18 @@ abstract class CliFramework
$w = min($this->termWidth(), 70);
$msg = ' ' . self::ICON_DRY . ' DRY-RUN MODE — no changes will be written ';
$row = $this->padRight($msg, $w - 2);
echo $this->c(
$this->display($this->c(
self::C_YELLOW . self::C_BOLD,
self::BOX_TL . str_repeat(self::BOX_H, $w - 2) . self::BOX_TR
) . "\n";
echo $this->c(
) . "\n");
$this->display($this->c(
self::C_YELLOW . self::C_BOLD,
self::BOX_V . $row . self::BOX_V
) . "\n";
echo $this->c(
) . "\n");
$this->display($this->c(
self::C_YELLOW . self::C_BOLD,
self::BOX_BL . str_repeat(self::BOX_H, $w - 2) . self::BOX_BR
) . "\n\n";
) . "\n\n");
}
// =========================================================================
@@ -435,11 +455,11 @@ abstract class CliFramework
$w = $this->termWidth();
$text = " {$title} ";
$fill = max(0, $w - strlen($text) - 4);
echo "\n";
echo $this->c(
$this->display("\n");
$this->display($this->c(
self::C_CYAN,
str_repeat(self::BOX_H, 2) . $text . str_repeat(self::BOX_H, $fill)
) . "\n\n";
) . "\n\n");
}
/** Print a plain horizontal divider. */
@@ -449,7 +469,7 @@ abstract class CliFramework
return;
}
$this->clearProgress();
echo $this->c(self::C_DIM, str_repeat(self::BOX_H, $this->termWidth())) . "\n";
$this->display($this->c(self::C_DIM, str_repeat(self::BOX_H, $this->termWidth())) . "\n");
}
// =========================================================================
@@ -495,11 +515,7 @@ abstract class CliFramework
$line = "{$ts} {$icon} {$badge} {$text}\n";
if ($level === 'ERROR') {
fwrite(STDERR, $line);
} else {
echo $line;
}
$this->display($line);
}
/** Log a success message. */
@@ -564,7 +580,7 @@ abstract class CliFramework
? ' ' . $this->c(self::C_DIM, "{$detail}")
: '';
echo ' ' . $this->c($color . self::C_BOLD, $icon) . ' ' . $label . $suffix . "\n";
$this->display(' ' . $this->c($color . self::C_BOLD, $icon) . ' ' . $label . $suffix . "\n");
}
// =========================================================================
@@ -601,10 +617,10 @@ abstract class CliFramework
$line = " [{$bar}] {$percent} {$counter}{$suffix}";
if ($newline) {
echo "\r{$line}\n";
$this->display("\r{$line}\n");
$this->progressActive = false;
} else {
echo "\r{$line}";
$this->display("\r{$line}");
$this->progressActive = true;
}
}
@@ -613,7 +629,7 @@ abstract class CliFramework
protected function clearProgress(): void
{
if ($this->progressActive) {
echo "\r" . str_repeat(' ', $this->termWidth()) . "\r";
$this->display("\r" . str_repeat(' ', $this->termWidth()) . "\r");
$this->progressActive = false;
}
}
@@ -644,8 +660,8 @@ abstract class CliFramework
$maxKey = max(array_map('strlen', array_keys($rows)));
$inner = $maxKey + 20;
echo "\n";
echo $this->c($color, self::BOX_TL . str_repeat(self::BOX_H, $inner) . self::BOX_TR) . "\n";
$this->display("\n");
$this->display($this->c($color, self::BOX_TL . str_repeat(self::BOX_H, $inner) . self::BOX_TR) . "\n");
foreach ($rows as $label => $value) {
$valStr = (string) $value;
@@ -653,10 +669,10 @@ abstract class CliFramework
$padding = $inner - strlen($label) - $valVis - 4;
$row = ' ' . $this->c(self::C_BOLD, $label)
. str_repeat(' ', max(1, $padding)) . $valStr . ' ';
echo $this->c($color, self::BOX_V) . $row . $this->c($color, self::BOX_V) . "\n";
$this->display($this->c($color, self::BOX_V) . $row . $this->c($color, self::BOX_V) . "\n");
}
echo $this->c($color, self::BOX_BL . str_repeat(self::BOX_H, $inner) . self::BOX_BR) . "\n\n";
$this->display($this->c($color, self::BOX_BL . str_repeat(self::BOX_H, $inner) . self::BOX_BR) . "\n\n");
}
/**
@@ -702,7 +718,7 @@ abstract class CliFramework
$this->clearProgress();
$badge = $this->c(self::C_BOLD . self::C_MAGENTA, "Step {$current}/{$total}");
$arrow = $this->c(self::C_DIM, self::ICON_INFO);
echo "\n{$badge} {$arrow} {$title}\n";
$this->display("\n{$badge} {$arrow} {$title}\n");
}
// =========================================================================
@@ -964,13 +980,13 @@ abstract class CliFramework
}
// Header.
echo $sep . "\n";
$this->display($sep . "\n");
$headerLine = '|';
foreach ($headers as $i => $h) {
$headerLine .= ' ' . $this->c(self::C_BOLD, str_pad($h, $widths[$i])) . ' |';
}
echo $headerLine . "\n";
echo $sep . "\n";
$this->display($headerLine . "\n");
$this->display($sep . "\n");
// Rows.
foreach ($rows as $row) {
@@ -978,9 +994,9 @@ abstract class CliFramework
foreach ($row as $i => $cell) {
$line .= ' ' . str_pad((string) $cell, $widths[$i]) . ' |';
}
echo $line . "\n";
$this->display($line . "\n");
}
echo $sep . "\n";
$this->display($sep . "\n");
}
}
-117
View File
@@ -1,117 +0,0 @@
<!--
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: MokoPlatform.Documentation
INGROUP: MokoPlatform.Templates
REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
PATH: /templates/docs/dolibarr/update-server.md
BRIEF: Developer guide for wiring up Dolibarr module update checks — synced to docs/ in all CRM repos
-->
# Module Update Server
This module uses `update.txt` hosted in the repo root to enable Dolibarr's built-in update checker.
## How It Works
1. When a PR is merged to `main`, the `auto-release.yml` workflow:
- Reads the version from `README.md`
- Sets `$this->version` in the module descriptor to the real version
- Creates a GitHub Release with a git tag
- Writes `update.txt` to the repo root
2. The module descriptor's `$this->url_last_version` points to the raw `update.txt` URL
3. Dolibarr's admin panel fetches this URL to check for available updates
## Setup
### 1. Module Descriptor
In `src/core/modules/mod*.class.php`, ensure these lines are in the constructor:
```php
// Version — 'development' on dev branches, real version set by auto-release on merge to main
$this->version = 'development';
// Update check — points to update.txt written by auto-release workflow
$this->url_last_version = 'https://raw.githubusercontent.com/mokoconsulting-tech/REPO_NAME/main/update.txt';
```
Replace `REPO_NAME` with this repository's name.
### 2. Version Parser
Add this method to the module descriptor class to parse the JSON response:
```php
/**
* Get the latest available version from the update server.
*
* Reads update.txt from the GitHub repo and extracts the version field.
* Called by Dolibarr's module update checker.
*
* @return string Latest version number, or empty string on failure
*/
public function getLatestVersion(): string
{
if (empty($this->url_last_version)) {
return '';
}
$content = @file_get_contents($this->url_last_version);
if ($content === false) {
return '';
}
$data = json_decode($content, true);
return $data['version'] ?? '';
}
```
### 3. That's It
Everything else is automated:
- `deploy-dev.yml` sets version to `"development"` on dev branches
- `auto-release.yml` sets the real version and writes `update.txt` on release
- `sync-version-on-merge.yml` bumps the patch version in README.md
## update.txt Format
```json
{
"version": "01.02.03",
"tag": "v01.02.03",
"repo": "mokoconsulting-tech/REPO_NAME",
"release_url": "https://git.mokoconsulting.tech/mokoconsulting-tech/REPO_NAME/releases/tag/v01.02.03",
"updated": "2026-03-27T00:00:00Z"
}
```
> **Do not edit `update.txt` manually** — it is auto-generated by the release workflow.
## Version Lifecycle
```
dev/** branch → $this->version = "development" (no update.txt)
merge to main → $this->version = "01.02.03" → update.txt written → GitHub Release
next commit → README auto-bumps to 01.02.04 (no release yet)
```
## Troubleshooting
| Issue | Solution |
|-------|----------|
| `update.txt` doesn't exist | Merge a PR to main — the first release creates it |
| Version shows "development" | Expected on `dev/**` branches — real version set on release |
| Dolibarr doesn't detect updates | Check `$this->url_last_version` URL returns valid JSON |
| Wrong version in update.txt | Check README.md VERSION field — it's the source of truth |
### Test the URL
```bash
curl -s https://raw.githubusercontent.com/mokoconsulting-tech/REPO_NAME/main/update.txt | jq .
```
@@ -1,70 +0,0 @@
<!--
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: {{REPO_NAME}}.Documentation
INGROUP: MokoPlatform.Templates
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/{{REPO_NAME}}
PATH: /docs/update-server.md
VERSION: {{standards_version}}
BRIEF: How this module's update server file (update.txt) is managed
-->
# Dolibarr Update Server
[![moko-platform](https://img.shields.io/badge/moko--platform-{{standards_version}}-blue)](https://git.mokoconsulting.tech/MokoConsulting/moko-platform)
This document explains how `update.txt` is automatically managed for this Dolibarr module.
## How It Works
Dolibarr checks for module updates by fetching a plain-text file from the URL in `$this->url_last_version` in the module descriptor (`src/core/modules/mod*.class.php`). The file must contain **only the version string** — no JSON, no XML, no trailing newline.
### Automatic Generation
| Event | Workflow | `update.txt` Content | `$this->version` |
|-------|----------|---------------------|-------------------|
| Merge to `main` | `auto-release.yml` | `XX.YY.ZZ` (real version) | Real version |
| Push to `dev/**` | `deploy-dev.yml` | `development` | `development` |
| Push to `rc/**` | `deploy-dev.yml` | `XX.YY.ZZ-rc` | RC version |
### Module Descriptor
The `url_last_version` in your module descriptor should point to:
```
https://raw.githubusercontent.com/mokoconsulting-tech/{{REPO_NAME}}/main/update.txt
```
This is set automatically by `version_set_platform.php` during the build pipeline. **Never manually edit `$this->version` or `$this->url_last_version`** — the workflows handle it.
### Branch Lifecycle
```
dev/XX.YY.ZZ → rc/XX.YY.ZZ → main → version/XX
(development) (release candidate) (stable release) (frozen snapshot)
```
1. **Development** (`dev/**`): `update.txt` = `development`, `$this->version` = `development`
2. **Release Candidate** (`rc/**`): `update.txt` = `XX.YY.ZZ-rc`, version set to RC
3. **Stable Release** (merge to `main`): `auto-release.yml` writes real version to `update.txt`, creates GitHub Release + tag, creates `version/XX` branch
4. **Frozen Snapshot** (`version/XX`): immutable, never force-pushed
### Health Checks
The `repo_health.yml` workflow verifies on every commit:
- `update.txt` exists in the repository root
- Module descriptor (`mod*.class.php`) exists in `src/core/modules/`
- `$this->numero` is set and non-zero
- `$this->version` is not hardcoded (should be set by workflow)
- `url_last_version` points to `update.txt` (not `update.json`)
- `url_last_version` references `/main/` branch on the main branch
---
*Managed by [moko-platform](https://git.mokoconsulting.tech/MokoConsulting/moko-platform). See [docs/workflows/update-server.md](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/blob/main/docs/workflows/update-server.md) for the full specification.*
@@ -1,122 +0,0 @@
<!--
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: {{REPO_NAME}}.Documentation
INGROUP: MokoPlatform.Templates
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/{{REPO_NAME}}
PATH: /docs/update-server.md
VERSION: {{standards_version}}
BRIEF: How this extension's Joomla update server file (updates.xml) is managed
-->
# Joomla Update Server
[![moko-platform](https://img.shields.io/badge/moko--platform-{{standards_version}}-blue)](https://git.mokoconsulting.tech/MokoConsulting/moko-platform)
This document explains how `updates.xml` is automatically managed for this Joomla extension following the [Joomla Update Server specification](https://docs.joomla.org/Deploying_an_Update_Server).
## How It Works
Joomla checks for extension updates by fetching an XML file from the URL defined in the `<updateservers>` tag in the extension's XML manifest. moko-platform generates this file automatically.
### Automatic Generation
| Event | Workflow | `<tag>` | `<version>` |
|-------|----------|---------|-------------|
| Merge to `main` | `auto-release.yml` | `stable` | `XX.YY.ZZ` |
| Push to `dev/**` | `deploy-dev.yml` | `development` | `development` |
| Push to `rc/**` | `deploy-dev.yml` | `rc` | `XX.YY.ZZ-rc` |
### Generated XML Structure
```xml
<?xml version="1.0" encoding="utf-8"?>
<updates>
<update>
<name>Extension Name</name>
<description>Extension Name update</description>
<element>com_extensionname</element>
<type>component</type>
<version>01.02.03</version>
<client>site</client>
<folder>system</folder> <!-- plugins only -->
<tags>
<tag>stable</tag>
</tags>
<downloads>
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/.../releases/download/v01.02.03/com_ext-01.02.03.zip</downloadurl>
<downloadurl type="full" format="zip">https://github.com/.../releases/download/v01.02.03/com_ext-01.02.03.zip</downloadurl>
</downloads>
<targetplatform name="joomla" version="((5\.[0-9])|(6\.[0-9]))" />
<php_minimum>8.2</php_minimum> <!-- if present in manifest -->
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
</updates>
```
### Metadata Source
All metadata is extracted from the extension's XML manifest (`src/*.xml`) at build time:
| XML Element | Source | Notes |
|-------------|--------|-------|
| `<name>` | `<name>` in manifest | Extension display name |
| `<element>` | `<element>` in manifest | Must match installed extension identifier |
| `<type>` | `type` attribute on `<extension>` | `component`, `module`, `plugin`, `library`, `package`, `template` |
| `<client>` | `client` attribute on `<extension>` | `site` or `administrator`**required for plugins and modules** |
| `<folder>` | `group` attribute on `<extension>` | Plugin group (e.g., `system`, `content`) — **required for plugins** |
| `<targetplatform>` | `<targetplatform>` in manifest | Falls back to Joomla 5.x / 6.x if not specified |
| `<php_minimum>` | `<php_minimum>` in manifest | Included only if present |
### Extension Manifest Setup
Your XML manifest must include an `<updateservers>` tag pointing to the `updates.xml` on the `main` branch:
```xml
<extension type="component" client="site" method="upgrade">
<name>My Extension</name>
<element>com_myextension</element>
<!-- ... -->
<updateservers>
<server type="extension" priority="1" name="My Extension Update Server (Gitea)">
https://git.mokoconsulting.tech/mokoconsulting-tech/{{REPO_NAME}}/raw/branch/main/updates.xml
</server>
<server type="extension" priority="2" name="My Extension Update Server (GitHub)">
https://raw.githubusercontent.com/mokoconsulting-tech/{{REPO_NAME}}/main/updates.xml
</server>
</updateservers>
</extension>
```
### Branch Lifecycle
```
dev/XX.YY.ZZ → rc/XX.YY.ZZ → main → version/XX
(development) (rc) (stable) (frozen snapshot)
```
1. **Development** (`dev/**`): `updates.xml` with `<tag>development</tag>`, download points to branch archive
2. **Release Candidate** (`rc/**`): `updates.xml` with `<tag>rc</tag>`, version set to `XX.YY.ZZ-rc`
3. **Stable Release** (merge to `main`): `updates.xml` with `<tag>stable</tag>`, download points to Gitea Release asset (primary) + GitHub Release asset (mirror)
4. **Frozen Snapshot** (`version/XX`): immutable, never force-pushed
### Health Checks
The `repo_health.yml` workflow verifies on every commit:
- `updates.xml` exists in the repository root
- XML manifest exists with `<extension>` tag
- `<version>`, `<name>`, `<author>`, `<namespace>` tags present
- Extension `type` attribute is valid
- Language `.ini` files exist
- `index.html` directory listing protection in `src/`, `src/admin/`, `src/site/`
---
*Managed by [moko-platform](https://git.mokoconsulting.tech/MokoConsulting/moko-platform). See [docs/workflows/update-server.md](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/blob/main/docs/workflows/update-server.md) for the full specification.*
-119
View File
@@ -1,119 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
VERSION: {{VERSION}}
-->
<updates>
<!-- 1. DEVELOPMENT -->
<update>
<name>{{EXTENSION_NAME}}</name>
<description>{{EXTENSION_NAME}} development build — unstable.</description>
<element>{{EXTENSION_ELEMENT}}</element>
<type>{{EXTENSION_TYPE}}</type>
<folder>{{EXTENSION_FOLDER}}</folder>
<client>{{EXTENSION_CLIENT}}</client>
<version>{{VERSION}}</version>
<creationDate>{{DATE}}</creationDate>
<infourl title='{{EXTENSION_NAME}} Dev'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/tag/development</infourl>
<downloads>
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/download/development/{{EXTENSION_ELEMENT}}-{{VERSION}}-dev.zip</downloadurl>
</downloads>
<sha256></sha256>
<tags><tag>development</tag></tags>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name='joomla' version='(5|6).*'/>
<php_minimum>8.1</php_minimum>
</update>
<!-- 2. ALPHA -->
<update>
<name>{{EXTENSION_NAME}}</name>
<description>{{EXTENSION_NAME}} alpha build — early testing.</description>
<element>{{EXTENSION_ELEMENT}}</element>
<type>{{EXTENSION_TYPE}}</type>
<folder>{{EXTENSION_FOLDER}}</folder>
<client>{{EXTENSION_CLIENT}}</client>
<version>{{VERSION}}</version>
<creationDate>{{DATE}}</creationDate>
<infourl title='{{EXTENSION_NAME}} Alpha'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/tag/alpha</infourl>
<downloads>
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/download/alpha/{{EXTENSION_ELEMENT}}-{{VERSION}}-alpha.zip</downloadurl>
</downloads>
<sha256></sha256>
<tags><tag>alpha</tag></tags>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name='joomla' version='(5|6).*'/>
<php_minimum>8.1</php_minimum>
</update>
<!-- 3. BETA -->
<update>
<name>{{EXTENSION_NAME}}</name>
<description>{{EXTENSION_NAME}} beta build — feature complete, stability testing.</description>
<element>{{EXTENSION_ELEMENT}}</element>
<type>{{EXTENSION_TYPE}}</type>
<folder>{{EXTENSION_FOLDER}}</folder>
<client>{{EXTENSION_CLIENT}}</client>
<version>{{VERSION}}</version>
<creationDate>{{DATE}}</creationDate>
<infourl title='{{EXTENSION_NAME}} Beta'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/tag/beta</infourl>
<downloads>
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/download/beta/{{EXTENSION_ELEMENT}}-{{VERSION}}-beta.zip</downloadurl>
</downloads>
<sha256></sha256>
<tags><tag>beta</tag></tags>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name='joomla' version='(5|6).*'/>
<php_minimum>8.1</php_minimum>
</update>
<!-- 4. RC -->
<update>
<name>{{EXTENSION_NAME}}</name>
<description>{{EXTENSION_NAME}} release candidate — testing only.</description>
<element>{{EXTENSION_ELEMENT}}</element>
<type>{{EXTENSION_TYPE}}</type>
<folder>{{EXTENSION_FOLDER}}</folder>
<client>{{EXTENSION_CLIENT}}</client>
<version>{{VERSION}}</version>
<creationDate>{{DATE}}</creationDate>
<infourl title='{{EXTENSION_NAME}} RC'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/tag/release-candidate</infourl>
<downloads>
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/download/release-candidate/{{EXTENSION_ELEMENT}}-{{VERSION}}-rc.zip</downloadurl>
</downloads>
<sha256></sha256>
<tags><tag>rc</tag></tags>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name='joomla' version='(5|6).*'/>
<php_minimum>8.1</php_minimum>
</update>
<!-- 5. STABLE -->
<update>
<name>{{EXTENSION_NAME}}</name>
<description>{{EXTENSION_NAME}} — Moko Consulting Joomla extension.</description>
<element>{{EXTENSION_ELEMENT}}</element>
<type>{{EXTENSION_TYPE}}</type>
<folder>{{EXTENSION_FOLDER}}</folder>
<client>{{EXTENSION_CLIENT}}</client>
<version>{{VERSION}}</version>
<creationDate>{{DATE}}</creationDate>
<infourl title='{{EXTENSION_NAME}}'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/tag/stable</infourl>
<downloads>
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/releases/download/stable/{{EXTENSION_ELEMENT}}-{{VERSION}}.zip</downloadurl>
</downloads>
<sha256></sha256>
<tags><tag>stable</tag></tags>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name='joomla' version='(5|6).*'/>
<php_minimum>8.1</php_minimum>
</update>
</updates>
+1 -1
View File
@@ -63,7 +63,7 @@ class VersionBumpTest extends TestCase
{
file_put_contents(
"{$this->tmpDir}/README.md",
"<!-- VERSION: 09.21.07 -->\nSome content\n"
"<!-- VERSION: 09.25.00 -->\nSome content\n"
);
$this->execute();
+2 -2
View File
@@ -34,7 +34,7 @@ class VersionReadTest extends TestCase
{
file_put_contents(
"{$this->tmpDir}/README.md",
"# Test\n<!-- VERSION: 09.21.07 -->\n"
"# Test\n<!-- VERSION: 09.25.00 -->\n"
);
$this->assertSame('02.03.04', trim($this->runScript()));
@@ -68,7 +68,7 @@ class VersionReadTest extends TestCase
{
file_put_contents(
"{$this->tmpDir}/README.md",
"<!-- VERSION: 09.21.07 -->\n"
"<!-- VERSION: 09.25.00 -->\n"
);
mkdir("{$this->tmpDir}/src", 0755, true);
file_put_contents(
+1 -1
View File
@@ -12,7 +12,7 @@
* INGROUP: MokoPlatform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /validate/check_file_integrity.php
* VERSION: 09.23.00
* VERSION: 09.25.00
* BRIEF: Compare deployed files on a remote server against the local repository to detect drift
*/