From a53595650f944b9413ece1f5d5dbd731d86b51c7 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:39:36 -0600 Subject: [PATCH] Update updateserver.yml --- .github/workflows/updateserver.yml | 201 ++++++++++++++++++++++++++--- 1 file changed, 183 insertions(+), 18 deletions(-) diff --git a/.github/workflows/updateserver.yml b/.github/workflows/updateserver.yml index 7865fa3..feb15f3 100644 --- a/.github/workflows/updateserver.yml +++ b/.github/workflows/updateserver.yml @@ -1,10 +1,155 @@ - - name: Update updates.xml (version, date, download URL only) +name: Update Joomla Update Server XML Feed + +on: + release: + types: [prereleased, released] + workflow_dispatch: + inputs: + version: + description: "Version to publish (defaults to release tag on release events)" + required: false + default: "" + asset_name: + description: "ZIP asset base name (without .zip). Defaults to -." + required: false + default: "" + +permissions: + contents: write + issues: write + +env: + EXT_NAME: "MokoWaaS-Brand" + EXT_ELEMENT: "mokowaasbrand" + EXT_TYPE: "plugin" + EXT_FOLDER: "system" + EXT_CLIENT: "site" + EXT_CATEGORY: "MokoWaaS-Brand" + +jobs: + update-server: + name: Publish version to UpdateServer + runs-on: ubuntu-latest + environment: UpdateServer + + steps: + # ------------------------------------------------------------------ + # HARD PREFLIGHT CHECK + # ------------------------------------------------------------------ + - name: Validate required UpdateServer environment variables + shell: bash + run: | + set -euo pipefail + + if [ -z "${{ vars.UPDATESERVER_FILE_URL }}" ]; then + echo "ERROR: Required environment variable UPDATESERVER_FILE_URL is not defined." + echo "This workflow will not run without UpdateServer environment configuration." + exit 1 + fi + + echo "Preflight validation passed." + + # ------------------------------------------------------------------ + # VERSION + ASSET METADATA + # ------------------------------------------------------------------ + - name: Resolve version and asset metadata + id: meta + shell: bash + run: | + set -euo pipefail + + if [ "${{ github.event_name }}" = "release" ]; then + VERSION="${{ github.event.release.tag_name }}" + else + VERSION="${{ github.event.inputs.version }}" + fi + + if [ -z "${VERSION}" ]; then + echo "ERROR: Version is not defined." + exit 1 + fi + + if echo "${VERSION}" | grep -qiE "(^|[-.])rc([-.]|$)"; then + echo "RC version detected (${VERSION}). Publication skipped by policy." + echo "skip=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + echo "skip=false" >> "$GITHUB_OUTPUT" + + if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.asset_name }}" ]; then + ASSET_NAME="${{ github.event.inputs.asset_name }}" + else + REPO_NAME="${GITHUB_REPOSITORY##*/}" + ASSET_NAME="${REPO_NAME}-${VERSION}" + fi + + DOWNLOAD_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${VERSION}/${ASSET_NAME}.zip" + + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "asset_name=${ASSET_NAME}" >> "$GITHUB_OUTPUT" + echo "download_url=${DOWNLOAD_URL}" >> "$GITHUB_OUTPUT" + + # ------------------------------------------------------------------ + # PARSE UPDATE SERVER LOCATION (FROM ENV ONLY) + # ------------------------------------------------------------------ + - name: Parse UpdateServer URL from environment variable + if: steps.meta.outputs.skip != 'true' + id: parse + env: + UPDATESERVER_FILE_URL: ${{ vars.UPDATESERVER_FILE_URL }} + shell: bash + run: | + set -euo pipefail + + python << 'PY' + import os + from urllib.parse import urlparse + + url = os.environ["UPDATESERVER_FILE_URL"].strip() + + parsed = urlparse(url) + parts = parsed.path.strip("/").split("/") + + if len(parts) < 5 or parts[2] != "blob": + raise SystemExit(f"Invalid UPDATESERVER_FILE_URL format: {url}") + + owner = parts[0] + repo = parts[1] + branch = parts[3] + file_path = "/".join(parts[4:]) + + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: + fh.write(f"update_repo={owner}/{repo}\n") + fh.write(f"update_branch={branch}\n") + fh.write(f"update_file={file_path}\n") + PY + + # ------------------------------------------------------------------ + # CHECKOUT UPDATE SERVER REPO + # ------------------------------------------------------------------ + - name: Check out update server repository + if: steps.meta.outputs.skip != 'true' + uses: actions/checkout@v4 + with: + repository: ${{ steps.parse.outputs.update_repo }} + ref: ${{ steps.parse.outputs.update_branch }} + token: ${{ secrets.MOKO_UPDATES_TOKEN }} + fetch-depth: 0 + + # ------------------------------------------------------------------ + # UPDATE XML (VERSION, DATE, DOWNLOAD URL ONLY) + # ------------------------------------------------------------------ + - name: Update updates.xml if: steps.meta.outputs.skip != 'true' env: VERSION: ${{ steps.meta.outputs.version }} DOWNLOAD_URL: ${{ steps.meta.outputs.download_url }} UPDATE_FILE: ${{ steps.parse.outputs.update_file }} + shell: bash run: | + set -euo pipefail + python << 'PY' import os from datetime import datetime @@ -13,20 +158,18 @@ xml_path = Path(os.environ["UPDATE_FILE"]) if not xml_path.exists(): - raise SystemExit(f"{xml_path} not found in update server repository") + raise SystemExit(f"{xml_path} not found") tree = ET.parse(xml_path) root = tree.getroot() - version = os.environ["VERSION"].strip() - download_url = os.environ["DOWNLOAD_URL"].strip() + version = os.environ["VERSION"] + download_url = os.environ["DOWNLOAD_URL"] today = datetime.utcnow().strftime("%Y-%m-%d") - # Find an existing update node for this version; if none exists, create one. target = None for upd in root.findall("update"): - v_node = upd.find("version") - if v_node is not None and (v_node.text or "").strip() == version: + if (upd.findtext("version") or "").strip() == version: target = upd break @@ -34,19 +177,13 @@ target = ET.SubElement(root, "update") ET.SubElement(target, "version").text = version - # Ensure version is set (only set the version field) - v_node = target.find("version") - if v_node is None: - v_node = ET.SubElement(target, "version") - v_node.text = version + target.find("version").text = version - # Ensure creationDate is set - cd_node = target.find("creationDate") - if cd_node is None: - cd_node = ET.SubElement(target, "creationDate") - cd_node.text = today + cd = target.find("creationDate") + if cd is None: + cd = ET.SubElement(target, "creationDate") + cd.text = today - # Ensure downloads/downloadurl exists; update text only, keep attributes as-is if present downloads = target.find("downloads") if downloads is None: downloads = ET.SubElement(target, "downloads") @@ -59,3 +196,31 @@ tree.write(xml_path, encoding="utf-8", xml_declaration=True) PY + + # ------------------------------------------------------------------ + # COMMIT AND PUSH + # ------------------------------------------------------------------ + - name: Configure git user + if: steps.meta.outputs.skip != 'true' + shell: bash + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Commit and push update server changes + if: steps.meta.outputs.skip != 'true' + env: + VERSION: ${{ steps.meta.outputs.version }} + UPDATE_FILE: ${{ steps.parse.outputs.update_file }} + shell: bash + run: | + set -euo pipefail + + if git diff --quiet; then + echo "No changes to commit." + exit 0 + fi + + git add "${UPDATE_FILE}" + git commit -m "Update server metadata for version ${VERSION}" + git push