From 0d3b14d55ca0c200451d888c1bb8434a53db81bc Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 20 Jun 2026 21:41:43 -0500 Subject: [PATCH 1/2] feat: cross-repo dependency update automation (#149) Add `deps:update` command that scans org repos for outdated Composer/npm dependencies, creates PRs with changelogs, and optionally auto-merges safe patch updates. - Composer: runs `composer outdated --format=json`, updates targeted packages - npm: runs `npm outdated --json`, updates targeted packages - Skips repos with existing deps PRs (no duplicates) - Checkpoint-based resumability with --resume - --patch-only for safe updates, --auto-merge for patch PRs - Supports --repos and --exclude filters --- automation/update_dependencies.php | 633 +++++++++++++++++++++++++++++ bin/moko | 1 + 2 files changed, 634 insertions(+) create mode 100644 automation/update_dependencies.php diff --git a/automation/update_dependencies.php b/automation/update_dependencies.php new file mode 100644 index 0000000..1380846 --- /dev/null +++ b/automation/update_dependencies.php @@ -0,0 +1,633 @@ +#!/usr/bin/env php + + * + * This file is part of a Moko Consulting project. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * FILE INFORMATION + * DEFGROUP: MokoPlatform.Automation + * INGROUP: MokoPlatform.Scripts + * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli + * PATH: /automation/update_dependencies.php + * VERSION: 01.00.00 + * BRIEF: Cross-repo dependency update automation — scan, update, PR, auto-merge + */ + +declare(strict_types=1); + +require_once __DIR__ . '/../vendor/autoload.php'; + +use MokoCli\{ + ApiClient, + AuditLogger, + CheckpointManager, + CircuitBreakerOpen, + CliFramework, + Config, + GitPlatformAdapter, + PlatformAdapterFactory, + RateLimitExceeded +}; + +/** + * Cross-Repo Dependency Update Automation + * + * Scans org repos for outdated Composer/npm dependencies, creates PRs with + * changelogs, and optionally auto-merges safe patch updates. + * + * @see https://git.mokoconsulting.tech/MokoConsulting/mokocli/issues/149 + */ +class UpdateDependencies extends CliFramework +{ + public const VERSION = '01.00.00'; + + private const BRANCH_PREFIX = 'chore/deps-update'; + + private ApiClient $api; + private GitPlatformAdapter $adapter; + private AuditLogger $logger; + private CheckpointManager $checkpoints; + + /** Summary counters. */ + private int $reposScanned = 0; + private int $reposUpdated = 0; + private int $prsCreated = 0; + private int $autoMerged = 0; + private int $reposFailed = 0; + + protected function configure(): void + { + $this->setDescription('Cross-repo dependency update automation'); + $this->addArgument('--org', 'Organization to scan', 'MokoConsulting'); + $this->addArgument('--repos', 'Comma-separated list of specific repos', ''); + $this->addArgument('--exclude', 'Comma-separated list of repos to exclude', ''); + $this->addArgument('--skip-archived', 'Skip archived repositories', true); + $this->addArgument('--type', 'Dependency type: composer, npm, or all', 'all'); + $this->addArgument('--patch-only', 'Only update patch versions (safe updates)', false); + $this->addArgument('--auto-merge', 'Auto-merge PRs with only patch updates', false); + $this->addArgument('--resume', 'Resume from checkpoint', false); + } + + protected function run(): int + { + $this->log("Dependency Update Automation v" . self::VERSION, 'INFO'); + + if (!$this->initComponents()) { + return self::EXIT_FAILURE; + } + + $org = $this->getArgument('--org', 'MokoConsulting'); + $depType = strtolower($this->getArgument('--type', 'all')); + $patchOnly = $this->getArgument('--patch-only', false); + $autoMerge = $this->getArgument('--auto-merge', false); + + // ── Gather repos ───────────────────────────────────────────────── + $repos = $this->gatherRepos($org); + if ($repos === null) { + return self::EXIT_FAILURE; + } + + $total = count($repos); + $this->log("Found {$total} repositories to scan", 'INFO'); + + // ── Resume support ─────────────────────────────────────────────── + $completed = []; + if ($this->getArgument('--resume', false)) { + $checkpoint = $this->checkpoints->load('deps_update'); + if ($checkpoint) { + $completed = $checkpoint['completed'] ?? []; + $this->log("Resuming — skipping " . count($completed) . " already-processed repos", 'INFO'); + } + } + + // ── Process each repo ──────────────────────────────────────────── + $this->section('Scanning repositories for outdated dependencies'); + + foreach ($repos as $i => $repo) { + $repoName = $repo['name']; + $this->progress($i + 1, $total, $repoName); + + if (in_array($repoName, $completed, true)) { + continue; + } + + try { + $this->processRepo($org, $repoName, $depType, $patchOnly, $autoMerge); + $completed[] = $repoName; + + $this->checkpoints->save('deps_update', ['completed' => $completed]); + } catch (RateLimitExceeded $e) { + $this->log("Rate limit hit — checkpoint saved", 'WARNING'); + break; + } catch (CircuitBreakerOpen $e) { + $this->log("Circuit breaker open — checkpoint saved", 'WARNING'); + break; + } catch (\Exception $e) { + $this->log("Failed {$repoName}: {$e->getMessage()}", 'ERROR'); + $this->reposFailed++; + } + } + + $this->progress($total, $total, '', true); + + // ── Summary ────────────────────────────────────────────────────── + $this->section('Summary'); + $this->printSummary( + $this->reposScanned - $this->reposFailed, + $this->reposFailed, + $this->elapsed() + ); + + $this->log("Repos scanned: {$this->reposScanned}", 'INFO'); + $this->log("Repos updated: {$this->reposUpdated}", 'INFO'); + $this->log("PRs created: {$this->prsCreated}", 'INFO'); + if ($autoMerge) { + $this->log("Auto-merged: {$this->autoMerged}", 'INFO'); + } + + if (count($completed) === $total) { + $this->checkpoints->clear('deps_update'); + } + + return $this->reposFailed > 0 ? self::EXIT_FAILURE : self::EXIT_SUCCESS; + } + + // ── Component init ─────────────────────────────────────────────────── + + private function initComponents(): bool + { + try { + $config = new Config(); + $this->api = new ApiClient($config); + $this->adapter = PlatformAdapterFactory::create($this->api, $config); + $this->logger = new AuditLogger(); + $this->checkpoints = new CheckpointManager(); + return true; + } catch (\Exception $e) { + $this->log("Failed to initialise: {$e->getMessage()}", 'ERROR'); + return false; + } + } + + // ── Repo gathering ─────────────────────────────────────────────────── + + private function gatherRepos(string $org): ?array + { + $specificRepos = array_filter(explode(',', $this->getArgument('--repos', ''))); + $excludeRepos = array_filter(explode(',', $this->getArgument('--exclude', ''))); + $skipArchived = $this->getArgument('--skip-archived', true); + + // Default exclusions + $excludeRepos = array_merge($excludeRepos, [ + 'mokocli', '.mokogitea-private', 'org-profile', + ]); + + try { + $repos = $this->adapter->listOrgRepos($org, $skipArchived); + } catch (\Exception $e) { + $this->log("Failed to list repos: {$e->getMessage()}", 'ERROR'); + return null; + } + + if (!empty($specificRepos)) { + $repos = array_filter($repos, fn($r) => in_array($r['name'], $specificRepos, true)); + } + if (!empty($excludeRepos)) { + $repos = array_filter($repos, fn($r) => !in_array($r['name'], $excludeRepos, true)); + } + + return array_values($repos); + } + + // ── Per-repo processing ────────────────────────────────────────────── + + private function processRepo( + string $org, + string $repoName, + string $depType, + bool $patchOnly, + bool $autoMerge + ): void { + $this->reposScanned++; + + $hasComposer = ($depType === 'all' || $depType === 'composer'); + $hasNpm = ($depType === 'all' || $depType === 'npm'); + + $outdated = []; + + // ── Composer ───────────────────────────────────────────────── + if ($hasComposer) { + $composerOutdated = $this->scanComposer($org, $repoName, $patchOnly); + if ($composerOutdated !== null) { + $outdated['composer'] = $composerOutdated; + } + } + + // ── npm ────────────────────────────────────────────────────── + if ($hasNpm) { + $npmOutdated = $this->scanNpm($org, $repoName, $patchOnly); + if ($npmOutdated !== null) { + $outdated['npm'] = $npmOutdated; + } + } + + if (empty($outdated)) { + return; + } + + // Check if there's already an open deps PR + if ($this->hasExistingDepsPR($org, $repoName)) { + $this->log(" {$repoName}: existing deps PR found — skipping", 'INFO'); + return; + } + + $this->reposUpdated++; + + // ── Create PR ──────────────────────────────────────────────── + $totalUpdates = 0; + $allPatchOnly = true; + + foreach ($outdated as $type => $packages) { + $totalUpdates += count($packages); + foreach ($packages as $pkg) { + if (!$this->isPatchUpdate($pkg['current'] ?? '', $pkg['latest'] ?? '')) { + $allPatchOnly = false; + } + } + } + + $title = "chore(deps): update {$totalUpdates} " . ($totalUpdates === 1 ? 'dependency' : 'dependencies'); + $body = $this->buildPrBody($repoName, $outdated); + $branch = self::BRANCH_PREFIX . '-' . date('Y-m-d'); + + if ($this->dryRun) { + $this->log("[dry-run] Would create PR in {$repoName}: {$title}", 'INFO'); + foreach ($outdated as $type => $packages) { + foreach ($packages as $pkg) { + $this->log(" [{$type}] {$pkg['name']}: {$pkg['current']} → {$pkg['latest']}", 'INFO'); + } + } + return; + } + + try { + // Clone repo, run updates, push branch + $prNumber = $this->cloneUpdateAndPR($org, $repoName, $branch, $title, $body, $outdated); + + if ($prNumber > 0) { + $this->prsCreated++; + $this->log(" {$repoName}: PR #{$prNumber} created", 'INFO'); + + // Auto-merge if all updates are patch-level + if ($autoMerge && $allPatchOnly && $prNumber > 0) { + $this->tryAutoMerge($org, $repoName, $prNumber); + } + } + } catch (\Exception $e) { + $this->log(" {$repoName}: PR creation failed — {$e->getMessage()}", 'ERROR'); + } + } + + // ── Composer scanning ──────────────────────────────────────────────── + + private function scanComposer(string $org, string $repoName, bool $patchOnly): ?array + { + // Check if repo has composer.json + try { + $this->adapter->getFileContents($org, $repoName, 'composer.json'); + } catch (\Exception $e) { + return null; + } + + // Check if repo has composer.lock + try { + $this->adapter->getFileContents($org, $repoName, 'composer.lock'); + } catch (\Exception $e) { + return null; + } + + // Clone to temp dir and run composer outdated + $tmpDir = sys_get_temp_dir() . '/moko_deps_' . $repoName . '_' . getmypid(); + @mkdir($tmpDir, 0700, true); + + try { + $cloneUrl = $this->adapter->getCloneUrl($org, $repoName); + $cmd = sprintf( + 'git clone --depth 1 --quiet %s %s 2>/dev/null', + escapeshellarg($cloneUrl), + escapeshellarg($tmpDir) + ); + exec($cmd, $output, $exitCode); + if ($exitCode !== 0) { + return null; + } + + // Run composer outdated + $flags = $patchOnly ? '--minor-only' : ''; + $cmd = sprintf( + 'composer outdated --format=json --no-interaction %s --working-dir=%s 2>/dev/null', + $flags, + escapeshellarg($tmpDir) + ); + $json = shell_exec($cmd); + if ($json === null || $json === '') { + return null; + } + + $data = json_decode($json, true); + $installed = $data['installed'] ?? []; + + if (empty($installed)) { + return null; + } + + $outdated = []; + foreach ($installed as $pkg) { + // Skip abandoned/dev packages + if (($pkg['abandoned'] ?? false) || str_starts_with($pkg['version'] ?? '', 'dev-')) { + continue; + } + + $outdated[] = [ + 'name' => $pkg['name'] ?? '', + 'current' => $pkg['version'] ?? '', + 'latest' => $pkg['latest'] ?? '', + 'status' => $pkg['latest-status'] ?? 'unknown', + ]; + } + + return empty($outdated) ? null : $outdated; + } finally { + // Cleanup + if (is_dir($tmpDir)) { + exec(sprintf('rm -rf %s', escapeshellarg($tmpDir))); + } + } + } + + // ── npm scanning ───────────────────────────────────────────────────── + + private function scanNpm(string $org, string $repoName, bool $patchOnly): ?array + { + // Check if repo has package.json + try { + $this->adapter->getFileContents($org, $repoName, 'package.json'); + } catch (\Exception $e) { + return null; + } + + // Check for lock file + $hasLock = false; + foreach (['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml'] as $lockFile) { + try { + $this->adapter->getFileContents($org, $repoName, $lockFile); + $hasLock = true; + break; + } catch (\Exception $e) { + // continue + } + } + + if (!$hasLock) { + return null; + } + + $tmpDir = sys_get_temp_dir() . '/moko_deps_npm_' . $repoName . '_' . getmypid(); + @mkdir($tmpDir, 0700, true); + + try { + $cloneUrl = $this->adapter->getCloneUrl($org, $repoName); + exec(sprintf('git clone --depth 1 --quiet %s %s 2>/dev/null', + escapeshellarg($cloneUrl), escapeshellarg($tmpDir))); + + if (!file_exists("{$tmpDir}/package.json")) { + return null; + } + + // Install deps first (needed for npm outdated) + exec(sprintf('cd %s && npm install --silent 2>/dev/null', escapeshellarg($tmpDir))); + + $json = shell_exec(sprintf('cd %s && npm outdated --json 2>/dev/null', escapeshellarg($tmpDir))); + if ($json === null || $json === '' || $json === '{}') { + return null; + } + + $data = json_decode($json, true); + if (!is_array($data) || empty($data)) { + return null; + } + + $outdated = []; + foreach ($data as $name => $info) { + $current = $info['current'] ?? ''; + $wanted = $info['wanted'] ?? ''; + $latest = $info['latest'] ?? ''; + $target = $patchOnly ? $wanted : $latest; + + if ($current === $target || $target === '') { + continue; + } + + $outdated[] = [ + 'name' => $name, + 'current' => $current, + 'latest' => $target, + 'status' => ($current === $wanted) ? 'up-to-date' : 'outdated', + ]; + } + + return empty($outdated) ? null : $outdated; + } finally { + if (is_dir($tmpDir)) { + exec(sprintf('rm -rf %s', escapeshellarg($tmpDir))); + } + } + } + + // ── PR creation ────────────────────────────────────────────────────── + + private function cloneUpdateAndPR( + string $org, + string $repoName, + string $branch, + string $title, + string $body, + array $outdated + ): int { + $tmpDir = sys_get_temp_dir() . '/moko_deps_pr_' . $repoName . '_' . getmypid(); + @mkdir($tmpDir, 0700, true); + + try { + $cloneUrl = $this->adapter->getCloneUrl($org, $repoName); + exec(sprintf('git clone --quiet %s %s 2>/dev/null', + escapeshellarg($cloneUrl), escapeshellarg($tmpDir))); + + // Create branch + exec(sprintf('git -C %s checkout -b %s 2>/dev/null', + escapeshellarg($tmpDir), escapeshellarg($branch))); + + $updated = false; + + // Run composer update if needed + if (isset($outdated['composer'])) { + $packages = array_column($outdated['composer'], 'name'); + $cmd = sprintf( + 'cd %s && composer update %s --no-interaction --quiet 2>/dev/null', + escapeshellarg($tmpDir), + implode(' ', array_map('escapeshellarg', $packages)) + ); + exec($cmd, $output, $exitCode); + if ($exitCode === 0) { + $updated = true; + } + } + + // Run npm update if needed + if (isset($outdated['npm'])) { + $packages = array_column($outdated['npm'], 'name'); + $cmd = sprintf( + 'cd %s && npm update %s --save 2>/dev/null', + escapeshellarg($tmpDir), + implode(' ', array_map('escapeshellarg', $packages)) + ); + exec($cmd, $output, $exitCode); + if ($exitCode === 0) { + $updated = true; + } + } + + if (!$updated) { + return 0; + } + + // Commit and push + exec(sprintf('git -C %s config user.email "gitea-actions[bot]@mokoconsulting.tech"', escapeshellarg($tmpDir))); + exec(sprintf('git -C %s config user.name "gitea-actions[bot]"', escapeshellarg($tmpDir))); + exec(sprintf('git -C %s add -A', escapeshellarg($tmpDir))); + + // Check if there are actual changes + exec(sprintf('git -C %s diff --cached --quiet', escapeshellarg($tmpDir)), $output, $diffExit); + if ($diffExit === 0) { + return 0; // No changes + } + + exec(sprintf('git -C %s commit -m %s', + escapeshellarg($tmpDir), + escapeshellarg($title . " [skip ci]"))); + exec(sprintf('git -C %s push origin %s 2>/dev/null', + escapeshellarg($tmpDir), escapeshellarg($branch)), $output, $pushExit); + + if ($pushExit !== 0) { + $this->log(" {$repoName}: push failed", 'ERROR'); + return 0; + } + + // Create PR via API + $defaultBranch = $this->getDefaultBranch($org, $repoName); + $pr = $this->adapter->createPullRequest( + $org, $repoName, $title, $branch, $defaultBranch, $body, [ + 'labels' => ['dependencies'], + ] + ); + + return (int) ($pr['number'] ?? 0); + } finally { + if (is_dir($tmpDir)) { + exec(sprintf('rm -rf %s', escapeshellarg($tmpDir))); + } + } + } + + // ── Auto-merge ─────────────────────────────────────────────────────── + + private function tryAutoMerge(string $org, string $repoName, int $prNumber): void + { + try { + $this->api->put( + "/repos/{$org}/{$repoName}/pulls/{$prNumber}/merge", + ['Do' => 'squash', 'merge_message_field' => 'chore(deps): auto-merge patch updates'] + ); + $this->autoMerged++; + $this->log(" {$repoName}: PR #{$prNumber} auto-merged", 'INFO'); + } catch (\Exception $e) { + $this->log(" {$repoName}: auto-merge failed — {$e->getMessage()}", 'WARNING'); + } + } + + // ── Helpers ─────────────────────────────────────────────────────────── + + private function hasExistingDepsPR(string $org, string $repoName): bool + { + try { + $prs = $this->adapter->listPullRequests($org, $repoName, ['state' => 'open']); + foreach ($prs as $pr) { + if (str_starts_with($pr['head']['ref'] ?? '', self::BRANCH_PREFIX)) { + return true; + } + } + } catch (\Exception $e) { + // Ignore — proceed with creating PR + } + return false; + } + + private function getDefaultBranch(string $org, string $repoName): string + { + try { + $repo = $this->api->get("/repos/{$org}/{$repoName}"); + return $repo['default_branch'] ?? 'main'; + } catch (\Exception $e) { + return 'main'; + } + } + + private function isPatchUpdate(string $current, string $latest): bool + { + $cur = explode('.', ltrim($current, 'v')); + $lat = explode('.', ltrim($latest, 'v')); + + if (count($cur) < 3 || count($lat) < 3) { + return false; + } + + // Same major and minor, only patch differs + return $cur[0] === $lat[0] && $cur[1] === $lat[1] && $cur[2] !== $lat[2]; + } + + private function buildPrBody(string $repoName, array $outdated): string + { + $lines = [ + "## Dependency Updates", + "", + "**Repository**: `{$repoName}`", + "**Scanned**: " . date('Y-m-d H:i:s'), + "", + ]; + + foreach ($outdated as $type => $packages) { + $lines[] = "### " . ucfirst($type); + $lines[] = ""; + $lines[] = "| Package | Current | Latest | Type |"; + $lines[] = "|---------|---------|--------|------|"; + + foreach ($packages as $pkg) { + $updateType = $this->isPatchUpdate($pkg['current'], $pkg['latest']) ? 'patch' : 'minor/major'; + $lines[] = "| `{$pkg['name']}` | {$pkg['current']} | {$pkg['latest']} | {$updateType} |"; + } + + $lines[] = ""; + } + + $lines[] = "---"; + $lines[] = "*Auto-generated by `moko deps:update`*"; + + return implode("\n", $lines); + } +} + +$script = new UpdateDependencies('update_dependencies', 'Cross-repo dependency update automation'); +exit($script->execute()); diff --git a/bin/moko b/bin/moko index db6a660..b6a58b6 100644 --- a/bin/moko +++ b/bin/moko @@ -89,6 +89,7 @@ const COMMAND_MAP = [ // Automation 'sync' => 'automation/bulk_sync.php', + 'deps:update' => 'automation/update_dependencies.php', 'automation:cleanup' => 'automation/repo_cleanup.php', 'automation:migrate-gitea' => 'automation/migrate_to_gitea.php', -- 2.52.0 From 109493ab4ad5e82cec63e1f65677d036f1b49ec6 Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Sun, 21 Jun 2026 02:42:15 +0000 Subject: [PATCH 2/2] chore(version): auto-bump patch 09.33.01-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- README.md | 2 +- automation/update_dependencies.php | 2 +- cli/branch_rename.php | 2 +- cli/bulk_workflow_push.php | 2 +- cli/bulk_workflow_trigger.php | 2 +- cli/client_dashboard.php | 2 +- cli/client_inventory.php | 2 +- cli/client_provision.php | 2 +- cli/grafana_dashboard.php | 2 +- cli/joomla_build.php | 2 +- cli/joomla_metadata_validate.php | 2 +- cli/manifest_detect.php | 2 +- cli/manifest_integrity.php | 2 +- cli/manifest_licensing.php | 2 +- cli/manifest_read.php | 2 +- cli/platform_detect.php | 2 +- cli/release_cascade.php | 2 +- cli/release_publish.php | 2 +- cli/scaffold_client.php | 2 +- cli/updates_xml_sync.php | 2 +- cli/version_auto_bump.php | 2 +- cli/version_check.php | 2 +- cli/wiki_sync.php | 2 +- cli/workflow_sync.php | 2 +- deploy/backup-before-deploy.php | 2 +- deploy/deploy-dolibarr.php | 2 +- deploy/health-check.php | 2 +- deploy/rollback-joomla.php | 2 +- deploy/sync-joomla.php | 2 +- mcp/servers/mokocrm_api/CONTRIBUTING.md | 2 +- mcp/servers/mokocrm_api/SECURITY.md | 2 +- mcp/servers/mokosuite_api/CONTRIBUTING.md | 2 +- mcp/servers/mokosuite_api/SECURITY.md | 2 +- tests/Unit/VersionBumpTest.php | 2 +- tests/Unit/VersionReadTest.php | 4 ++-- validate/check_file_integrity.php | 2 +- 37 files changed, 38 insertions(+), 38 deletions(-) diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 75a6963..73ca529 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 01.00.00 +# VERSION: 09.33.01 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/README.md b/README.md index c2df4af..15377d3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ DEFGROUP: MokoPlatform.Root INGROUP: MokoPlatform REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform PATH: /README.md -VERSION: 09.33.00 +VERSION: 09.33.01 BRIEF: Project overview and documentation --> diff --git a/automation/update_dependencies.php b/automation/update_dependencies.php index 1380846..80fa926 100644 --- a/automation/update_dependencies.php +++ b/automation/update_dependencies.php @@ -13,7 +13,7 @@ * INGROUP: MokoPlatform.Scripts * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli * PATH: /automation/update_dependencies.php - * VERSION: 01.00.00 + * VERSION: 09.33.01 * BRIEF: Cross-repo dependency update automation — scan, update, PR, auto-merge */ diff --git a/cli/branch_rename.php b/cli/branch_rename.php index 6843980..e011d16 100644 --- a/cli/branch_rename.php +++ b/cli/branch_rename.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/branch_rename.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Rename a git branch via Gitea API (create new, update PR, delete old) */ diff --git a/cli/bulk_workflow_push.php b/cli/bulk_workflow_push.php index b121ad4..028efa4 100644 --- a/cli/bulk_workflow_push.php +++ b/cli/bulk_workflow_push.php @@ -12,7 +12,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/bulk_workflow_push.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Push a workflow file to all governed repos via the Gitea Contents API */ diff --git a/cli/bulk_workflow_trigger.php b/cli/bulk_workflow_trigger.php index 63cb026..7c58c03 100644 --- a/cli/bulk_workflow_trigger.php +++ b/cli/bulk_workflow_trigger.php @@ -12,7 +12,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/bulk_workflow_trigger.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Trigger a workflow across multiple repos at once */ diff --git a/cli/client_dashboard.php b/cli/client_dashboard.php index 956873f..8e005ed 100644 --- a/cli/client_dashboard.php +++ b/cli/client_dashboard.php @@ -12,7 +12,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/client_dashboard.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Generate unified client dashboard HTML */ diff --git a/cli/client_inventory.php b/cli/client_inventory.php index adff0de..b983b2e 100644 --- a/cli/client_inventory.php +++ b/cli/client_inventory.php @@ -12,7 +12,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/client_inventory.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Discover and list all client-waas repos with their server configuration status */ diff --git a/cli/client_provision.php b/cli/client_provision.php index 9a7a6f1..85b64e1 100644 --- a/cli/client_provision.php +++ b/cli/client_provision.php @@ -12,7 +12,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/client_provision.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Provision a new client environment end-to-end */ diff --git a/cli/grafana_dashboard.php b/cli/grafana_dashboard.php index 1db52bb..59ce557 100644 --- a/cli/grafana_dashboard.php +++ b/cli/grafana_dashboard.php @@ -12,7 +12,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/grafana_dashboard.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Manage Grafana dashboards via API */ diff --git a/cli/joomla_build.php b/cli/joomla_build.php index 66d9b26..7d0654b 100644 --- a/cli/joomla_build.php +++ b/cli/joomla_build.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/joomla_build.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Build a Joomla extension ZIP from manifest — all types supported * NOTE: Called by pre-release and auto-release workflows. */ diff --git a/cli/joomla_metadata_validate.php b/cli/joomla_metadata_validate.php index a807033..5ca1f29 100644 --- a/cli/joomla_metadata_validate.php +++ b/cli/joomla_metadata_validate.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/joomla_metadata_validate.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Validate MokoGitea repo metadata against Joomla extension manifest XML */ diff --git a/cli/manifest_detect.php b/cli/manifest_detect.php index 40d924a..c4bc866 100644 --- a/cli/manifest_detect.php +++ b/cli/manifest_detect.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/manifest_detect.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Auto-detect manifest fields from source files and optionally push to API */ diff --git a/cli/manifest_integrity.php b/cli/manifest_integrity.php index 076ebf3..0171d8f 100644 --- a/cli/manifest_integrity.php +++ b/cli/manifest_integrity.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/manifest_integrity.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Cross-check manifest API fields against repo contents across the org */ diff --git a/cli/manifest_licensing.php b/cli/manifest_licensing.php index 7efd446..9acf2cb 100644 --- a/cli/manifest_licensing.php +++ b/cli/manifest_licensing.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/manifest_licensing.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Ensure licensing tags (updateservers, dlid) in Joomla extension manifests */ diff --git a/cli/manifest_read.php b/cli/manifest_read.php index 592c737..3ce7951 100644 --- a/cli/manifest_read.php +++ b/cli/manifest_read.php @@ -10,7 +10,7 @@ * INGROUP: mokocli * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli * PATH: /cli/manifest_read.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Read repo metadata from Gitea manifest API, auto-detect the rest */ diff --git a/cli/platform_detect.php b/cli/platform_detect.php index c3fa688..2f417b4 100644 --- a/cli/platform_detect.php +++ b/cli/platform_detect.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/platform_detect.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Auto-detect repository platform type and optionally update manifest */ diff --git a/cli/release_cascade.php b/cli/release_cascade.php index cf06dfc..5b89497 100644 --- a/cli/release_cascade.php +++ b/cli/release_cascade.php @@ -10,7 +10,7 @@ * INGROUP: mokocli * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli * PATH: /cli/release_cascade.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Cascade release zip to all lower stability channels */ diff --git a/cli/release_publish.php b/cli/release_publish.php index b47971b..2b181d3 100644 --- a/cli/release_publish.php +++ b/cli/release_publish.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/release_publish.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Publish a release and create copies for all lesser stability streams. */ diff --git a/cli/scaffold_client.php b/cli/scaffold_client.php index 6056390..b66355a 100644 --- a/cli/scaffold_client.php +++ b/cli/scaffold_client.php @@ -12,7 +12,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/scaffold_client.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Scaffold a new client-waas repo from Template-Client-WaaS with pre-configured settings */ diff --git a/cli/updates_xml_sync.php b/cli/updates_xml_sync.php index 0a2ab91..4a52f5e 100644 --- a/cli/updates_xml_sync.php +++ b/cli/updates_xml_sync.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/updates_xml_sync.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Sync updates.xml to target branches via Gitea API * NOTE: Called by pre-release and auto-release workflows after updates.xml * is modified on the current branch. Pushes the file to other branches diff --git a/cli/version_auto_bump.php b/cli/version_auto_bump.php index 2804b8d..df4b5a9 100644 --- a/cli/version_auto_bump.php +++ b/cli/version_auto_bump.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/version_auto_bump.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Auto patch-bump, set stability suffix, and commit — single CLI replacing inline workflow bash */ diff --git a/cli/version_check.php b/cli/version_check.php index 6be014b..c0cfe0a 100644 --- a/cli/version_check.php +++ b/cli/version_check.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/version_check.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Validate version consistency across README, manifests, and sub-packages */ diff --git a/cli/wiki_sync.php b/cli/wiki_sync.php index 1dc2106..f0048f4 100644 --- a/cli/wiki_sync.php +++ b/cli/wiki_sync.php @@ -10,7 +10,7 @@ * INGROUP: mokoplatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /cli/wiki_sync.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Sync select wiki pages from mokoplatform to all template repos */ diff --git a/cli/workflow_sync.php b/cli/workflow_sync.php index 335d65f..4c86337 100644 --- a/cli/workflow_sync.php +++ b/cli/workflow_sync.php @@ -10,7 +10,7 @@ * INGROUP: moko-platform * REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform * PATH: /cli/workflow_sync.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Sync workflows from Generic → platform templates → live repos based on manifest.platform */ diff --git a/deploy/backup-before-deploy.php b/deploy/backup-before-deploy.php index 0aba8a1..f3041f2 100644 --- a/deploy/backup-before-deploy.php +++ b/deploy/backup-before-deploy.php @@ -12,7 +12,7 @@ * INGROUP: MokoPlatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /deploy/backup-before-deploy.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Snapshot Joomla directories before deployment for rollback capability */ diff --git a/deploy/deploy-dolibarr.php b/deploy/deploy-dolibarr.php index aa3172a..2e39c2c 100644 --- a/deploy/deploy-dolibarr.php +++ b/deploy/deploy-dolibarr.php @@ -12,7 +12,7 @@ * INGROUP: MokoPlatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /deploy/deploy-dolibarr.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Deploy Dolibarr module files to a remote server via SFTP/rsync */ diff --git a/deploy/health-check.php b/deploy/health-check.php index 72d26ae..1f2f4e7 100644 --- a/deploy/health-check.php +++ b/deploy/health-check.php @@ -12,7 +12,7 @@ * INGROUP: MokoPlatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /deploy/health-check.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Post-deploy health check — verify a Joomla site is responding correctly */ diff --git a/deploy/rollback-joomla.php b/deploy/rollback-joomla.php index 1a7b898..bc4de01 100644 --- a/deploy/rollback-joomla.php +++ b/deploy/rollback-joomla.php @@ -12,7 +12,7 @@ * INGROUP: MokoPlatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /deploy/rollback-joomla.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Rollback a Joomla deployment by restoring from a pre-deploy snapshot */ diff --git a/deploy/sync-joomla.php b/deploy/sync-joomla.php index 2932a79..db0e953 100644 --- a/deploy/sync-joomla.php +++ b/deploy/sync-joomla.php @@ -12,7 +12,7 @@ * INGROUP: MokoPlatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /deploy/sync-joomla.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Sync Joomla site directories between two servers via rsync over SSH */ diff --git a/mcp/servers/mokocrm_api/CONTRIBUTING.md b/mcp/servers/mokocrm_api/CONTRIBUTING.md index 6d5ce1b..c064e25 100644 --- a/mcp/servers/mokocrm_api/CONTRIBUTING.md +++ b/mcp/servers/mokocrm_api/CONTRIBUTING.md @@ -14,7 +14,7 @@ DEFGROUP: dolibarr-api-mcp.Documentation INGROUP: dolibarr-api-mcp REPO: https://git.mokoconsulting.tech/MokoConsulting/dolibarr-api-mcp - VERSION: 09.33.00 + VERSION: 09.33.01 PATH: ./CONTRIBUTING.md BRIEF: Contribution guidelines for the project --> diff --git a/mcp/servers/mokocrm_api/SECURITY.md b/mcp/servers/mokocrm_api/SECURITY.md index 6b14161..c8899e2 100644 --- a/mcp/servers/mokocrm_api/SECURITY.md +++ b/mcp/servers/mokocrm_api/SECURITY.md @@ -10,7 +10,7 @@ DEFGROUP: dolibarr-api-mcp.Documentation INGROUP: dolibarr-api-mcp REPO: https://git.mokoconsulting.tech/MokoConsulting/dolibarr-api-mcp PATH: /SECURITY.md -VERSION: 09.33.00 +VERSION: 09.33.01 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/mcp/servers/mokosuite_api/CONTRIBUTING.md b/mcp/servers/mokosuite_api/CONTRIBUTING.md index 96f178e..a18ff08 100644 --- a/mcp/servers/mokosuite_api/CONTRIBUTING.md +++ b/mcp/servers/mokosuite_api/CONTRIBUTING.md @@ -14,7 +14,7 @@ DEFGROUP: INGROUP: Project.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoCli-Template-Generic - VERSION: 09.33.00 + VERSION: 09.33.01 PATH: ./CONTRIBUTING.md BRIEF: Contribution guidelines for the project --> diff --git a/mcp/servers/mokosuite_api/SECURITY.md b/mcp/servers/mokosuite_api/SECURITY.md index fb0919e..c80ea43 100644 --- a/mcp/servers/mokosuite_api/SECURITY.md +++ b/mcp/servers/mokosuite_api/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: [PROJECT_NAME] INGROUP: [PROJECT_NAME].Documentation REPO: [REPOSITORY_URL] PATH: /SECURITY.md -VERSION: 09.33.00 +VERSION: 09.33.01 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/tests/Unit/VersionBumpTest.php b/tests/Unit/VersionBumpTest.php index 17019ef..730ca24 100644 --- a/tests/Unit/VersionBumpTest.php +++ b/tests/Unit/VersionBumpTest.php @@ -63,7 +63,7 @@ class VersionBumpTest extends TestCase { file_put_contents( "{$this->tmpDir}/README.md", - "\nSome content\n" + "\nSome content\n" ); $this->execute(); diff --git a/tests/Unit/VersionReadTest.php b/tests/Unit/VersionReadTest.php index b150e27..0f851be 100644 --- a/tests/Unit/VersionReadTest.php +++ b/tests/Unit/VersionReadTest.php @@ -34,7 +34,7 @@ class VersionReadTest extends TestCase { file_put_contents( "{$this->tmpDir}/README.md", - "# Test\n\n" + "# Test\n\n" ); $this->assertSame('02.03.04', trim($this->runScript())); @@ -68,7 +68,7 @@ class VersionReadTest extends TestCase { file_put_contents( "{$this->tmpDir}/README.md", - "\n" + "\n" ); mkdir("{$this->tmpDir}/src", 0755, true); file_put_contents( diff --git a/validate/check_file_integrity.php b/validate/check_file_integrity.php index 558a85e..38e2d89 100644 --- a/validate/check_file_integrity.php +++ b/validate/check_file_integrity.php @@ -12,7 +12,7 @@ * INGROUP: MokoPlatform * REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform * PATH: /validate/check_file_integrity.php - * VERSION: 09.33.00 + * VERSION: 09.33.01 * BRIEF: Compare deployed files on a remote server against the local repository to detect drift */ -- 2.52.0