#!/usr/bin/env php * * 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/version_reset_dev.php * BRIEF: Reset platform version to 'development' on a branch via Gitea API */ declare(strict_types=1); require_once __DIR__ . '/../lib/Enterprise/CliFramework.php'; use MokoEnterprise\CliFramework; class VersionResetDevCli extends CliFramework { protected function configure(): void { $this->setDescription('Reset platform version to development on a branch via Gitea API'); $this->addArgument('--token', 'Gitea API token (also reads MOKOGITEA_TOKEN / GITEA_TOKEN env)', ''); $this->addArgument('--api-base', 'Gitea API base URL for the repo', ''); $this->addArgument('--branch', 'Target branch (default: dev)', 'dev'); $this->addArgument('--platform', 'Platform type: dolibarr, crm-module, joomla, waas-component', ''); $this->addArgument('--path', 'Repo root for auto-detecting platform from manifest.xml', ''); } protected function run(): int { $token = $this->getArgument('--token'); $apiBase = $this->getArgument('--api-base'); $branch = $this->getArgument('--branch'); $platform = $this->getArgument('--platform'); $path = $this->getArgument('--path'); // Allow token from environment if ($token === '') { $envToken = getenv('MOKOGITEA_TOKEN'); if ($envToken !== false && $envToken !== '') { $token = $envToken; } } if ($token === '') { $envToken = getenv('GITEA_TOKEN'); if ($envToken !== false && $envToken !== '') { $token = $envToken; } } if ($token === '' || $apiBase === '') { $this->log('ERROR', '--token and --api-base are required.'); return 1; } $apiBase = rtrim($apiBase, '/'); // ── Platform detection ─────────────────────────────────────────────────────── if ($platform === '' && $path !== '') { $platform = $this->detectPlatform($path) ?? ''; if ($platform !== '') { echo "Detected platform: {$platform}\n"; } } if ($platform === '') { $this->log('ERROR', 'Could not determine platform. Use --platform or --path.'); return 1; } // ── Dispatch by platform ───────────────────────────────────────────────────── $changed = 0; if (in_array($platform, ['dolibarr', 'crm-module'], true)) { $changed = $this->resetDolibarrVersion($apiBase, $token, $branch); } elseif (in_array($platform, ['joomla', 'waas-component'], true)) { echo "Joomla version reset is not yet implemented — skipping.\n"; } else { echo "Platform '{$platform}' has no version-reset logic — skipping.\n"; } echo "Reset {$changed} file(s) to 'development' on branch '{$branch}'.\n"; return 0; } private function detectPlatform(string $repoPath): ?string { $root = realpath($repoPath) ?: $repoPath; $manifestXml = "{$root}/.mokogitea/manifest.xml"; if (!file_exists($manifestXml)) { return null; } $xml = @simplexml_load_file($manifestXml); if ($xml === false) { return null; } if (isset($xml->governance->platform)) { $platform = (string) $xml->governance->platform; if ($platform !== '') { return $platform; } } return null; } private function giteaApiCall(string $url, string $token, string $method = 'GET', ?string $body = null): ?array { $ch = curl_init($url); if ($ch === false) { $this->log('ERROR', "curl_init() failed for {$url}"); return null; } $headers = [ "Authorization: token {$token}", 'Accept: application/json', ]; if ($body !== null) { $headers[] = 'Content-Type: application/json'; } curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_TIMEOUT => 30, CURLOPT_CUSTOMREQUEST => $method, ]); if ($body !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, $body); } $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode < 200 || $httpCode >= 300 || !is_string($response) || $response === '') { return null; } $data = json_decode($response, true); if (!is_array($data)) { return null; } return $data; } private function resetDolibarrVersion(string $apiBase, string $token, string $branch): int { // Search the repo tree for mod*.class.php files $treeUrl = "{$apiBase}/git/trees/{$branch}?recursive=true"; $tree = $this->giteaApiCall($treeUrl, $token); if ($tree === null || !isset($tree['tree']) || !is_array($tree['tree'])) { $this->log('ERROR', "Could not read repository tree for branch '{$branch}'."); return 0; } // Find candidate files: mod*.class.php anywhere in the tree $candidates = []; foreach ($tree['tree'] as $entry) { if (!isset($entry['path']) || !is_string($entry['path'])) { continue; } $basename = basename($entry['path']); if (preg_match('/^mod[A-Za-z0-9_]+\.class\.php$/', $basename)) { $candidates[] = $entry['path']; } } if (empty($candidates)) { echo "No mod*.class.php files found on branch '{$branch}'.\n"; return 0; } $changed = 0; foreach ($candidates as $filePath) { // GET file contents via API $encodedPath = implode('/', array_map('rawurlencode', explode('/', $filePath))); $fileUrl = "{$apiBase}/contents/{$encodedPath}?ref={$branch}"; $fileData = $this->giteaApiCall($fileUrl, $token); if ($fileData === null || !isset($fileData['content'])) { echo "Skipping {$filePath}: could not fetch contents.\n"; continue; } // Decode base64 content $rawContent = is_string($fileData['content']) ? $fileData['content'] : ''; $content = base64_decode($rawContent, true); if ($content === false) { echo "Skipping {$filePath}: could not decode content.\n"; continue; } // Verify this file extends DolibarrModules if (!str_contains($content, 'extends DolibarrModules')) { continue; } // Replace $this->version = '...' with $this->version = 'development' $updated = preg_replace( '/(\$this->version\s*=\s*)[\'"][^\'"]*[\'"]/', "\${1}'development'", $content ); if ($updated === null || $updated === $content) { echo "Skipping {$filePath}: no version change needed.\n"; continue; } // PUT updated content back via API $sha = $fileData['sha'] ?? ''; $putBody = json_encode([ 'content' => base64_encode($updated), 'message' => 'chore(version): reset dev version [skip ci]', 'branch' => $branch, 'sha' => $sha, ]); $putUrl = "{$apiBase}/contents/{$encodedPath}"; $result = $this->giteaApiCall($putUrl, $token, 'PUT', $putBody); if ($result !== null) { echo "Reset: {$filePath} -> \$this->version = 'development'\n"; $changed++; } else { $this->log('ERROR', "Failed to update {$filePath} on branch '{$branch}'."); } } return $changed; } } $app = new VersionResetDevCli(); exit($app->execute());