- mokoconsulting-tech → MokoConsulting across all docs - github.com → git.mokoconsulting.tech - CLI examples updated with new org name Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
15 KiB
Update Server Files
MokoStandards 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/** push |
Note: Alpha and beta are optional stages. Not every release cycle will have alpha/beta entries.
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+rcentries - Minimum Stability = Beta: Sees
stable+rc+betaentries - Minimum Stability = Alpha: Sees
stable+rc+beta+alphaentries - 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/**: Active development. Update files tagged asdevelopment.alpha/**: (Optional) Early internal testing. Update files tagged asalpha. Can be skipped.beta/**: (Optional) Broader external testing. Update files tagged asbeta. Can be skipped.rc/**: Release candidate. Update files tagged asrc. 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.ymlcreates GitHub Release andvXXtag. Update files tagged asstable.- Main merges back to
devto 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://raw.githubusercontent.com/{org}/{repo}/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.
Complete Multi-Entry Example
<?xml version="1.0" encoding="utf-8"?>
<updates>
<!-- Stable entry: visible to all sites (default minimum stability) -->
<update>
<name>My Extension</name>
<description>My Extension stable release</description>
<element>com_myextension</element>
<type>component</type>
<version>01.02.03</version>
<client>site</client>
<tags>
<tag>stable</tag>
</tags>
<infourl title="My Extension">https://github.com/org/repo/releases/tag/v01</infourl>
<downloads>
<downloadurl type="full" format="zip">https://github.com/org/repo/releases/download/v01/com_myextension-01.02.03.zip</downloadurl>
</downloads>
<sha256>abc123...full-hash-here</sha256>
<targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
<!-- RC entry: visible to sites with minimum stability = RC or lower -->
<update>
<name>My Extension</name>
<description>My Extension release candidate</description>
<element>com_myextension</element>
<type>component</type>
<version>01.03.01-rc</version>
<client>site</client>
<tags>
<tag>rc</tag>
</tags>
<infourl title="My Extension">https://github.com/org/repo/tree/rc/01.03.01</infourl>
<downloads>
<downloadurl type="full" format="zip">https://github.com/org/repo/archive/refs/heads/rc/01.03.01.zip</downloadurl>
</downloads>
<targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
<!-- Beta entry: visible to sites with minimum stability = Beta or lower -->
<update>
<name>My Extension</name>
<description>My Extension beta build</description>
<element>com_myextension</element>
<type>component</type>
<version>01.03.01-beta</version>
<client>site</client>
<tags>
<tag>beta</tag>
</tags>
<infourl title="My Extension">https://github.com/org/repo/tree/beta/01.03.01</infourl>
<downloads>
<downloadurl type="full" format="zip">https://github.com/org/repo/archive/refs/heads/beta/01.03.01.zip</downloadurl>
</downloads>
<targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
<!-- Alpha entry: visible to sites with minimum stability = Alpha or lower -->
<update>
<name>My Extension</name>
<description>My Extension alpha build</description>
<element>com_myextension</element>
<type>component</type>
<version>01.03.01-alpha</version>
<client>site</client>
<tags>
<tag>alpha</tag>
</tags>
<infourl title="My Extension">https://github.com/org/repo/tree/alpha/01.03.01</infourl>
<downloads>
<downloadurl type="full" format="zip">https://github.com/org/repo/archive/refs/heads/alpha/01.03.01.zip</downloadurl>
</downloads>
<targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
<!-- Development entry: visible to sites with minimum stability = Development -->
<update>
<name>My Extension</name>
<description>My Extension development build</description>
<element>com_myextension</element>
<type>component</type>
<version>01.04.00-dev</version>
<client>site</client>
<tags>
<tag>development</tag>
</tags>
<infourl title="My Extension">https://github.com/org/repo/tree/dev/01.04</infourl>
<downloads>
<downloadurl type="full" format="zip">https://github.com/org/repo/archive/refs/heads/dev/01.04.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 |
update-server.yml |
Push to beta/** |
<tag>beta</tag> — adds/updates the beta entry |
update-server.yml |
Push to alpha/** |
<tag>alpha</tag> — adds/updates the alpha entry |
update-server.yml |
Push to 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 only its specific entry (rc, beta, alpha, or dev) and preserves the others.
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 administrator — required 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)
-
On release (
auto-release.yml→ main branch):- Builds ZIP from
src/directory - Uploads ZIP to the
vXXmajor release on GitHub - Computes SHA-256 hash of the ZIP
- Writes/updates the
<tag>stable</tag>entry inupdates.xmlwith version, download URL, and SHA-256 - Preserves any existing rc/dev entries in the file
- Commits updated
updates.xmlto main
- Builds ZIP from
-
On RC push (
update-server.yml→ rc/** branches):- Writes/updates the
<tag>rc</tag>entry inupdates.xml - Download URL points to the branch archive ZIP
- Preserves all other stability entries
- Commits updated
updates.xmlto the rc branch
- Writes/updates the
-
On beta push (
update-server.yml→ beta/** branches):- Writes/updates the
<tag>beta</tag>entry inupdates.xml - Download URL points to the branch archive ZIP
- Preserves all other stability entries
- Commits updated
updates.xmlto the beta branch
- Writes/updates the
-
On alpha push (
update-server.yml→ alpha/** branches):- Writes/updates the
<tag>alpha</tag>entry inupdates.xml - Download URL points to the branch archive ZIP
- Preserves all other stability entries
- Commits updated
updates.xmlto the alpha branch
- Writes/updates the
-
On dev push (
update-server.yml→ dev/** branches):- Writes/updates the
<tag>development</tag>entry inupdates.xml - Download URL points to the branch archive ZIP
- Preserves all other stability entries
- Commits updated
updates.xmlto the dev branch
- Writes/updates the
Dolibarr (update.txt)
- On release (
auto-release.yml→ main): writes real version toupdate.txt - On RC deploy (
deploy-dev.yml→ rc/**): writesXX.YY.ZZ-rctoupdate.txt - On beta deploy (
deploy-dev.yml→ beta/**): writesXX.YY.ZZ-betatoupdate.txt - On alpha deploy (
deploy-dev.yml→ alpha/**): writesXX.YY.ZZ-alphatoupdate.txt - On dev deploy (
deploy-dev.yml→ dev/**): writesdevelopmenttoupdate.txt
RC --> Main Flow
When a release candidate is ready:
rc/XX.YY.ZZbranch is tested with<tag>rc</tag>update entries- RC branch is merged to
mainvia PR - Push to main triggers
auto-release.yml→ GitHub Release +vXXtag updates.xmlon main gets a new/updated<tag>stable</tag>entryversion/XXarchive branch is auto-created
Health Checks
The platform-specific repo_health.yml workflows verify:
- Dolibarr:
update.txtexists in root, module descriptor valid, url_last_version correct - Joomla:
updates.xmlexists 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