# 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 `` 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 `` | Who sees it | Source workflow | |-----------|---------------|-------------|----------------| | Stable | `stable` | All sites (default) | `auto-release.yml` on `main` | | Release Candidate | `rc` | Sites set to RC or lower | `update-server.yml` on `rc/**` push | | Beta | `beta` | Sites set to Beta or lower | `update-server.yml` on `beta/**` push | | Alpha | `alpha` | Sites set to Alpha or lower | `update-server.yml` on `alpha/**` push | | Development | `development` | 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 `development` 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 `` entries from the XML file but only presents entries whose `` matches the site's minimum stability threshold: - **Minimum Stability = Stable** (default): Only sees `stable` 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 My Extension My Extension stable release com_myextension component 01.02.03 stable https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/v01/com_myextension-01.02.03.zip https://github.com/mokoconsulting-tech/MyExtension/releases/download/v01/com_myextension-01.02.03.zip Moko Consulting https://mokoconsulting.tech My Extension My Extension release candidate com_myextension component 01.03.01-rc rc https://git.mokoconsulting.tech/MokoConsulting/MyExtension/src/branch/rc https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/rc/com_myextension-01.03.01-rc.zip Moko Consulting https://mokoconsulting.tech My Extension My Extension beta build com_myextension component 01.03.01-beta beta https://git.mokoconsulting.tech/MokoConsulting/MyExtension/src/branch/beta https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/beta/com_myextension-01.03.01-beta.zip Moko Consulting https://mokoconsulting.tech My Extension My Extension alpha build com_myextension component 01.03.01-alpha alpha https://git.mokoconsulting.tech/MokoConsulting/MyExtension/src/branch/alpha https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/alpha/com_myextension-01.03.01-alpha.zip Moko Consulting https://mokoconsulting.tech My Extension My Extension development build com_myextension component 01.04.00-dev development https://git.mokoconsulting.tech/MokoConsulting/MyExtension/src/branch/dev https://git.mokoconsulting.tech/MokoConsulting/MyExtension/releases/download/development/com_myextension-01.04.00-dev.zip Moko Consulting https://mokoconsulting.tech ``` ### Which Workflow Writes Which Entry | Workflow | Trigger | Entry written | |----------|---------|---------------| | `auto-release.yml` | Push to `main` | `stable` — writes the stable entry with SHA-256 hash of the ZIP | | `update-server.yml` | Push to `rc/**` | `rc` — adds/updates the RC entry (+ cascaded lower channels) | | `update-server.yml` | Push to `beta/**` | `beta` — adds/updates the beta entry (+ cascaded lower channels) | | `update-server.yml` | Push to `alpha/**` | `alpha` — adds/updates the alpha entry (+ cascaded lower channels) | | `update-server.yml` | Push to `dev` or `dev/**` | `development` — 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 | |---------|--------|-------| | `` | `` in manifest | Extension display name | | `` | `` in manifest, or manifest filename | Must match installed extension | | `` | `type` attribute on `` | `component`, `module`, `plugin`, `library`, `package`, `template` | | `` | `client` attribute on `` | `site` or `administrator` — **required for plugins and modules** | | `` | `group` attribute on `` | Plugin group (e.g., `system`, `content`) — **required for plugins** | | `` | README.md VERSION field | Real version on release, `development` on dev | | `` | Workflow determines | `stable` on release, `development` on dev | | `` | `` in manifest | Falls back to Joomla 5.x / 6.x | | `` | `` in manifest | Optional, included if present | | `` | GitHub release/branch URL | Links to release page or branch | | `` | 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 My Extension com_myextension https://git.mokoconsulting.tech/mokoconsulting-tech/{repo}/raw/branch/main/updates.xml https://raw.githubusercontent.com/mokoconsulting-tech/{repo}/main/updates.xml ``` The `` 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 `stable` 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 `rc` 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 `beta` 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 `alpha` 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 `development` 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 `rc` 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 `stable` 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 `` 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 https://git.mokoconsulting.tech/MokoConsulting/RepoName/raw/branch/main/updates.xml https://raw.githubusercontent.com/mokoconsulting-tech/RepoName/main/updates.xml ``` ### 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.