b3d9ee8255
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 36s
Wrap all CLI tools in cli/, automation/, maintenance/, deploy/, and release/ in classes extending CliFramework. Replaces manual $argv parsing with configure()/addArgument(), moves logic into run(): int, and converts fwrite(STDERR,...) to $this->log(). Two CLIApp subclasses (generate_dolibarr_version_txt, generate_joomla_update_xml) converted to extend CliFramework directly. Every script now gets free --help, --verbose, --quiet, --dry-run, --json, --no-color, banners, coloured logging, and progress bars. Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
92 lines
6.7 KiB
PHP
92 lines
6.7 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: moko-platform.CLI
|
|
* INGROUP: moko-platform
|
|
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
|
|
* PATH: /cli/release_validate.php
|
|
* BRIEF: Pre-release validation -- version consistency, required files, manifest checks
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../lib/Enterprise/CliFramework.php';
|
|
|
|
use MokoEnterprise\CliFramework;
|
|
|
|
class ReleaseValidateCli extends CliFramework
|
|
{
|
|
private int $pass = 0;
|
|
private int $fail = 0;
|
|
private int $warn = 0;
|
|
private array $results = [];
|
|
|
|
protected function configure(): void
|
|
{
|
|
$this->setDescription('Pre-release validation -- version consistency, required files, manifest checks');
|
|
$this->addArgument('--path', 'Repository root', '.');
|
|
$this->addArgument('--version', 'Expected version string', null);
|
|
$this->addArgument('--platform', 'joomla|dolibarr|generic', null);
|
|
$this->addArgument('--output-summary', 'Write markdown to $GITHUB_STEP_SUMMARY', false);
|
|
$this->addArgument('--github-output', 'Export counts to $GITHUB_OUTPUT', false);
|
|
}
|
|
|
|
protected function run(): int
|
|
{
|
|
$path = $this->getArgument('--path'); $version = $this->getArgument('--version');
|
|
$platform = $this->getArgument('--platform');
|
|
$outputSummary = (bool) $this->getArgument('--output-summary');
|
|
$githubOutput = (bool) $this->getArgument('--github-output');
|
|
if ($version === null) { $this->log('ERROR', "Usage: release_validate.php --path . --version XX.YY.ZZ [--platform joomla]"); return 1; }
|
|
$root = realpath($path) ?: $path;
|
|
if ($platform === null) {
|
|
$manifestXml = "{$root}/.mokogitea/manifest.xml";
|
|
if (file_exists($manifestXml)) { $mContent = file_get_contents($manifestXml); if (preg_match('/<platform>([^<]+)<\/platform>/', $mContent, $pm)) { $platform = trim($pm[1]); } }
|
|
if (in_array($platform, ['waas-component'], true)) { $platform = 'joomla'; }
|
|
if (in_array($platform, ['crm-module'], true)) { $platform = 'dolibarr'; }
|
|
if ($platform === null) { $platform = 'generic'; }
|
|
}
|
|
$hasSource = is_dir("{$root}/src") || is_dir("{$root}/htdocs");
|
|
$this->addVResult('Source directory', $hasSource ? 'PASS' : 'WARN', $hasSource ? 'src/ or htdocs/ found' : 'No src/ or htdocs/ directory');
|
|
if (!file_exists("{$root}/README.md")) { $this->addVResult('README.md', 'FAIL', 'Not found'); }
|
|
else { $readme = file_get_contents("{$root}/README.md"); $this->addVResult('README.md version', (preg_match('/VERSION:\s*' . preg_quote($version, '/') . '/', $readme) || strpos($readme, $version) !== false) ? 'PASS' : 'FAIL', (preg_match('/VERSION:\s*' . preg_quote($version, '/') . '/', $readme) || strpos($readme, $version) !== false) ? "`{$version}` found" : "`{$version}` not found"); }
|
|
if (!file_exists("{$root}/CHANGELOG.md")) { $this->addVResult('CHANGELOG.md', 'WARN', 'Not found'); }
|
|
else { $cl = file_get_contents("{$root}/CHANGELOG.md"); $this->addVResult('CHANGELOG.md version', preg_match('/^##\s.*' . preg_quote($version, '/') . '/m', $cl) ? 'PASS' : 'WARN', preg_match('/^##\s.*' . preg_quote($version, '/') . '/m', $cl) ? "Section found" : "No section header"); }
|
|
$licenseFound = false; foreach (['LICENSE', 'LICENSE.md', 'LICENSE.txt', 'COPYING'] as $lf) { if (file_exists("{$root}/{$lf}")) { $licenseFound = true; break; } }
|
|
$this->addVResult('LICENSE', $licenseFound ? 'PASS' : 'FAIL', $licenseFound ? 'Found' : 'Not found');
|
|
if ($platform === 'joomla') {
|
|
$manifest = null; foreach (["{$root}/src", $root] as $dir) { if (!is_dir($dir)) continue; foreach (glob("{$dir}/*.xml") as $xmlFile) { $content = file_get_contents($xmlFile); if (strpos($content, '<extension') !== false) { $manifest = $xmlFile; break 2; } } }
|
|
if ($manifest === null) { $this->addVResult('XML manifest', 'FAIL', 'No Joomla manifest found'); }
|
|
else { if (preg_match('/<version>([^<]+)<\/version>/', file_get_contents($manifest), $m)) { $mVer = trim($m[1]); $this->addVResult('Manifest version', $mVer === $version ? 'PASS' : 'FAIL', $mVer === $version ? "`{$mVer}` matches" : "`{$mVer}` != `{$version}`"); } else { $this->addVResult('Manifest version', 'FAIL', 'No <version> tag'); } }
|
|
if (!file_exists("{$root}/updates.xml")) { $this->addVResult('updates.xml', 'WARN', 'Not found'); }
|
|
else { $ux = file_get_contents("{$root}/updates.xml"); $this->addVResult('updates.xml version', preg_match('/<version>' . preg_quote($version, '/') . '<\/version>/', $ux) ? 'PASS' : 'FAIL', preg_match('/<version>' . preg_quote($version, '/') . '<\/version>/', $ux) ? "`{$version}` found" : "`{$version}` not found"); }
|
|
} elseif ($platform === 'dolibarr') {
|
|
$modFile = null; foreach (['src', 'htdocs'] as $sd) { $matches = glob("{$root}/{$sd}/mod*.class.php"); if (!empty($matches)) { $modFile = $matches[0]; break; } }
|
|
if ($modFile === null) { $this->addVResult('Dolibarr mod file', 'FAIL', 'No mod*.class.php found'); }
|
|
else { $mc = file_get_contents($modFile); $this->addVResult('Dolibarr version', preg_match("/\\\$this->version\s*=\s*'" . preg_quote($version, '/') . "'/", $mc) ? 'PASS' : 'FAIL', preg_match("/\\\$this->version\s*=\s*'" . preg_quote($version, '/') . "'/", $mc) ? "`{$version}` matches" : "`{$version}` not found"); }
|
|
}
|
|
if (file_exists("{$root}/composer.json")) { $composer = json_decode(file_get_contents("{$root}/composer.json"), true); if (isset($composer['version'])) { $this->addVResult('composer.json version', $composer['version'] === $version ? 'PASS' : 'WARN', $composer['version'] === $version ? "`{$version}` matches" : "`{$composer['version']}` != `{$version}`"); } }
|
|
$table = "| Check | Result | Details |\n|-------|--------|--------|\n";
|
|
foreach ($this->results as $r) { $table .= "| {$r['check']} | {$r['status']} | {$r['details']} |\n"; }
|
|
$table .= "\n**Validation: {$this->pass} passed, {$this->fail} failed, {$this->warn} warnings**\n";
|
|
echo $table;
|
|
if ($outputSummary) { $summaryFile = getenv('GITHUB_STEP_SUMMARY'); if ($summaryFile) { file_put_contents($summaryFile, "## Pre-Release Sanity Checks ({$platform})\n\n{$table}\n", FILE_APPEND); } }
|
|
if ($githubOutput) { $ghOutput = getenv('GITHUB_OUTPUT'); if ($ghOutput) { file_put_contents($ghOutput, "validation_pass={$this->pass}\nvalidation_fail={$this->fail}\nvalidation_warn={$this->warn}\nvalidation_platform={$platform}\n", FILE_APPEND); } }
|
|
return $this->fail > 0 ? 1 : 0;
|
|
}
|
|
|
|
private function addVResult(string $check, string $status, string $details): void
|
|
{
|
|
$this->results[] = ['check' => $check, 'status' => $status, 'details' => $details];
|
|
if ($status === 'PASS') { $this->pass++; } elseif ($status === 'FAIL') { $this->fail++; } elseif ($status === 'WARN') { $this->warn++; }
|
|
}
|
|
}
|
|
|
|
$app = new ReleaseValidateCli();
|
|
exit($app->execute());
|