419 lines
20 KiB
Markdown
419 lines
20 KiB
Markdown
<!--
|
|
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
|
|
SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
# FILE INFORMATION
|
|
DEFGROUP: MokoStandards.Documentation
|
|
INGROUP: MokoStandards.Workflows
|
|
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-API
|
|
PATH: /docs/workflows/update-server.md
|
|
VERSION: 04.06.00
|
|
BRIEF: How update files (update.txt and updates.xml) are generated per platform
|
|
-->
|
|
|
|
# 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](https://docs.joomla.org/Deploying_an_Update_Server) |
|
|
|
|
## 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](https://git.mokoconsulting.tech/MokoConsulting/MokoStandards/src/branch/main/docs/release-management/cascade-channels.md).
|
|
|
|
### 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
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<updates>
|
|
<!-- Stable: dual download (Gitea + GitHub), visible to all sites -->
|
|
<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>
|
|
|
|
<!-- RC: Gitea only, 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>
|
|
<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>
|
|
|
|
<!-- Beta: Gitea only, 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>
|
|
<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>
|
|
|
|
<!-- Alpha: Gitea only, 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>
|
|
<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>
|
|
|
|
<!-- 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>
|
|
<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 `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:
|
|
|
|
```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}/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.yml` → `dev` 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
|
|
|
|
```xml
|
|
<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.
|