Files
MokoCLI/cli/version_read.php
T
jmiller 7728b6b4ac
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 12s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Universal: PR Check / Secret Scan (pull_request) Successful in 10s
Platform: mokocli CI / Gate 1: Code Quality (pull_request) Failing after 1m3s
Platform: mokocli CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: mokocli CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: mokocli CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: mokocli CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: mokocli CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: mokocli CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: mokocli CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
refactor(rename): Gitea/MokoGitea -> MokoGit across the codebase [#4]
MokoGitea instance rebrand to MokoGit. Content sweep over 265 files (ordered to avoid
moko-prefix doubling) plus path renames:
- .mokogitea/ -> .mokogit/ (repo + all mcp/servers/*)
- templates/mokogitea/ -> templates/mokogit/
- lib/Enterprise/MokoGiteaAdapter.php -> MokoGitAdapter.php (class MokoGitAdapter)
- mcp/servers/mokogitea_{skill,api} -> mokogit_{skill,api}; skills/mokogitea -> skills/mokogit
- automation/migrate_to_gitea.php -> migrate_to_mokogit.php
- env/secret names GITEA_* -> MOKOGIT_*

Note: ~/.claude/.mcp.json server flipped to @mokoconsulting/mcp-mokogit (publish pending).
2026-07-16 16:49:12 -05:00

140 lines
5.4 KiB
PHP

#!/usr/bin/env php
<?php
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: mokocli.CLI
* INGROUP: mokocli
* REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
* PATH: /cli/version_read.php
* BRIEF: Read version — manifest.xml is canonical, falls back to README.md and Joomla XML
*/
declare(strict_types=1);
require_once __DIR__ . '/../lib/Enterprise/CliFramework.php';
use MokoCli\{CliFramework, SourceResolver};
class VersionReadCli extends CliFramework
{
protected function configure(): void
{
$this->setDescription('Read version — manifest.xml is canonical, falls back to README.md and Joomla XML');
$this->addArgument('--path', 'Repository root path', '.');
}
protected function run(): int
{
$path = $this->getArgument('--path');
$root = realpath($path) ?: $path;
// The retired .mokogit/manifest.xml is no longer a version source; README.md is now
// canonical (version_prefix, when needed, comes from the MokoGit metadata API, not a
// committed manifest). Default to an empty prefix — non-prefixed repos parse normally.
$versionPrefix = '';
// -- 1. README.md (canonical) --
$readmeVersion = null;
$readme = "{$root}/README.md";
if (file_exists($readme)) {
$content = file_get_contents($readme);
if (!empty($versionPrefix)) {
// Prefix-aware: search for prefix followed by version
$prefixPattern = preg_quote($versionPrefix, '/');
if (preg_match('/' . $prefixPattern . '(\d{2}\.\d{2}\.\d{2})/m', $content, $m)) {
$readmeVersion = $m[1];
}
}
if ($readmeVersion === null && preg_match('/VERSION:\s*(\d{2}\.\d{2}\.\d{2})/m', $content, $m)) {
$readmeVersion = $m[1];
}
}
// -- 3. Fallback: Joomla manifest XML --
$manifestVersion = null;
$manifestFiles = array_merge(
SourceResolver::globSource($root, 'pkg_*.xml'),
SourceResolver::globSource($root, '*.xml'),
SourceResolver::globSource($root, 'packages/*/*.xml'),
glob("{$root}/*.xml") ?: []
);
foreach ($manifestFiles as $xmlFile) {
$xmlContent = file_get_contents($xmlFile);
if (strpos($xmlContent, '<extension') === false && strpos($xmlContent, '<version>') === false) {
continue;
}
if (!empty($versionPrefix)) {
// Prefix-aware: look for <version>prefix + XX.YY.ZZ</version>
$prefixPattern = preg_quote($versionPrefix, '#');
if (preg_match('#<version>' . $prefixPattern . '(\d{2}\.\d{2}\.\d{2})</version>#', $xmlContent, $xm)) {
$candidate = $xm[1];
$currentBase = $manifestVersion ? preg_replace('/(-(?:dev|alpha|beta|rc))+$/', '', $manifestVersion) : null;
if ($currentBase === null || version_compare($candidate, $currentBase, '>')) {
$manifestVersion = $candidate;
}
continue;
}
}
if (preg_match('#<version>(\d{2}\.\d{2}\.\d{2}(?:(?:-(?:dev|alpha|beta|rc))+)?)</version>#', $xmlContent, $xm)) {
$candidate = $xm[1];
$candidateBase = preg_replace('/(-(?:dev|alpha|beta|rc))+$/', '', $candidate);
$currentBase = $manifestVersion ? preg_replace('/(-(?:dev|alpha|beta|rc))+$/', '', $manifestVersion) : null;
if ($currentBase === null || version_compare($candidateBase, $currentBase, '>')) {
$manifestVersion = $candidate;
}
}
}
// -- 4. Fallback: package.json (Node.js / MCP) --
$packageJsonVersion = null;
$packageJsonFile = "{$root}/package.json";
if (file_exists($packageJsonFile)) {
$pkgData = json_decode(file_get_contents($packageJsonFile), true);
if (isset($pkgData['version']) && preg_match('/^\d{2}\.\d{2}\.\d{2}$/', $pkgData['version'])) {
$packageJsonVersion = $pkgData['version'];
}
}
// -- 5. Fallback: pyproject.toml (Python) --
$pyprojectVersion = null;
$pyprojectFile = "{$root}/pyproject.toml";
if (file_exists($pyprojectFile)) {
$pyContent = file_get_contents($pyprojectFile);
if (preg_match('/^version\s*=\s*"(\d{2}\.\d{2}\.\d{2})"/m', $pyContent, $pm)) {
$pyprojectVersion = $pm[1];
}
}
// -- Output the higher version --
$candidates = array_filter([
$readmeVersion,
$manifestVersion,
$packageJsonVersion,
$pyprojectVersion,
]);
$version = null;
foreach ($candidates as $candidate) {
if ($version === null || version_compare($candidate, $version, '>')) {
$version = $candidate;
}
}
if ($version === null) {
$this->log('ERROR', 'No version found in manifest.xml, README.md, Joomla XML, package.json, or pyproject.toml');
return 1;
}
echo $version . "\n";
return 0;
}
}
$app = new VersionReadCli();
exit($app->execute());