Public Access
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
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).
305 lines
11 KiB
PHP
305 lines
11 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_auto_bump.php
|
|
* VERSION: 09.38.05
|
|
* BRIEF: Auto patch-bump, set stability suffix, and commit — single CLI replacing inline workflow bash
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../lib/Enterprise/CliFramework.php';
|
|
|
|
use MokoCli\CliFramework;
|
|
|
|
class VersionAutoBumpCli extends CliFramework
|
|
{
|
|
protected function configure(): void
|
|
{
|
|
$this->setDescription('Auto patch-bump, set stability suffix, and commit');
|
|
$this->addArgument('--path', 'Repository root path', '.');
|
|
$this->addArgument('--branch', 'Git branch name', '');
|
|
$this->addArgument('--token', 'API token for push', '');
|
|
$this->addArgument('--repo-url', 'Repository URL for git remote', '');
|
|
$this->addArgument('--watch-path', 'Path to watch for changes', '');
|
|
}
|
|
|
|
protected function run(): int
|
|
{
|
|
$path = $this->getArgument('--path');
|
|
$branch = $this->getArgument('--branch');
|
|
$token = $this->getArgument('--token');
|
|
$repoUrl = $this->getArgument('--repo-url');
|
|
$watchPath = $this->getArgument('--watch-path');
|
|
|
|
// Auto-detect branch from git or CI env
|
|
if ($branch === '') {
|
|
$branch = getenv('GITHUB_REF_NAME') ?: trim((string) @shell_exec('git rev-parse --abbrev-ref HEAD 2>/dev/null'));
|
|
if (empty($branch) || $branch === 'HEAD') {
|
|
$this->log('ERROR', 'Cannot detect branch — pass --branch');
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Map branch to stability suffix
|
|
$stabilityMap = [
|
|
'dev' => 'dev',
|
|
'alpha' => 'alpha',
|
|
'beta' => 'beta',
|
|
'rc' => 'rc',
|
|
];
|
|
|
|
if (array_key_exists($branch, $stabilityMap)) {
|
|
$stability = $stabilityMap[$branch];
|
|
} elseif (str_starts_with($branch, 'feature/') || str_starts_with($branch, 'patch/')) {
|
|
$stability = 'dev';
|
|
} else {
|
|
$stability = 'dev';
|
|
}
|
|
|
|
$cli = __DIR__;
|
|
$php = '"' . PHP_BINARY . '"';
|
|
|
|
// Watch-path was previously read from .mokogit/manifest.xml <build><entry-point>.
|
|
// That manifest is retired; when --watch-path is not supplied we simply skip the
|
|
// change-gate and always bump (the prior no-manifest behavior).
|
|
|
|
// Check if code files actually changed (skip bump for docs/config-only changes)
|
|
$shouldBump = true;
|
|
if (!empty($watchPath)) {
|
|
$root = realpath($path) ?: $path;
|
|
$cdCmd = PHP_OS_FAMILY === 'Windows' ? "cd /d " : "cd ";
|
|
$diffOutput = trim((string) @shell_exec(
|
|
$cdCmd . escapeshellarg($root)
|
|
. " && git diff --name-only HEAD~1 HEAD -- "
|
|
. escapeshellarg($watchPath) . " 2>/dev/null"
|
|
));
|
|
if (empty($diffOutput)) {
|
|
echo "No changes in {$watchPath} — skipping version bump\n";
|
|
$shouldBump = false;
|
|
} else {
|
|
echo "Changes detected in {$watchPath}:\n{$diffOutput}\n";
|
|
}
|
|
}
|
|
|
|
if (!$shouldBump) {
|
|
echo "No code changes — nothing to do\n";
|
|
return 0;
|
|
}
|
|
|
|
// Step 1: Patch bump
|
|
$bumpOutput = [];
|
|
exec("{$php} {$cli}/version_bump.php --path " . escapeshellarg($path) . " 2>&1", $bumpOutput, $bumpRc);
|
|
foreach ($bumpOutput as $line) {
|
|
echo "{$line}\n";
|
|
}
|
|
|
|
// Step 2: Read version (--quiet suppresses banner so only the version is output)
|
|
$versionOutput = [];
|
|
exec("{$php} {$cli}/version_read.php --path " . escapeshellarg($path) . " --quiet 2>&1", $versionOutput, $versionRc);
|
|
// Take the last non-empty line — the version is always the final output
|
|
$version = '';
|
|
foreach (array_reverse($versionOutput) as $line) {
|
|
$line = trim($line);
|
|
if (preg_match('/^\d{2}\.\d{2}\.\d{2}/', $line)) {
|
|
$version = $line;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (empty($version)) {
|
|
echo "No version found — skipping\n";
|
|
return 0;
|
|
}
|
|
|
|
echo "Version: {$version} | Branch: {$branch} | Stability: {$stability}\n";
|
|
|
|
// Step 3: Set platform version with stability suffix
|
|
$setPlatOutput = [];
|
|
exec("{$php} {$cli}/version_set_platform.php --path " . escapeshellarg($path)
|
|
. " --version " . escapeshellarg($version)
|
|
. " --branch " . escapeshellarg($branch)
|
|
. " --stability " . escapeshellarg($stability) . " 2>&1", $setPlatOutput);
|
|
foreach ($setPlatOutput as $line) {
|
|
echo "{$line}\n";
|
|
}
|
|
|
|
// Step 4: Version consistency check and fix
|
|
exec("{$php} {$cli}/version_check.php --path " . escapeshellarg($path) . " --fix 2>&1", $checkOutput);
|
|
|
|
// Step 4b (#351/#354): keep Joomla #__schemas in lockstep with the stamped manifest.
|
|
// Must run AFTER version_set_platform/version_check have stamped each manifest <version>,
|
|
// and BEFORE the git commit below so markers are staged in the same bump commit.
|
|
$markerRoot = realpath($path) ?: $path;
|
|
foreach ($this->writeSchemaMarkers($markerRoot) as $marker) {
|
|
echo "Schema marker: {$marker}\n";
|
|
}
|
|
|
|
// Re-read version (now includes suffix from version_set_platform)
|
|
$suffixMap = [
|
|
'dev' => '-dev',
|
|
'alpha' => '-alpha',
|
|
'beta' => '-beta',
|
|
'rc' => '-rc',
|
|
];
|
|
$displayVersion = preg_replace('/(-(dev|alpha|beta|rc))+$/', '', $version) . ($suffixMap[$stability] ?? '');
|
|
|
|
if ($this->dryRun) {
|
|
echo "[DRY-RUN] Would commit and push {$displayVersion} to {$branch}\n";
|
|
return 0;
|
|
}
|
|
|
|
// Step 5: Git commit and push
|
|
$root = realpath($path) ?: $path;
|
|
|
|
// Check if anything changed
|
|
$cdPrefix = PHP_OS_FAMILY === 'Windows' ? "cd /d " : "cd ";
|
|
$diffStatus = trim((string) @shell_exec(
|
|
$cdPrefix . escapeshellarg($root)
|
|
. " && git diff --quiet && git diff --cached --quiet"
|
|
. " 2>&1 && echo clean || echo dirty"
|
|
));
|
|
if ($diffStatus === 'clean') {
|
|
echo "No version changes to commit\n";
|
|
return 0;
|
|
}
|
|
|
|
// Configure git
|
|
$cd = PHP_OS_FAMILY === 'Windows' ? "cd /d " : "cd ";
|
|
$cdRoot = $cd . escapeshellarg($root);
|
|
@shell_exec(
|
|
$cdRoot . " && git config --local user.email"
|
|
. " \"mokogit-actions[bot]@mokoconsulting.tech\""
|
|
);
|
|
@shell_exec(
|
|
$cdRoot . " && git config --local user.name"
|
|
. " \"mokogit-actions[bot]\""
|
|
);
|
|
|
|
if (!empty($repoUrl)) {
|
|
@shell_exec(
|
|
$cdRoot . " && git remote set-url origin "
|
|
. escapeshellarg($repoUrl)
|
|
);
|
|
}
|
|
|
|
@shell_exec($cdRoot . " && git add -A");
|
|
$commitMsg = $shouldBump
|
|
? "chore(version): auto-bump patch {$displayVersion} [skip ci]"
|
|
: "chore(version): set {$stability} suffix {$displayVersion} [skip ci]";
|
|
@shell_exec(
|
|
$cdRoot . " && git commit -m " . escapeshellarg($commitMsg)
|
|
. " --author=\"mokogit-actions[bot]"
|
|
. " <mokogit-actions[bot]@mokoconsulting.tech>\""
|
|
);
|
|
|
|
$pushResult = @shell_exec(
|
|
$cdRoot . " && git push origin "
|
|
. escapeshellarg($branch) . " 2>&1"
|
|
);
|
|
echo $pushResult ?? '';
|
|
|
|
echo "Bumped to {$displayVersion}\n";
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Issues #351/#354 — keep Joomla #__schemas in lockstep with the manifest version.
|
|
*
|
|
* Joomla advances #__schemas only to the highest schema-update file whose version is
|
|
* <= the manifest <version>. When auto-bump climbs the manifest without adding a matching
|
|
* marker, #__schemas freezes at the last real migration and com_installer perpetually
|
|
* reports the component "a schema version behind". For every Joomla extension manifest that
|
|
* declares <update><schemas><schemapath ...>, write a comment-only no-op marker named
|
|
* exactly <manifest-version>.sql (idempotent). Reading the version back out of the stamped
|
|
* manifest guarantees the filename equals — never exceeds — the manifest version.
|
|
*
|
|
* @param string $root Repository root.
|
|
* @return string[] Marker paths created (each suffixed " (would create)" under --dry-run).
|
|
*/
|
|
private function writeSchemaMarkers(string $root): array
|
|
{
|
|
$created = [];
|
|
|
|
// Joomla manifests may sit at the repo root or under a source/packages tree.
|
|
$manifests = array_unique(array_merge(
|
|
glob("{$root}/*.xml") ?: [],
|
|
glob("{$root}/*/*.xml") ?: [],
|
|
glob("{$root}/*/packages/*/*.xml") ?: []
|
|
));
|
|
|
|
foreach ($manifests as $file) {
|
|
$xml = @simplexml_load_file($file);
|
|
|
|
if ($xml === false) {
|
|
continue;
|
|
}
|
|
|
|
// Only Joomla extension manifests that actually declare a schema update path.
|
|
if (!isset($xml->update->schemas->schemapath)) {
|
|
continue;
|
|
}
|
|
|
|
$version = trim((string) $xml->version);
|
|
|
|
// Guard: only stamp when the manifest carries a well-formed platform version.
|
|
if (!preg_match('/^\d{2}\.\d{2}\.\d{2}((?:-(?:dev|alpha|beta|rc))+)?$/', $version)) {
|
|
continue;
|
|
}
|
|
|
|
// Resolve the admin-relative root: <administration><files folder="admin">.
|
|
$baseDir = dirname($file);
|
|
$adminFolder = isset($xml->administration->files['folder'])
|
|
? trim((string) $xml->administration->files['folder'])
|
|
: '';
|
|
$adminDir = $adminFolder !== '' ? "{$baseDir}/{$adminFolder}" : $baseDir;
|
|
|
|
// One marker per driver-specific schemapath (mysql, postgresql, …).
|
|
foreach ($xml->update->schemas->schemapath as $schemapath) {
|
|
$rel = trim((string) $schemapath);
|
|
|
|
if ($rel === '') {
|
|
continue;
|
|
}
|
|
|
|
$dir = "{$adminDir}/{$rel}";
|
|
$marker = "{$dir}/{$version}.sql";
|
|
|
|
// Idempotent: never overwrite an existing marker (real or prior no-op).
|
|
if (file_exists($marker)) {
|
|
continue;
|
|
}
|
|
|
|
if ($this->dryRun) {
|
|
$created[] = "{$marker} (would create)";
|
|
continue;
|
|
}
|
|
|
|
if (!is_dir($dir) && !@mkdir($dir, 0755, true) && !is_dir($dir)) {
|
|
$this->log('WARNING', "Could not create schemapath dir: {$dir}");
|
|
continue;
|
|
}
|
|
|
|
$body = "/* {$version} — no schema changes (auto version marker) */\n";
|
|
|
|
if (file_put_contents($marker, $body) !== false) {
|
|
$created[] = $marker;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $created;
|
|
}
|
|
}
|
|
|
|
$app = new VersionAutoBumpCli();
|
|
exit($app->execute());
|