From d5fa609f1565ed84f1e89b3cc28ebcae58f73308 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 20 Jun 2026 21:35:47 -0500 Subject: [PATCH] fix(version-bump): prevent dev from falling behind stable (#283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit version_bump.php now checks two additional sources before bumping: 1. --min-version argument: workflow can pass the current stable version so the bump is guaranteed to be above it 2. Auto-detect from git: scans commit messages and remote branch manifests (origin/main, origin/rc) to find the highest version released on any channel. If a higher version exists on another branch, uses that as the base instead of the local manifest. This prevents the scenario where dev builds at 02.44.xx while stable is at 02.45.00 — the bump will now use 02.45.00 as the base and produce 02.45.01-dev or 02.46.00-dev depending on bump type. --- cli/version_bump.php | 71 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/cli/version_bump.php b/cli/version_bump.php index aa2d51a..9dec58b 100644 --- a/cli/version_bump.php +++ b/cli/version_bump.php @@ -27,6 +27,7 @@ class VersionBumpCli extends CliFramework $this->addArgument('--path', 'Repository root', '.'); $this->addArgument('--minor', 'Bump minor version', false); $this->addArgument('--major', 'Bump major version', false); + $this->addArgument('--min-version', 'Minimum base version (ensures bump is above this)', ''); } protected function run(): int @@ -116,6 +117,28 @@ class VersionBumpCli extends CliFramework $baseVersion = $v; } } + + // Check --min-version: ensures dev never falls behind stable + $minVersion = $this->getArgument('--min-version'); + if (!empty($minVersion)) { + $minVersion = preg_replace('/-(?:dev|alpha|beta|rc)$/', '', $minVersion); + if (preg_match('/^\d{2}\.\d{2}\.\d{2}$/', $minVersion)) { + if ($baseVersion === null || version_compare($minVersion, $baseVersion, '>')) { + $this->log('INFO', "Using --min-version {$minVersion} (higher than manifest {$baseVersion})"); + $baseVersion = $minVersion; + } + } + } + + // Auto-detect: scan git tags for higher versions from other channels + if ($baseVersion !== null) { + $gitTagVersion = $this->getHighestGitTagVersion($root); + if ($gitTagVersion !== null && version_compare($gitTagVersion, $baseVersion, '>')) { + $this->log('INFO', "Git tag version {$gitTagVersion} is higher than manifest {$baseVersion} — using as base"); + $baseVersion = $gitTagVersion; + } + } + if ($baseVersion === null) { $this->log('ERROR', "No version found in manifest.xml, README.md, or Joomla XML"); return 1; @@ -343,6 +366,54 @@ class VersionBumpCli extends CliFramework echo "{$old} -> {$newFull}\n"; return 0; } + + /** + * Scan git release tags for the highest version across all channels. + * + * Checks release names like "MokoSuiteClient (VERSION: 02.45.00)" in + * git tags (stable, release-candidate, development, etc.) to find the + * highest version that has been released on any channel. + */ + private function getHighestGitTagVersion(string $root): ?string + { + $highest = null; + + // Method 1: Parse version from git tag annotations / release commit messages + $output = []; + exec("cd " . escapeshellarg($root) . " && git log --all --oneline --grep='chore(version)' --grep='chore(release)' --format='%s' -20 2>/dev/null", $output); + + foreach ($output as $line) { + if (preg_match('/(\d{2}\.\d{2}\.\d{2})/', $line, $m)) { + $v = preg_replace('/-(?:dev|alpha|beta|rc)$/', '', $m[1]); + if ($highest === null || version_compare($v, $highest, '>')) { + $highest = $v; + } + } + } + + // Method 2: Check version in remote branches' manifest files + $branches = ['origin/main', 'origin/rc', 'origin/dev']; + $manifestPaths = ['source/pkg_*.xml', 'pkg_*.xml']; + + foreach ($branches as $branch) { + foreach ($manifestPaths as $pattern) { + $files = []; + exec("cd " . escapeshellarg($root) . " && git ls-tree --name-only {$branch} -- '{$pattern}' 2>/dev/null", $files); + + foreach ($files as $file) { + $content = shell_exec("cd " . escapeshellarg($root) . " && git show {$branch}:{$file} 2>/dev/null"); + if ($content && preg_match('#(\d{2}\.\d{2}\.\d{2})(?:-(?:dev|alpha|beta|rc))?#', $content, $m)) { + $v = $m[1]; + if ($highest === null || version_compare($v, $highest, '>')) { + $highest = $v; + } + } + } + } + } + + return $highest; + } } $app = new VersionBumpCli();