#!/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/platform_detect.php * VERSION: 09.25.02 * BRIEF: Auto-detect repository platform type and optionally update manifest */ declare(strict_types=1); require_once __DIR__ . '/../lib/Enterprise/CliFramework.php'; use MokoEnterprise\CliFramework; class PlatformDetectCli extends CliFramework { protected function configure(): void { $this->setDescription('Auto-detect repository platform type and optionally update manifest'); $this->addArgument('--path', 'Local repo path to scan (default: .)', '.'); $this->addArgument('--token', 'Gitea API token for updating manifest', ''); $this->addArgument('--gitea-url', 'Gitea URL (default: https://git.mokoconsulting.tech)', 'https://git.mokoconsulting.tech'); $this->addArgument('--owner', 'Repo owner for API update', ''); $this->addArgument('--repo', 'Repo name for API update', ''); $this->addArgument('--update', 'Update manifest.platform via API (flag)', 'false'); $this->addArgument('--github-output', 'Append platform=xxx to $GITHUB_OUTPUT (flag)', 'false'); } protected function run(): int { $path = $this->getArgument('--path'); $root = realpath($path) ?: $path; $token = $this->getArgument('--token'); $giteaUrl = rtrim($this->getArgument('--gitea-url'), '/'); $owner = $this->getArgument('--owner'); $repo = $this->getArgument('--repo'); $doUpdate = $this->isFlagSet('--update'); $githubOutput = $this->isFlagSet('--github-output'); $platform = $this->detectPlatform($root); $this->log('INFO', "Detected platform: {$platform}"); echo $platform . "\n"; // Append to $GITHUB_OUTPUT if requested if ($githubOutput) { $outputFile = getenv('GITHUB_OUTPUT'); if ($outputFile !== false && $outputFile !== '') { file_put_contents($outputFile, "platform={$platform}\n", FILE_APPEND); $this->log('INFO', "Appended platform={$platform} to \$GITHUB_OUTPUT"); } else { $this->log('WARN', '$GITHUB_OUTPUT is not set; skipping output append.'); } } // Update manifest via API if requested if ($doUpdate) { if ($token === '' || $owner === '' || $repo === '') { $this->log('ERROR', '--update requires --token, --owner, and --repo.'); return 1; } if ($this->dryRun) { $this->log('INFO', "[DRY RUN] Would update manifest.platform to \"{$platform}\" " . "for {$owner}/{$repo}."); return 0; } $this->log('INFO', "Updating manifest.platform for {$owner}/{$repo} to \"{$platform}\"..."); $response = $this->apiRequest( $giteaUrl, $token, 'PATCH', "/api/v1/repos/{$owner}/{$repo}/manifest", json_encode(['platform' => $platform]) ); if ($response['code'] >= 200 && $response['code'] < 300) { $this->log('INFO', "Manifest updated successfully (HTTP {$response['code']})."); } else { $this->log('ERROR', "Failed to update manifest (HTTP {$response['code']}): " . $response['body']); return 1; } } return 0; } private function detectPlatform(string $root): string { // 1. Joomla — has pkg_*.xml or Joomla-style extension manifest $joomlaIndicators = array_merge( glob("{$root}/source/pkg_*.xml") ?: [], glob("{$root}/pkg_*.xml") ?: [], glob("{$root}/source/packages/*/services/provider.php") ?: [], glob("{$root}/**/templateDetails.xml") ?: [], ); if (!empty($joomlaIndicators)) { return 'joomla'; } // 2. Dolibarr — has mod*.class.php or dolibarr module descriptor $doliIndicators = array_merge( glob("{$root}/core/modules/mod*.class.php") ?: [], glob("{$root}/class/*.class.php") ?: [], ); if (!empty($doliIndicators) && file_exists("{$root}/langs")) { return 'dolibarr'; } // 3. Go — has go.mod if (file_exists("{$root}/go.mod")) { return 'go'; } // 4. MCP — has package.json with mcp-related content or dist/index.js pattern if (file_exists("{$root}/package.json")) { $pkg = json_decode(file_get_contents("{$root}/package.json"), true); $name = $pkg['name'] ?? ''; if (str_contains($name, 'mcp') || isset($pkg['dependencies']['@modelcontextprotocol/sdk'])) { return 'mcp'; } } // 5. Platform — is mokoplatform itself or org-config $repoName = basename($root); if (in_array($repoName, ['mokoplatform', 'mokogitea-org-config'])) { return 'platform'; } // 6. Default return 'generic'; } private function isFlagSet(string $flag): bool { $value = $this->getArgument($flag); return $value === 'true' || $value === '1' || $value === 'yes'; } private function apiRequest( string $giteaUrl, string $token, string $method, string $endpoint, ?string $body = null ): array { $url = $giteaUrl . $endpoint; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Accept: application/json', "Authorization: token {$token}", ]); if ($body !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, $body); } $responseBody = curl_exec($ch); $httpCode = (int) curl_getinfo( $ch, CURLINFO_HTTP_CODE ); if (curl_errno($ch)) { $error = curl_error($ch); curl_close($ch); return [ 'code' => 0, 'body' => "cURL error: {$error}", ]; } curl_close($ch); return ['code' => $httpCode, 'body' => $responseBody]; } } $app = new PlatformDetectCli(); exit($app->execute());