Clone
1
workflows-update-server.-
Jonathan Miller edited this page 2026-05-08 02:34:41 +00:00

Home

Update Server Files

moko-platform automatically generates platform-specific update server files on every release and dev/alpha/beta/rc deployment.

Overview

Platform File Format Reference
Dolibarr (crm-module) update.txt Plain text version string (< 30 chars) Dolibarr url_last_version check
Joomla (waas-component) updates.xml Multi-entry XML following Joomla update server spec Joomla Update Server Docs

Stability Tags

Joomla's updates.xml contains multiple <update> entries simultaneously — one per stability level. Joomla filters which entries the admin sees based on the site's Minimum Stability setting (Extensions > Update > Options).

Stability Joomla <tag> Who sees it Source workflow
Stable <tag>stable</tag> All sites (default) auto-release.yml on main
Release Candidate <tag>rc</tag> Sites set to RC or lower update-server.yml on rc/** push
Beta <tag>beta</tag> Sites set to Beta or lower update-server.yml on beta/** push
Alpha <tag>alpha</tag> Sites set to Alpha or lower update-server.yml on alpha/** push
Development <tag>development</tag> Sites set to Development update-server.yml on dev or dev/** push

Note: Alpha and beta are optional stages. Not every release cycle will have alpha/beta entries.

update-server.yml Trigger Behavior

The update-server.yml workflow triggers on both direct pushes and PR merges to the following branches:

  • dev (bare branch — no sub-path required)
  • dev/** (versioned dev branches like dev/02.01)
  • alpha/**
  • beta/**
  • rc/**

Previously, the workflow only triggered on PR merges. The addition of push triggers ensures that direct commits to these branches (e.g., CI-generated version bumps, automated fixes) also update the updates.xml entries.

Cascade Release Channels

Each stability level writes its own channel and all lower channels to updates.xml. This ensures Joomla sites on any "Minimum Stability" setting always see the latest available release:

Release Stream Channels written to updates.xml
development development
alpha development, alpha
beta development, alpha, beta
rc development, alpha, beta, rc
stable development, alpha, beta, rc, stable

Without cascade, a site set to "Development" minimum stability would only see <tag>development</tag> entries and would miss stable releases entirely. The cascade ensures stable releases are visible to all sites regardless of their minimum stability setting.

For full cascade documentation, see Cascade Release Channels.

Sync to Main

Since Joomla sites read updates.xml from the main branch, the update-server.yml workflow syncs updates.xml to main via the Gitea API after building on non-main branches. This ensures pre-release channel entries (dev, alpha, beta, rc) are visible to sites checking for updates, without requiring a PR merge to main.

Previously, update-server.yml only committed updates.xml to the current branch, so Joomla sites never saw dev/alpha/beta/rc releases until they were merged to main.

How Joomla Filters Updates

Joomla's update system reads all <update> entries from the XML file but only presents entries whose <tag> matches the site's minimum stability threshold:

  • Minimum Stability = Stable (default): Only sees <tag>stable</tag> entries
  • Minimum Stability = RC: Sees stable + rc entries
  • Minimum Stability = Beta: Sees stable + rc + beta entries
  • Minimum Stability = Alpha: Sees stable + rc + beta + alpha entries
  • Minimum Stability = Development: Sees all entries (stable + rc + beta + alpha + development)

The admin always gets the highest version among visible entries.

Dolibarr Stability

Workflow Branch update.txt content
auto-release.yml main XX.YY.ZZ (real version)
deploy-dev.yml rc/** XX.YY.ZZ-rc
deploy-dev.yml beta/** XX.YY.ZZ-beta
deploy-dev.yml alpha/** XX.YY.ZZ-alpha
deploy-dev.yml dev/** development

Branch Lifecycle

dev → [alpha] → [beta] → rc → version/XX → main → dev
       optional   optional     (integration)  (production)  (feedback)
  • dev or dev/**: Active development. Update files tagged as development.
  • alpha/**: (Optional) Early internal testing. Update files tagged as alpha. Can be skipped.
  • beta/**: (Optional) Broader external testing. Update files tagged as beta. Can be skipped.
  • rc/**: Release candidate. Update files tagged as rc. RC branches deploy to dev server for final testing.
  • version/XX: Major version integration branch (major only). All minors and patches flow into the same major branch.
  • main: Stable release. auto-release.yml creates GitHub Release and vXX tag. Update files tagged as stable.
  • Main merges back to dev to start the next cycle.

Dolibarr: update.txt

Dolibarr modules check for updates by fetching a plain-text file from the URL in $this->url_last_version. The file must contain only the version string (e.g., 01.02.03) — no JSON, no XML, no newlines.

On release (main):

01.02.03

On RC deploy (rc/):**

01.02.03-rc

On dev deploy (dev/):**

development

The module descriptor's url_last_version should point to:

https://git.mokoconsulting.tech/MokoConsulting/{repo}/raw/branch/main/update.txt

Joomla: updates.xml (Multi-Entry)

The updates.xml file contains up to five stability entries at once (one per stability level). Joomla reads the entire file and filters by the site's minimum stability setting.

Platform Distribution

Release Type Gitea Release GitHub Release Download URLs
Stable Yes Yes (via mirror) Dual (Gitea + GitHub)
RC Yes No Single (Gitea only)
Beta Yes No Single (Gitea only)
Alpha Yes No Single (Gitea only)
Development Yes No Single (Gitea only)

Pre-release builds stay on Gitea for internal testing. Only stable releases are mirrored to GitHub.

Complete Multi-Entry Example

<?xml version="1.0" encoding="utf-8"?>
<updates>
    <update>
        <name>My Extension</name>
        <description>My Extension stable release</description>
        <element>com_myextension</element>
        <type>component</type>
        <version>01.02.03</version>
        <tags>
            <tag>stable</tag>
        </tags>
        <infourl title="My Extension">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases</infourl>
        <downloads>
            <downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/v01/com_myextension-01.02.03.zip</downloadurl>
            <downloadurl type="full" format="zip">https://github.com/mokoconsulting-tech/MyExtension/releases/download/v01/com_myextension-01.02.03.zip</downloadurl>
        </downloads>
        <targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
        <maintainer>Moko Consulting</maintainer>
        <maintainerurl>https://mokoconsulting.tech</maintainerurl>
    </update>

    <update>
        <name>My Extension</name>
        <description>My Extension release candidate</description>
        <element>com_myextension</element>
        <type>component</type>
        <version>01.03.01-rc</version>
        <tags>
            <tag>rc</tag>
        </tags>
        <infourl title="My Extension">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/src/branch/rc</infourl>
        <downloads>
            <downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/rc/com_myextension-01.03.01-rc.zip</downloadurl>
        </downloads>
        <targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
        <maintainer>Moko Consulting</maintainer>
        <maintainerurl>https://mokoconsulting.tech</maintainerurl>
    </update>

    <update>
        <name>My Extension</name>
        <description>My Extension beta build</description>
        <element>com_myextension</element>
        <type>component</type>
        <version>01.03.01-beta</version>
        <tags>
            <tag>beta</tag>
        </tags>
        <infourl title="My Extension">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/src/branch/beta</infourl>
        <downloads>
            <downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/beta/com_myextension-01.03.01-beta.zip</downloadurl>
        </downloads>
        <targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
        <maintainer>Moko Consulting</maintainer>
        <maintainerurl>https://mokoconsulting.tech</maintainerurl>
    </update>

    <update>
        <name>My Extension</name>
        <description>My Extension alpha build</description>
        <element>com_myextension</element>
        <type>component</type>
        <version>01.03.01-alpha</version>
        <tags>
            <tag>alpha</tag>
        </tags>
        <infourl title="My Extension">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/src/branch/alpha</infourl>
        <downloads>
            <downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/alpha/com_myextension-01.03.01-alpha.zip</downloadurl>
        </downloads>
        <targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
        <maintainer>Moko Consulting</maintainer>
        <maintainerurl>https://mokoconsulting.tech</maintainerurl>
    </update>

    <update>
        <name>My Extension</name>
        <description>My Extension development build</description>
        <element>com_myextension</element>
        <type>component</type>
        <version>01.04.00-dev</version>
        <tags>
            <tag>development</tag>
        </tags>
        <infourl title="My Extension">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/src/branch/dev</infourl>
        <downloads>
            <downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/development/com_myextension-01.04.00-dev.zip</downloadurl>
        </downloads>
        <targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
        <maintainer>Moko Consulting</maintainer>
        <maintainerurl>https://mokoconsulting.tech</maintainerurl>
    </update>
</updates>

Which Workflow Writes Which Entry

Workflow Trigger Entry written
auto-release.yml Push to main <tag>stable</tag> — writes the stable entry with SHA-256 hash of the ZIP
update-server.yml Push to rc/** <tag>rc</tag> — adds/updates the RC entry (+ cascaded lower channels)
update-server.yml Push to beta/** <tag>beta</tag> — adds/updates the beta entry (+ cascaded lower channels)
update-server.yml Push to alpha/** <tag>alpha</tag> — adds/updates the alpha entry (+ cascaded lower channels)
update-server.yml Push to dev or dev/** <tag>development</tag> — adds/updates the development entry

The auto-release.yml workflow writes the stable entry and preserves any existing pre-release entries. The update-server.yml workflow writes its specific entry (and cascaded lower channels) and preserves the others.

Important: All update-server.yml runs also sync the updated updates.xml to main via the Gitea API, since Joomla sites read the update server XML from the main branch.

XML Elements

All metadata is auto-extracted from the extension's XML manifest at build time:

Element Source Notes
<name> <name> in manifest Extension display name
<element> <element> in manifest, or manifest filename Must match installed extension
<type> type attribute on <extension> component, module, plugin, library, package, template
<client> client attribute on <extension> site or administratorrequired for plugins and modules
<folder> group attribute on <extension> Plugin group (e.g., system, content) — required for plugins
<version> README.md VERSION field Real version on release, development on dev
<tags><tag> Workflow determines stable on release, development on dev
<targetplatform> <targetplatform> in manifest Falls back to Joomla 5.x / 6.x
<php_minimum> <php_minimum> in manifest Optional, included if present
<infourl> GitHub release/branch URL Links to release page or branch
<downloads><downloadurl> GitHub release asset or branch archive type="full" format="zip"

Extension Manifest Setup

For the updates.xml generation to work correctly, your Joomla extension manifest must include:

<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}/raw/branch/main/updates.xml
        </server>
        <server type="extension" priority="2" name="My Extension Update Server (GitHub)">
            https://raw.githubusercontent.com/mokoconsulting-tech/{repo}/main/updates.xml
        </server>
    </updateservers>
</extension>

The <updateservers> tag tells Joomla where to check for updates. Both servers are declared for redundancy — Gitea (primary, priority 1) and GitHub mirror (fallback, priority 2).

How It Works

Joomla (updates.xml)

  1. On release (auto-release.yml → main branch):

    • Builds ZIP from src/ directory
    • Uploads ZIP to the vXX major release on GitHub
    • Computes SHA-256 hash of the ZIP
    • Writes/updates the <tag>stable</tag> entry in updates.xml with version, download URL, and SHA-256
    • Cascades to all 5 stability channels
    • Preserves any existing rc/dev entries in the file
    • Commits updated updates.xml to main
  2. On RC push (update-server.yml → rc/** branches):

    • Writes/updates the <tag>rc</tag> entry in updates.xml
    • Cascades to rc, beta, alpha, and development channels
    • Download URL points to the Gitea release ZIP
    • Preserves all other stability entries
    • Commits updated updates.xml to the rc branch
    • Syncs updates.xml to main via Gitea API
  3. On beta push (update-server.yml → beta/** branches):

    • Writes/updates the <tag>beta</tag> entry in updates.xml
    • Cascades to beta, alpha, and development channels
    • Download URL points to the Gitea release ZIP
    • Preserves all other stability entries
    • Commits updated updates.xml to the beta branch
    • Syncs updates.xml to main via Gitea API
  4. On alpha push (update-server.yml → alpha/** branches):

    • Writes/updates the <tag>alpha</tag> entry in updates.xml
    • Cascades to alpha and development channels
    • Download URL points to the Gitea release ZIP
    • Preserves all other stability entries
    • Commits updated updates.xml to the alpha branch
    • Syncs updates.xml to main via Gitea API
  5. On dev push (update-server.ymldev or dev/** branches):

    • Writes/updates the <tag>development</tag> entry in updates.xml
    • Download URL points to the Gitea release ZIP
    • Preserves all other stability entries
    • Commits updated updates.xml to the dev branch
    • Syncs updates.xml to main via Gitea API

Dolibarr (update.txt)

  1. On release (auto-release.yml → main): writes real version to update.txt
  2. On RC deploy (deploy-dev.yml → rc/**): writes XX.YY.ZZ-rc to update.txt
  3. On beta deploy (deploy-dev.yml → beta/**): writes XX.YY.ZZ-beta to update.txt
  4. On alpha deploy (deploy-dev.yml → alpha/**): writes XX.YY.ZZ-alpha to update.txt
  5. On dev deploy (deploy-dev.yml → dev/**): writes development to update.txt

RC --> Main Flow

When a release candidate is ready:

  1. rc/XX.YY.ZZ branch is tested with <tag>rc</tag> update entries
  2. RC branch is merged to main via PR
  3. Push to main triggers auto-release.yml → GitHub Release + vXX tag
  4. updates.xml on main gets a new/updated <tag>stable</tag> entry
  5. version/XX archive branch is auto-created

Health Checks

The platform-specific repo_health.yml workflows verify:

  • Dolibarr: update.txt exists in root, module descriptor valid, url_last_version correct
  • Joomla: updates.xml exists in root, XML manifest valid, language files present

Rulesets

Branch protection rulesets (applied via sync_rulesets.php):

  • MAIN: prevents deletion, non-fast-forward, requires PRs
  • VERSION: immutable — prevents updates, deletion, force-push
  • DEV: prevents deletion, non-fast-forward
  • ALPHA: prevents deletion, non-fast-forward
  • BETA: prevents deletion, non-fast-forward
  • RC: prevents deletion, non-fast-forward

Update Server Priority

Joomla manifest <updateservers> entries MUST follow this priority order:

Priority Server URL pattern
1 (primary) Gitea https://git.mokoconsulting.tech/MokoConsulting/{REPO}/raw/branch/main/updates.xml
2 (fallback) GitHub https://raw.githubusercontent.com/mokoconsulting-tech/{REPO}/main/updates.xml

Why Gitea first

  1. Gitea is the source of truth — all CI/CD runs on Gitea, releases are created here first
  2. GitHub is a push mirror — it may lag behind by minutes or hours
  3. Self-hosted control — Gitea is under our infrastructure, GitHub is third-party
  4. Availability — if GitHub has an outage, Joomla sites still get updates from Gitea

Manifest example

<updateservers>
  <server type="extension" priority="1" name="ExtensionName Update Server (Gitea)">
    https://git.mokoconsulting.tech/MokoConsulting/RepoName/raw/branch/main/updates.xml
  </server>
  <server type="extension" priority="2" name="ExtensionName Update Server (GitHub)">
    https://raw.githubusercontent.com/mokoconsulting-tech/RepoName/main/updates.xml
  </server>
</updateservers>

Enforcement

The enforce_tags.sh script and repo_health.yml workflow validate this ordering. Repos with GitHub as priority 1 will be flagged as non-compliant.