From 2b0f0a37046920e7e066a3e90e3f292fad5a7941 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sun, 24 May 2026 23:10:40 -0500 Subject: [PATCH 1/2] fix(ci): rewrite pre-release.yml with PHP CLI tools - Fix broken platform detection (mangled sed pipeline on line 58) - Replace inline Python updates.xml manipulation with PHP - Use moko-platform CLI tools (version_bump, version_set_platform, release_cascade) instead of inline reimplementations - Support pre-installed /opt/moko-platform with fallback to git clone - Add summary step for job output Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) --- .mokogitea/workflows/pre-release.yml | 231 +++++++++++---------------- 1 file changed, 89 insertions(+), 142 deletions(-) diff --git a/.mokogitea/workflows/pre-release.yml b/.mokogitea/workflows/pre-release.yml index f2f9bd9..44d3de6 100644 --- a/.mokogitea/workflows/pre-release.yml +++ b/.mokogitea/workflows/pre-release.yml @@ -5,9 +5,9 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: moko-platform.Release -# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards +# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform # PATH: /templates/workflows/universal/pre-release.yml.template -# VERSION: 05.00.00 +# VERSION: 05.01.00 # BRIEF: Manual pre-release -- builds dev/alpha/beta/rc packages from any branch name: "Universal: Pre-Release" @@ -45,20 +45,35 @@ jobs: fetch-depth: 0 token: ${{ secrets.GA_TOKEN }} - - name: Setup PHP + - name: Setup tools run: | - if ! command -v php &> /dev/null; then - sudo apt-get update -qq - sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip >/dev/null 2>&1 + # Update moko-platform CLI tools if available; install PHP if missing + if command -v moko-platform-update &> /dev/null; then + moko-platform-update + elif [ -d "/opt/moko-platform" ]; then + cd /opt/moko-platform && git pull origin main --quiet 2>/dev/null || true + else + if ! command -v php &> /dev/null; then + sudo apt-get update -qq + sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl >/dev/null 2>&1 + fi + git clone --depth 1 --branch main --quiet \ + "https://x-access-token:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/moko-platform.git" \ + /tmp/moko-platform-api + fi + # Set MOKO_CLI to whichever path exists + if [ -d "/opt/moko-platform/cli" ]; then + echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV" + else + echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV" fi - name: Detect platform id: platform run: | - tr -d '[:space:]')| tr -d '[:space:]') + PLATFORM=$(sed -n 's/.*\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1 | tr -d '[:space:]') [ -z "$PLATFORM" ] && PLATFORM="generic" echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" - # For packages: prefer pkg_*.xml in src/; fallback to any manifest MANIFEST=$(find ./src -maxdepth 1 -name "pkg_*.xml" -exec grep -l '/dev/null | head -1) [ -z "$MANIFEST" ] && MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" ! -path "*/packages/*" -exec grep -l '/dev/null | head -1) [ -z "$MANIFEST" ] && MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '/dev/null | head -1) @@ -66,7 +81,7 @@ jobs: echo "manifest=${MANIFEST}" >> "$GITHUB_OUTPUT" echo "mod_file=${MOD_FILE}" >> "$GITHUB_OUTPUT" - - name: Resolve metadata + - name: Resolve metadata and bump version id: meta run: | STABILITY="${{ inputs.stability }}" @@ -78,66 +93,19 @@ jobs: release-candidate) SUFFIX="-rc"; TAG="release-candidate" ;; esac - # Read and bump patch version (with rollover) - CURRENT=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' README.md 2>/dev/null | head -1) - [ -z "$CURRENT" ] && CURRENT="00.00.00" - - MAJOR=$(echo "$CURRENT" | cut -d. -f1) - MINOR=$(echo "$CURRENT" | cut -d. -f2) - PATCH=$(echo "$CURRENT" | cut -d. -f3) - - # Patch bump with rollover: ZZ=99 -> bump minor, YY=99 -> bump major - NEW_PATCH=$((10#$PATCH + 1)) - NEW_MINOR=$((10#$MINOR)) - NEW_MAJOR=$((10#$MAJOR)) - - if [ $NEW_PATCH -gt 99 ]; then - NEW_PATCH=0 - NEW_MINOR=$((NEW_MINOR + 1)) - fi - if [ $NEW_MINOR -gt 99 ]; then - NEW_MINOR=0 - NEW_MAJOR=$((NEW_MAJOR + 1)) - fi - - VERSION=$(printf "%02d.%02d.%02d" $NEW_MAJOR $NEW_MINOR $NEW_PATCH) + # Patch bump via CLI tool + php ${MOKO_CLI}/version_bump.php --path . + VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null) + [ -z "$VERSION" ] && VERSION="00.00.01" TODAY=$(date +%Y-%m-%d) - echo "Bumping: ${CURRENT} -> ${VERSION} (patch)" - - # Update README.md - sed -i "s/VERSION:[[:space:]]*${CURRENT}/VERSION: ${VERSION}/" README.md - # Update platform-specific manifest PLATFORM="${{ steps.platform.outputs.platform }}" MANIFEST="${{ steps.platform.outputs.manifest }}" MOD_FILE="${{ steps.platform.outputs.mod_file }}" - case "$PLATFORM" in - joomla) - if [ -n "$MANIFEST" ]; then - MANIFEST_VER=$(sed -n 's/.*\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" | head -1) - sed -i "s|${MANIFEST_VER}|${VERSION}|" "$MANIFEST" - sed -i "s|[^<]*|${TODAY}|" "$MANIFEST" - fi - # For packages: also bump version in all sub-extension manifests - if [ -d "src/packages" ]; then - for SUB_MANIFEST in $(find src/packages -maxdepth 2 -name "*.xml" -exec grep -l '/dev/null); do - SUB_VER=$(sed -n 's/.*\([^<]*\)<\/version>.*/\1/p' "$SUB_MANIFEST" | head -1) - if [ -n "$SUB_VER" ]; then - sed -i "s|${SUB_VER}|${VERSION}|" "$SUB_MANIFEST" - sed -i "s|[^<]*|${TODAY}|" "$SUB_MANIFEST" - echo " Bumped sub-extension: $(basename $SUB_MANIFEST) ${SUB_VER} -> ${VERSION}" - fi - done - fi - ;; - dolibarr) - if [ -n "$MOD_FILE" ]; then - sed -i "s/\$this->version = '[^']*'/\$this->version = '${VERSION}'/" "$MOD_FILE" - fi - ;; - *) ;; - esac + + php ${MOKO_CLI}/version_set_platform.php \ + --path . --version "$VERSION" --branch "${{ github.ref_name }}" 2>/dev/null || true # Commit version bump git config --local user.email "gitea-actions[bot]@mokoconsulting.tech" @@ -145,15 +113,14 @@ jobs: git remote set-url origin "https://jmiller:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git" git add -A git diff --cached --quiet || { - git commit -m "chore(version): bump ${CURRENT} -> ${VERSION} [skip ci]" + git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]" git push origin HEAD 2>&1 } # Auto-detect element (platform-aware) + EXT_ELEMENT="" case "$PLATFORM" in joomla) - MANIFEST="${{ steps.platform.outputs.manifest }}" - EXT_ELEMENT="" if [ -n "$MANIFEST" ]; then EXT_ELEMENT=$(sed -n 's/.*\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" 2>/dev/null | head -1) if [ -z "$EXT_ELEMENT" ]; then @@ -167,7 +134,6 @@ jobs: fi ;; dolibarr) - MOD_FILE="${{ steps.platform.outputs.mod_file }}" if [ -n "$MOD_FILE" ]; then MOD_BASENAME=$(basename "$MOD_FILE" .class.php) EXT_ELEMENT=$(echo "$MOD_BASENAME" | sed 's/^mod//' | tr '[:upper:]' '[:lower:]') @@ -213,8 +179,6 @@ jobs: if [ "$EXT_TYPE" = "package" ] && [ -d "${SOURCE_DIR}/packages" ]; then echo "=== Building Joomla PACKAGE (multi-extension) ===" - - # 1) ZIP each sub-extension in src/packages/ for ext_dir in "${SOURCE_DIR}"/packages/*/; do [ ! -d "$ext_dir" ] && continue EXT_NAME=$(basename "$ext_dir") @@ -223,16 +187,11 @@ jobs: zip -r "../../build/package/${EXT_NAME}.zip" . -x $EXCLUDES cd "$OLDPWD" done - - # 2) Copy package-level files (manifest, script, etc.) for f in "${SOURCE_DIR}"/*.xml "${SOURCE_DIR}"/*.php; do [ -f "$f" ] && cp "$f" build/package/ done - - echo "Package contents:" - ls -la build/package/ else - echo "=== Building standard Joomla extension ===" + echo "=== Building standard extension ===" rsync -a \ --exclude='sftp-config*' \ --exclude='.ftpignore' \ @@ -314,57 +273,51 @@ jobs: SHA256="${{ steps.zip.outputs.sha256 }}" ZIP_NAME="${{ steps.meta.outputs.zip_name }}" TAG="${{ steps.meta.outputs.tag }}" - DATE=$(date +%Y-%m-%d) if [ ! -f "updates.xml" ]; then echo "No updates.xml -- skipping" exit 0 fi - export PY_STABILITY="$STABILITY" PY_VERSION="$VERSION" PY_SHA256="$SHA256" \ - PY_ZIP_NAME="$ZIP_NAME" PY_TAG="$TAG" PY_DATE="$DATE" \ - PY_GITEA_ORG="$GITEA_ORG" PY_GITEA_REPO="$GITEA_REPO" - python3 << 'PYEOF' - import re, os - - stability = os.environ["PY_STABILITY"] - version = os.environ["PY_VERSION"] - sha256 = os.environ["PY_SHA256"] - zip_name = os.environ["PY_ZIP_NAME"] - tag = os.environ["PY_TAG"] - date = os.environ["PY_DATE"] - gitea_org = os.environ["PY_GITEA_ORG"] - gitea_repo = os.environ["PY_GITEA_REPO"] - download_url = f"https://git.mokoconsulting.tech/{gitea_org}/{gitea_repo}/releases/download/{tag}/{zip_name}" - - with open("updates.xml", "r") as f: - content = f.read() - # Map stability to XML tag name - tag_map = {"development": "development", "alpha": "alpha", "beta": "beta", "release-candidate": "rc"} - xml_tag = tag_map.get(stability, stability) + case "$STABILITY" in + development) XML_TAG="development" ;; + alpha) XML_TAG="alpha" ;; + beta) XML_TAG="beta" ;; + release-candidate) XML_TAG="rc" ;; + *) XML_TAG="$STABILITY" ;; + esac - pattern = r"((?:(?!).)*?" + re.escape(xml_tag) + r".*?)" - match = re.search(pattern, content, re.DOTALL) - if match: - block = match.group(1) - updated = re.sub(r"[^<]*", f"{version}", block) - updated = re.sub(r"[^<]*", f"{date}", updated) - if "" in updated: - updated = re.sub(r"[^<]*", f"{sha256}", updated) - else: - updated = updated.replace("", f"\n {sha256}") - updated = re.sub(r"(]*>)[^<]*()", rf"\g<1>{download_url}\g<2>", updated) - content = content.replace(block, updated) - print(f"Updated {xml_tag} channel: version={version}") - else: - print(f"WARNING: No {xml_tag} block in updates.xml") + DOWNLOAD_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${TAG}/${ZIP_NAME}" - with open("updates.xml", "w") as f: - f.write(content) - PYEOF + # Use PHP to update the channel in updates.xml + php -r ' + $xml_tag = $argv[1]; + $version = $argv[2]; + $sha256 = $argv[3]; + $url = $argv[4]; + $date = date("Y-m-d"); - # Commit and push to current branch + $content = file_get_contents("updates.xml"); + $pattern = "/((?:(?!<\/update>).)*?" . preg_quote($xml_tag) . "<\/tag>.*?<\/update>)/s"; + + $content = preg_replace_callback($pattern, function($m) use ($version, $sha256, $url, $date) { + $block = $m[0]; + $block = preg_replace("/[^<]*<\/version>/", "{$version}", $block); + if (strpos($block, "") !== false) { + $block = preg_replace("/[^<]*<\/sha256>/", "{$sha256}", $block); + } else { + $block = str_replace("", "\n {$sha256}", $block); + } + $block = preg_replace("/(]*>)[^<]*(<\/downloadurl>)/", "\${1}{$url}\${2}", $block); + return $block; + }, $content); + + file_put_contents("updates.xml", $content); + echo "Updated {$xml_tag} channel: version={$version}\n"; + ' "$XML_TAG" "$VERSION" "$SHA256" "$DOWNLOAD_URL" + + # Commit and push if ! git diff --quiet updates.xml 2>/dev/null; then git config --local user.email "gitea-actions[bot]@mokoconsulting.tech" git config --local user.name "gitea-actions[bot]" @@ -380,10 +333,8 @@ jobs: git config --local user.email "gitea-actions[bot]@mokoconsulting.tech" git config --local user.name "gitea-actions[bot]" - # Sync updates.xml to main and dev (whichever isn't current) for BRANCH in main dev; do [ "$BRANCH" = "$CURRENT_BRANCH" ] && continue - echo "Syncing updates.xml -> ${BRANCH}" git fetch origin "${BRANCH}" 2>/dev/null || continue git checkout "origin/${BRANCH}" -- . 2>/dev/null || continue @@ -401,28 +352,24 @@ jobs: run: | API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" TOKEN="${{ secrets.GA_TOKEN }}" + + php ${MOKO_CLI}/release_cascade.php \ + --stability "${{ steps.meta.outputs.stability }}" \ + --token "${TOKEN}" \ + --api-base "${API_BASE}" + + - name: Summary + if: always() + run: | + VERSION="${{ steps.meta.outputs.version }}" STABILITY="${{ steps.meta.outputs.stability }}" - - # Cascade: rc -> beta,alpha,dev | beta -> alpha,dev | alpha -> dev | dev -> nothing - case "$STABILITY" in - release-candidate) TAGS_TO_DELETE="beta alpha development" ;; - beta) TAGS_TO_DELETE="alpha development" ;; - alpha) TAGS_TO_DELETE="development" ;; - *) TAGS_TO_DELETE="" ;; - esac - - [ -z "$TAGS_TO_DELETE" ] && exit 0 - - for TAG in $TAGS_TO_DELETE; do - RELEASE_ID=$(curl -sS -H "Authorization: token ${TOKEN}" \ - "${API_BASE}/releases/tags/${TAG}" 2>/dev/null | \ - python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true) - - if [ -n "$RELEASE_ID" ] && [ "$RELEASE_ID" != "None" ]; then - curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \ - "${API_BASE}/releases/${RELEASE_ID}" 2>/dev/null || true - curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \ - "${API_BASE}/tags/${TAG}" 2>/dev/null || true - echo "Deleted: ${TAG} (id: ${RELEASE_ID})" - fi - done + ZIP_NAME="${{ steps.meta.outputs.zip_name }}" + SHA256="${{ steps.zip.outputs.sha256 }}" + echo "## Pre-Release Complete" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY + echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY + echo "| Channel | ${STABILITY} |" >> $GITHUB_STEP_SUMMARY + echo "| Package | \`${ZIP_NAME}\` |" >> $GITHUB_STEP_SUMMARY + echo "| SHA-256 | \`${SHA256:-n/a}\` |" >> $GITHUB_STEP_SUMMARY -- 2.52.0 From 6125f945be93ba354b5d2301fab6684345275479 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sun, 24 May 2026 23:17:08 -0500 Subject: [PATCH 2/2] docs: update CHANGELOG with session work Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4df529a..3086158 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,11 +22,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Removed -- Removed deploy-manual.yml workflow — switching to Joomla update server method for extension distribution +- Removed deploy-manual.yml workflow -- switching to Joomla update server method for extension distribution - Removed deploy variables and secrets (DEV_FTP_*) +- **Theme preview removed** -- Removed unused language strings for theme preview feature (never wired into config) +- **Repo cleanup** -- Removed 38 unused files: Fredoka/Pacifico fonts, dead npm tooling (package.json, scripts/), tmp-overrides/, placeholder tests, orphaned workflow copies, stale READMEs +- **Broken font options removed** -- Removed Noto Sans and Fira Sans from font selector (CSS files never existed) +- **Docs moved to wiki** -- CONTRIBUTING.md, CODE_OF_CONDUCT.md, GOVERNANCE.md migrated to Gitea wiki + +### Changed +- **repo-health.yml** -- Wiki-preferred documentation checks via Gitea API (wiki = full credit, repo file = advisory) +- **auto-release.yml Step 8b** -- Replaced inline Python with release_body_update.php CLI tool (fixes SIGPIPE exit 141) +- **pre-release.yml rewritten** -- Uses moko-platform CLI tools, PHP instead of Python, fixed broken platform detection +- **All workflow YAML files** -- Stripped non-ASCII characters (em dashes, arrows, emoji) for Gitea YAML parser compatibility ### Fixed -- **Menu icon padding removed** — Removed hardcoded `p-2` class from all mod_menu icon spans (horizontal + mainmenu layouts); icons now inherit spacing from the parent link +- **Menu icon padding removed** -- Removed hardcoded `p-2` class from all mod_menu icon spans (horizontal + mainmenu layouts); icons now inherit spacing from the parent link +- **Runner checkout failures** -- Fixed MySQL deadlocks in Gitea actions scheduler by restarting Gitea and recreating runners with --privileged flag +- **workflow_dispatch 500 error** -- Stripped UTF-8 multibyte characters from all YAML files that Gitea's Go parser rejected as control characters ## [02.06.00] - 2026-05-16 -- 2.52.0