Public Access
Merge pull request 'chore: PHPDoc Priority 1 + Coding Standards wiki' (#138) from dev into main
Generic: Repo Health / Site Health (push) Has been cancelled
Generic: Repo Health / Access control (push) Has been cancelled
Universal: Cascade Main → Dev / Cascade main → branches (push) Has been cancelled
Platform: moko-platform CI / Gate 1: Code Quality (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Site Health (push) Has been cancelled
Generic: Repo Health / Access control (push) Has been cancelled
Universal: Cascade Main → Dev / Cascade main → branches (push) Has been cancelled
Platform: moko-platform CI / Gate 1: Code Quality (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
This commit was merged in pull request #138.
This commit is contained in:
@@ -18,6 +18,12 @@ Version format: `XX.YY.ZZ` (zero-padded semver).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `updates_xml_build.php`: cascade entries down to lower channels — stable now writes all 5 entries instead of wiping them
|
||||||
|
- `updates_xml_build.php`: separate Joomla stability tags (`dev`, `rc`) from Gitea release tags (`development`, `release-candidate`) — download URLs now point to correct release assets
|
||||||
|
- `updates_xml_build.php`: only emit `<client>site</client>` for templates and modules, not packages or components
|
||||||
|
- `updates_xml_build.php`: preservation logic matches Joomla tag names when deciding which existing entries to keep
|
||||||
|
|
||||||
## [08.00.00] - 2026-05-26
|
## [08.00.00] - 2026-05-26
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
+47
-42
@@ -194,8 +194,7 @@ $stabilitySuffixMap = [
|
|||||||
'development' => '-dev',
|
'development' => '-dev',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Joomla's stabilityTagToInteger() maps these to STABILITY_* constants.
|
// Joomla <tags><tag> values — maps to Joomla's stabilityTagToInteger()
|
||||||
// MUST use 'dev' not 'development' — STABILITY_DEVELOPMENT does not exist.
|
|
||||||
$stabilityTagMap = [
|
$stabilityTagMap = [
|
||||||
'stable' => 'stable',
|
'stable' => 'stable',
|
||||||
'rc' => 'rc',
|
'rc' => 'rc',
|
||||||
@@ -204,23 +203,26 @@ $stabilityTagMap = [
|
|||||||
'development' => 'dev',
|
'development' => 'dev',
|
||||||
];
|
];
|
||||||
|
|
||||||
// -- Build update entries -----------------------------------------------------
|
// Gitea release tag names (used in download/info URLs)
|
||||||
$releaseTag = $stabilityTagMap[$stability] ?? $stability;
|
$releaseTagMap = [
|
||||||
|
'stable' => 'stable',
|
||||||
|
'rc' => 'release-candidate',
|
||||||
|
'beta' => 'beta',
|
||||||
|
'alpha' => 'alpha',
|
||||||
|
'development' => 'development',
|
||||||
|
];
|
||||||
|
|
||||||
|
// -- Build update entries -----------------------------------------------------
|
||||||
// For the primary entry: apply suffix if not stable
|
// For the primary entry: apply suffix if not stable
|
||||||
$primarySuffix = $stabilitySuffixMap[$stability] ?? '';
|
$primarySuffix = $stabilitySuffixMap[$stability] ?? '';
|
||||||
$primaryVersion = $version . $primarySuffix;
|
$primaryVersion = $version . $primarySuffix;
|
||||||
|
|
||||||
$downloadUrl = "{$giteaUrl}/{$org}/{$repo}/releases/download/{$releaseTag}/{$typePrefix}{$extElement}-{$primaryVersion}.zip";
|
// Build client tag — only needed for templates and modules (site vs admin).
|
||||||
$infoUrl = "{$giteaUrl}/{$org}/{$repo}/releases/tag/{$releaseTag}";
|
// Packages and components don't use client; plugins use folder instead.
|
||||||
|
|
||||||
// Build client tag — Joomla defaults to client_id=1 (administrator) when missing.
|
|
||||||
// Packages install with client_id=0 (site), so we MUST include <client>site</client>
|
|
||||||
// for all types to prevent a mismatch that causes extension_id=0 in #__updates.
|
|
||||||
$clientTag = '';
|
$clientTag = '';
|
||||||
if (!empty($extClient)) {
|
if (!empty($extClient)) {
|
||||||
$clientTag = " <client>{$extClient}</client>";
|
$clientTag = " <client>{$extClient}</client>";
|
||||||
} else {
|
} elseif (in_array($extType, ['template', 'module'])) {
|
||||||
$clientTag = ' <client>site</client>';
|
$clientTag = ' <client>site</client>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,41 +288,44 @@ function buildEntry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -- Determine which channels to write ----------------------------------------
|
// -- Determine which channels to write ----------------------------------------
|
||||||
// Stable cascades to all channels; pre-releases only write their level and below
|
// Stable cascades to all channels; pre-releases cascade down to lower channels.
|
||||||
// Each channel gets its own suffixed version:
|
// Each channel entry represents "latest release available at this stability or higher".
|
||||||
// development -> 04.01.00-dev
|
// When stable releases, ALL channels point to stable (it's the newest for everyone).
|
||||||
// alpha -> 04.01.00-alpha
|
// When RC releases, rc/beta/alpha/dev point to RC; stable is preserved.
|
||||||
// beta -> 04.01.00-beta
|
// When dev releases, only dev is updated; everything else is preserved.
|
||||||
// rc -> 04.01.00-rc
|
|
||||||
// stable -> 04.01.00
|
|
||||||
$allChannels = ['development', 'alpha', 'beta', 'rc', 'stable'];
|
$allChannels = ['development', 'alpha', 'beta', 'rc', 'stable'];
|
||||||
$stabilityIndex = array_search($stability === 'development' ? 'development' : $stability, $allChannels);
|
$stabilityIndex = array_search($stability === 'development' ? 'development' : $stability, $allChannels);
|
||||||
if ($stabilityIndex === false) $stabilityIndex = 4; // default to stable
|
if ($stabilityIndex === false) $stabilityIndex = 4; // default to stable
|
||||||
|
|
||||||
// Write only the current channel entry (not cascade)
|
// Write entries for the current channel AND all lower channels (cascade down)
|
||||||
// Each channel release only creates its own entry; preserved entries handle other channels
|
// All cascaded entries point to the CURRENT release (the highest stability being built)
|
||||||
$entries = [];
|
$entries = [];
|
||||||
$channelName = $allChannels[$stabilityIndex];
|
$giteaTag = $releaseTagMap[$stability] ?? $stability;
|
||||||
$channelSuffix = $stabilitySuffixMap[$channelName] ?? '';
|
$channelVersion = $version . ($stabilitySuffixMap[$stability] ?? '');
|
||||||
$channelVersion = $version . $channelSuffix;
|
$channelDownloadUrl = "{$giteaUrl}/{$org}/{$repo}/releases/download/{$giteaTag}/{$typePrefix}{$extElement}-{$channelVersion}.zip";
|
||||||
$channelTag = $stabilityTagMap[$channelName] ?? $channelName;
|
$channelInfoUrl = "{$giteaUrl}/{$org}/{$repo}/releases/tag/{$giteaTag}";
|
||||||
$channelDownloadUrl = "{$giteaUrl}/{$org}/{$repo}/releases/download/{$channelTag}/{$typePrefix}{$extElement}-{$channelVersion}.zip";
|
|
||||||
$channelInfoUrl = "{$giteaUrl}/{$org}/{$repo}/releases/tag/{$channelTag}";
|
|
||||||
|
|
||||||
$entries[] = buildEntry(
|
for ($i = 0; $i <= $stabilityIndex; $i++) {
|
||||||
$channelName,
|
$channelName = $allChannels[$i];
|
||||||
$channelVersion,
|
$joomlaTag = $stabilityTagMap[$channelName] ?? $channelName;
|
||||||
$channelDownloadUrl,
|
// Only attach SHA to the primary channel entry
|
||||||
$extName,
|
$entrySha = ($i === $stabilityIndex) ? $shaTag : '';
|
||||||
$extElement,
|
|
||||||
$extType,
|
$entries[] = buildEntry(
|
||||||
$clientTag,
|
$joomlaTag,
|
||||||
$folderTag,
|
$channelVersion,
|
||||||
$channelInfoUrl,
|
$channelDownloadUrl,
|
||||||
$targetPlatform,
|
$extName,
|
||||||
$phpTag,
|
$extElement,
|
||||||
$shaTag
|
$extType,
|
||||||
);
|
$clientTag,
|
||||||
|
$folderTag,
|
||||||
|
$channelInfoUrl,
|
||||||
|
$targetPlatform,
|
||||||
|
$phpTag,
|
||||||
|
$entrySha
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// -- Preserve existing entries for channels not being updated -----------------
|
// -- Preserve existing entries for channels not being updated -----------------
|
||||||
$dest = $outputFile ?? "{$root}/updates.xml";
|
$dest = $outputFile ?? "{$root}/updates.xml";
|
||||||
@@ -329,10 +334,10 @@ $preservedEntries = [];
|
|||||||
if (file_exists($dest)) {
|
if (file_exists($dest)) {
|
||||||
$existingXml = @simplexml_load_file($dest);
|
$existingXml = @simplexml_load_file($dest);
|
||||||
if ($existingXml) {
|
if ($existingXml) {
|
||||||
// Channels we're writing — don't preserve these
|
// Joomla tags we're writing — don't preserve these
|
||||||
$writtenChannels = [];
|
$writtenChannels = [];
|
||||||
for ($i = 0; $i <= $stabilityIndex; $i++) {
|
for ($i = 0; $i <= $stabilityIndex; $i++) {
|
||||||
$writtenChannels[] = $allChannels[$i];
|
$writtenChannels[] = $stabilityTagMap[$allChannels[$i]] ?? $allChannels[$i];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($existingXml->update as $existingUpdate) {
|
foreach ($existingXml->update as $existingUpdate) {
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ class CircuitBreakerOpen extends RuntimeException
|
|||||||
* );
|
* );
|
||||||
* $response = $client->get('/repos/owner/repo');
|
* $response = $client->get('/repos/owner/repo');
|
||||||
* ```
|
* ```
|
||||||
|
*
|
||||||
|
* @since 04.00.00
|
||||||
*/
|
*/
|
||||||
class ApiClient
|
class ApiClient
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -716,6 +716,9 @@ class ValidationCLI extends CLIApp
|
|||||||
* Lifecycle: configure() -> parseArguments() -> printBanner() -> initialize() -> run()
|
* Lifecycle: configure() -> parseArguments() -> printBanner() -> initialize() -> run()
|
||||||
*
|
*
|
||||||
* All new scripts must extend CliFramework and implement configure() + run().
|
* All new scripts must extend CliFramework and implement configure() + run().
|
||||||
|
*
|
||||||
|
* @since 04.00.15
|
||||||
|
* @see CLIApp Legacy base class (deprecated)
|
||||||
*/
|
*/
|
||||||
abstract class CliFramework
|
abstract class CliFramework
|
||||||
{
|
{
|
||||||
@@ -932,6 +935,11 @@ abstract class CliFramework
|
|||||||
// Argument parsing (internal)
|
// Argument parsing (internal)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse CLI arguments from $_SERVER['argv'] into registered argument definitions.
|
||||||
|
*
|
||||||
|
* @since 04.00.15
|
||||||
|
*/
|
||||||
private function parseArguments(): void
|
private function parseArguments(): void
|
||||||
{
|
{
|
||||||
$argv = array_slice($_SERVER['argv'] ?? [], 1);
|
$argv = array_slice($_SERVER['argv'] ?? [], 1);
|
||||||
@@ -970,6 +978,11 @@ abstract class CliFramework
|
|||||||
// Help screen
|
// Help screen
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print auto-generated help screen from registered arguments.
|
||||||
|
*
|
||||||
|
* @since 04.00.15
|
||||||
|
*/
|
||||||
protected function printHelp(): void
|
protected function printHelp(): void
|
||||||
{
|
{
|
||||||
$w = $this->termWidth();
|
$w = $this->termWidth();
|
||||||
|
|||||||
@@ -32,12 +32,17 @@ use RuntimeException;
|
|||||||
* - Workflow dir: .github/workflows
|
* - Workflow dir: .github/workflows
|
||||||
*
|
*
|
||||||
* @package MokoStandards\Enterprise
|
* @package MokoStandards\Enterprise
|
||||||
* @version 04.06.10
|
* @since 04.06.10
|
||||||
|
* @see GitPlatformAdapter
|
||||||
*/
|
*/
|
||||||
class GitHubAdapter implements GitPlatformAdapter
|
class GitHubAdapter implements GitPlatformAdapter
|
||||||
{
|
{
|
||||||
|
/** @var ApiClient HTTP client for GitHub API calls. */
|
||||||
private ApiClient $apiClient;
|
private ApiClient $apiClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ApiClient $apiClient Configured API client for api.github.com
|
||||||
|
*/
|
||||||
public function __construct(ApiClient $apiClient)
|
public function __construct(ApiClient $apiClient)
|
||||||
{
|
{
|
||||||
$this->apiClient = $apiClient;
|
$this->apiClient = $apiClient;
|
||||||
|
|||||||
@@ -34,13 +34,21 @@ use RuntimeException;
|
|||||||
* - Workflow dir: .mokogitea/workflows
|
* - Workflow dir: .mokogitea/workflows
|
||||||
*
|
*
|
||||||
* @package MokoStandards\Enterprise
|
* @package MokoStandards\Enterprise
|
||||||
* @version 04.06.10
|
* @since 04.06.10
|
||||||
|
* @see GitPlatformAdapter
|
||||||
*/
|
*/
|
||||||
class MokoGiteaAdapter implements GitPlatformAdapter
|
class MokoGiteaAdapter implements GitPlatformAdapter
|
||||||
{
|
{
|
||||||
|
/** @var ApiClient HTTP client for Gitea API calls. */
|
||||||
private ApiClient $apiClient;
|
private ApiClient $apiClient;
|
||||||
|
|
||||||
|
/** @var string Base URL for Gitea API (e.g. https://git.mokoconsulting.tech/api/v1). */
|
||||||
private string $baseUrl;
|
private string $baseUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ApiClient $apiClient Configured API client
|
||||||
|
* @param string $baseUrl Gitea API base URL
|
||||||
|
*/
|
||||||
public function __construct(ApiClient $apiClient, string $baseUrl = 'https://git.mokoconsulting.tech/api/v1')
|
public function __construct(ApiClient $apiClient, string $baseUrl = 'https://git.mokoconsulting.tech/api/v1')
|
||||||
{
|
{
|
||||||
$this->apiClient = $apiClient;
|
$this->apiClient = $apiClient;
|
||||||
|
|||||||
@@ -415,15 +415,9 @@ parameters:
|
|||||||
path: cli/theme_lint.php
|
path: cli/theme_lint.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Offset ''alpha''\|''beta''\|''development''\|''rc''\|''stable'' on array\{stable\: '''', rc\: ''\-rc'', beta\: ''\-beta'', alpha\: ''\-alpha'', development\: ''\-dev''\} on left side of \?\? always exists and is not nullable\.$#'
|
message: '#^Offset ''alpha''\|''beta''\|''development''\|''rc''\|''stable'' on array\{stable\: ''stable'', rc\: ''rc'', beta\: ''beta'', alpha\: ''alpha'', development\: ''dev''\} on left side of \?\? always exists and is not nullable\.$#'
|
||||||
identifier: nullCoalesce.offset
|
identifier: nullCoalesce.offset
|
||||||
count: 1
|
count: 2
|
||||||
path: cli/updates_xml_build.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: '#^Offset ''alpha''\|''beta''\|''development''\|''rc''\|''stable'' on array\{stable\: ''stable'', rc\: ''rc'', beta\: ''beta'', alpha\: ''alpha'', development\: ''development''\} on left side of \?\? always exists and is not nullable\.$#'
|
|
||||||
identifier: nullCoalesce.offset
|
|
||||||
count: 1
|
|
||||||
path: cli/updates_xml_build.php
|
path: cli/updates_xml_build.php
|
||||||
|
|
||||||
-
|
-
|
||||||
|
|||||||
Reference in New Issue
Block a user