diff --git a/cli/create_project.php b/cli/create_project.php index 4a70a4b..17170bc 100644 --- a/cli/create_project.php +++ b/cli/create_project.php @@ -49,11 +49,18 @@ if (!$repoName && !$allMode) { exit(2); } -$token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN'); -if (empty($token)) { - fwrite(STDERR, "GH_TOKEN or GITHUB_TOKEN not set\n"); +$config = \MokoEnterprise\Config::load(); +$platform = $config->getString('platform', 'gitea'); +try { + $adapter = \MokoEnterprise\PlatformAdapterFactory::create($config); + $api = $adapter->getApiClient(); +} catch (\Exception $e) { + fwrite(STDERR, "Platform initialization failed: " . $e->getMessage() . "\n"); exit(1); } +$token = $platform === 'gitea' + ? $config->getString('gitea.token', '') + : $config->getString('github.token', ''); $repoRoot = dirname(__DIR__, 2); $templatesDir = "{$repoRoot}/templates/projects"; @@ -93,12 +100,15 @@ $TYPE_TO_TEMPLATE = [ ]; /** - * Execute a GitHub GraphQL query. + * Execute a GraphQL query (GitHub only — Gitea does not support GraphQL). * * @return array */ -function graphql(string $query, array $variables, string $token): array +function graphql(string $query, array $variables, string $token, string $platformName = 'gitea'): array { + if ($platformName !== 'github') { + return []; + } $payload = json_encode(['query' => $query, 'variables' => $variables]); $ch = curl_init('https://api.github.com/graphql'); curl_setopt_array($ch, [ @@ -131,36 +141,30 @@ function graphql(string $query, array $variables, string $token): array } /** - * Execute a GitHub REST API GET call. + * Execute a REST API GET call via the platform adapter's ApiClient. * * @return array */ -function restGet(string $path, string $token): array +function restGet(string $path, string $token, ?\MokoEnterprise\ApiClient $apiClient = null): array { - $ch = curl_init("https://api.github.com/{$path}"); - curl_setopt_array($ch, [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => [ - 'Authorization: token ' . $token, - 'User-Agent: MokoStandards-CreateProject', - 'Accept: application/vnd.github.v3+json', - ], - ]); - $body = (string) curl_exec($ch); - $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - - return $status === 200 ? (json_decode($body, true) ?? []) : []; + if ($apiClient !== null) { + try { + return $apiClient->get("/{$path}"); + } catch (\Exception $e) { + return []; + } + } + return []; } /** * Detect platform type from .mokostandards file in the repo. */ -function detectPlatform(string $org, string $repo, string $token): string +function detectPlatform(string $org, string $repo, string $token, ?\MokoEnterprise\ApiClient $apiClient = null): string { - // Try .github/.mokostandards first, then root - foreach (['.github/.mokostandards', '.mokostandards'] as $path) { - $data = restGet("repos/{$org}/{$repo}/contents/{$path}", $token); + // Try platform metadata dir first, then root + foreach (['.github/.mokostandards', '.gitea/.mokostandards', '.mokostandards'] as $path) { + $data = restGet("repos/{$org}/{$repo}/contents/{$path}", $token, $apiClient); if (!empty($data['content'])) { $content = base64_decode($data['content']); if (preg_match('/^platform:\s*(.+)/m', $content, $m)) { diff --git a/cli/joomla_release.php b/cli/joomla_release.php index a2821c6..bd923a4 100644 --- a/cli/joomla_release.php +++ b/cli/joomla_release.php @@ -25,7 +25,7 @@ declare(strict_types=1); require_once __DIR__ . '/../../vendor/autoload.php'; -use MokoEnterprise\{ApiClient, AuditLogger, CLIApp}; +use MokoEnterprise\{ApiClient, AuditLogger, CLIApp, Config, PlatformAdapterFactory}; class JoomlaRelease extends CLIApp { @@ -73,7 +73,9 @@ class JoomlaRelease extends CLIApp return 1; } - $this->api = new ApiClient(); + $config = Config::load(); + $this->adapter = PlatformAdapterFactory::create($config); + $this->api = $this->adapter->getApiClient(); $this->logger = new AuditLogger('joomla_release'); if ($repo !== '') { @@ -287,7 +289,12 @@ class JoomlaRelease extends CLIApp } } - $token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN'); + $releaseConfig = Config::load(); + $releasePlatform = $releaseConfig->getString('platform', 'gitea'); + $releaseToken = $releasePlatform === 'gitea' + ? $releaseConfig->getString('gitea.token', '') + : $releaseConfig->getString('github.token', ''); + $acceptHeader = $releasePlatform === 'github' ? 'application/vnd.github+json' : 'application/json'; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => "{$uploadUrl}?name=" . urlencode($fileName), @@ -295,9 +302,9 @@ class JoomlaRelease extends CLIApp CURLOPT_POSTFIELDS => file_get_contents($filePath), CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ - "Authorization: token {$token}", + "Authorization: token {$releaseToken}", 'Content-Type: application/octet-stream', - 'Accept: application/vnd.github+json', + "Accept: {$acceptHeader}", ], ]); curl_exec($ch); @@ -369,8 +376,15 @@ class JoomlaRelease extends CLIApp if (is_dir($tmpDir)) { $this->rmdir($tmpDir); } - $token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN'); - $url = "https://x-access-token:{$token}@github.com/" . self::ORG . "/{$repo}.git"; + $config = Config::load(); + $platform = $config->getString('platform', 'gitea'); + $token = $platform === 'gitea' + ? $config->getString('gitea.token', '') + : $config->getString('github.token', ''); + $cloneHost = $platform === 'gitea' + ? rtrim($config->getString('gitea.url', 'https://git.mokoconsulting.tech'), '/') + : 'https://github.com'; + $url = "https://x-access-token:{$token}@" . preg_replace('#^https?://#', '', $cloneHost) . '/' . self::ORG . "/{$repo}.git"; $cmd = ['git', 'clone', '--depth', '1', '--quiet', $url, $tmpDir]; $proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes); proc_close($proc); diff --git a/lib/Common.php b/lib/Common.php index b494b08..0efbec0 100644 --- a/lib/Common.php +++ b/lib/Common.php @@ -32,7 +32,8 @@ class Common */ const FALLBACK_VERSION = '04.00.00'; - const REPO_URL = 'https://github.com/mokoconsulting-tech/MokoStandards'; + const REPO_URL = 'https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-API'; + const REPO_URL_GITHUB = 'https://github.com/mokoconsulting-tech/MokoStandards'; const COPYRIGHT = 'Copyright (C) 2026 Moko Consulting '; const LICENSE = 'GPL-3.0-or-later'; diff --git a/maintenance/repo_inventory.php b/maintenance/repo_inventory.php index c4cd2d0..a8f4bf1 100644 --- a/maintenance/repo_inventory.php +++ b/maintenance/repo_inventory.php @@ -30,11 +30,17 @@ foreach ($argv as $i => $arg) { if ($arg === '--org' && isset($argv[$i + 1])) { $org = $argv[$i + 1]; } } -$token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN'); -if (empty($token)) { - fwrite(STDERR, "GH_TOKEN or GITHUB_TOKEN not set\n"); +$config = \MokoEnterprise\Config::load(); +try { + $_adapter = \MokoEnterprise\PlatformAdapterFactory::create($config); + $_api = $_adapter->getApiClient(); +} catch (\Exception $e) { + fwrite(STDERR, "Platform init failed: " . $e->getMessage() . "\n"); exit(1); } +$token = $config->getString('platform', 'gitea') === 'gitea' + ? $config->getString('gitea.token', '') + : $config->getString('github.token', ''); $ALWAYS_EXCLUDE = ['MokoStandards', '.github-private']; @@ -43,23 +49,20 @@ $ALWAYS_EXCLUDE = ['MokoStandards', '.github-private']; */ function ghApi(string $method, string $path, ?array $body, string $token): array { - $ch = curl_init("https://api.github.com/{$path}"); - $opts = [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => [ - 'Authorization: token ' . $token, - 'Content-Type: application/json', - 'User-Agent: MokoStandards-Inventory', - 'Accept: application/vnd.github.v3+json', - ], - ]; - if ($method !== 'GET') { $opts[CURLOPT_CUSTOMREQUEST] = $method; } - if ($body !== null) { $opts[CURLOPT_POSTFIELDS] = json_encode($body); } - curl_setopt_array($ch, $opts); - $resp = (string) curl_exec($ch); - $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - return [$status, json_decode($resp, true) ?? []]; + global $_api; + try { + $result = match ($method) { + 'GET' => $_api->get("/{$path}"), + 'POST' => $_api->post("/{$path}", $body ?? []), + 'PATCH' => $_api->patch("/{$path}", $body ?? []), + 'PUT' => $_api->put("/{$path}", $body ?? []), + 'DELETE' => $_api->delete("/{$path}"), + default => throw new \RuntimeException("Unsupported method: {$method}"), + }; + return [200, $result]; + } catch (\Exception $e) { + return [500, ['message' => $e->getMessage()]]; + } } /** @@ -69,11 +72,17 @@ function ghApi(string $method, string $path, ?array $body, string $token): array */ function graphql(string $query, array $variables, string $token): array { + global $config; + $pf = isset($config) ? $config->getString('platform', 'gitea') : 'gitea'; + if ($pf !== 'github') { + return []; + } + $payload = json_encode(['query' => $query, 'variables' => $variables]); $ch = curl_init('https://api.github.com/graphql'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, - CURLOPT_POSTFIELDS => json_encode(['query' => $query, 'variables' => $variables]), + CURLOPT_POSTFIELDS => $payload, CURLOPT_HTTPHEADER => [ 'Authorization: bearer ' . $token, 'Content-Type: application/json', diff --git a/maintenance/rotate_secrets.php b/maintenance/rotate_secrets.php index 50fabcb..574a70c 100644 --- a/maintenance/rotate_secrets.php +++ b/maintenance/rotate_secrets.php @@ -40,11 +40,17 @@ if (!$repoName && !$allMode) { exit(2); } -$token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN'); -if (empty($token)) { - fwrite(STDERR, "GH_TOKEN or GITHUB_TOKEN not set\n"); +$config = \MokoEnterprise\Config::load(); +try { + $_adapter = \MokoEnterprise\PlatformAdapterFactory::create($config); + $_api = $_adapter->getApiClient(); +} catch (\Exception $e) { + fwrite(STDERR, "Platform init failed: " . $e->getMessage() . "\n"); exit(1); } +$token = $config->getString('platform', 'gitea') === 'gitea' + ? $config->getString('gitea.token', '') + : $config->getString('github.token', ''); $ALWAYS_EXCLUDE = ['MokoStandards', '.github-private']; @@ -61,25 +67,23 @@ $ENVS = [ */ function ghApi(string $method, string $path, ?array $body, string $token): array { - $ch = curl_init("https://api.github.com/{$path}"); - $opts = [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => [ - 'Authorization: token ' . $token, - 'Content-Type: application/json', - 'User-Agent: MokoStandards-SecretAudit', - 'Accept: application/vnd.github.v3+json', - ], - ]; - if ($method !== 'GET') { $opts[CURLOPT_CUSTOMREQUEST] = $method; } - if ($body !== null) { $opts[CURLOPT_POSTFIELDS] = json_encode($body); } - curl_setopt_array($ch, $opts); - $resp = (string) curl_exec($ch); - $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - return [$status, json_decode($resp, true) ?? []]; + global $_api; + try { + $result = match ($method) { + 'GET' => $_api->get("/{$path}"), + 'POST' => $_api->post("/{$path}", $body ?? []), + 'PATCH' => $_api->patch("/{$path}", $body ?? []), + 'PUT' => $_api->put("/{$path}", $body ?? []), + 'DELETE' => $_api->delete("/{$path}"), + default => throw new \RuntimeException("Unsupported method: {$method}"), + }; + return [200, $result]; + } catch (\Exception $e) { + return [500, ['message' => $e->getMessage()]]; + } } + /** * Fetch all names from a paginated list endpoint. * diff --git a/maintenance/update_version_from_readme.php b/maintenance/update_version_from_readme.php index b5872a9..1027786 100644 --- a/maintenance/update_version_from_readme.php +++ b/maintenance/update_version_from_readme.php @@ -109,7 +109,7 @@ class UpdateVersionFromReadme extends CliFramework $remaining = $this->countRemainingMismatches($repoRoot, $version); if ($remaining > 0) { $this->log("⚠ {$remaining} version reference(s) could not be auto-updated"); - $this->createGitHubIssue($repo, $version, $remaining); + $this->createDriftIssue($repo, $version, $remaining); } } @@ -408,16 +408,19 @@ class UpdateVersionFromReadme extends CliFramework * @param string $version Expected version * @param int $remaining Number of remaining mismatches */ - private function createGitHubIssue(string $repo, string $version, int $remaining): void + private function createDriftIssue(string $repo, string $version, int $remaining): void { - $token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN'); - if (empty($token)) { - $this->error('GH_TOKEN or GITHUB_TOKEN required to create issue'); - return; + if (!isset($this->apiClient)) { + $config = \MokoEnterprise\Config::load(); + try { + $adapter = \MokoEnterprise\PlatformAdapterFactory::create($config); + $this->apiClient = $adapter->getApiClient(); + } catch (\Exception $e) { + $this->error('Platform initialization failed: ' . $e->getMessage()); + return; + } } - $this->apiClient ??= new ApiClient($token, ['base_url' => 'https://api.github.com']); - $title = "⚠️ Version drift: {$remaining} file(s) not updated to {$version}"; $labels = ['version-drift', 'maintenance', 'type: chore', 'automation']; $body = implode("\n", [ diff --git a/release/generate_dolibarr_version_txt.php b/release/generate_dolibarr_version_txt.php index 53d835e..7b852bf 100644 --- a/release/generate_dolibarr_version_txt.php +++ b/release/generate_dolibarr_version_txt.php @@ -310,13 +310,9 @@ class GenerateDolibarrVersionTxt extends CLIApp private function initApi(): bool { $config = Config::load(); - $token = $config->getString('github.token', ''); - if (empty($token)) { - $this->log('❌ GitHub token not configured. Set GH_TOKEN or run: gh auth login', 'ERROR'); - return false; - } try { - $this->api = new ApiClient('https://api.github.com', $token); + $this->adapter = \MokoEnterprise\PlatformAdapterFactory::create($config); + $this->api = $this->adapter->getApiClient(); return true; } catch (\Exception $e) { $this->log('❌ API init failed: ' . $e->getMessage(), 'ERROR'); diff --git a/release/generate_joomla_update_xml.php b/release/generate_joomla_update_xml.php index 5de8f36..b699487 100644 --- a/release/generate_joomla_update_xml.php +++ b/release/generate_joomla_update_xml.php @@ -532,13 +532,9 @@ XML; private function initApi(): bool { $config = Config::load(); - $token = $config->getString('github.token', ''); - if (empty($token)) { - $this->log('❌ GitHub token not configured. Set GH_TOKEN or run: gh auth login', 'ERROR'); - return false; - } try { - $this->api = new ApiClient('https://api.github.com', $token); + $this->adapter = \MokoEnterprise\PlatformAdapterFactory::create($config); + $this->api = $this->adapter->getApiClient(); return true; } catch (\Exception $e) { $this->log('❌ API init failed: ' . $e->getMessage(), 'ERROR'); diff --git a/validate/check_composer_deps.php b/validate/check_composer_deps.php index 055ef65..9cd8610 100644 --- a/validate/check_composer_deps.php +++ b/validate/check_composer_deps.php @@ -38,11 +38,17 @@ if (!$repoName && !$allMode) { exit(2); } -$token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN'); -if (empty($token)) { - fwrite(STDERR, "GH_TOKEN or GITHUB_TOKEN not set\n"); +$config = \MokoEnterprise\Config::load(); +try { + $_adapter = \MokoEnterprise\PlatformAdapterFactory::create($config); + $_api = $_adapter->getApiClient(); +} catch (\Exception $e) { + fwrite(STDERR, "Platform init failed: " . $e->getMessage() . "\n"); exit(1); } +$token = $config->getString('platform', 'gitea') === 'gitea' + ? $config->getString('gitea.token', '') + : $config->getString('github.token', ''); $EXPECTED_VERSION = '04.02.30'; $EXPECTED_DEP = "dev-version/{$EXPECTED_VERSION}"; @@ -56,19 +62,13 @@ $ALWAYS_EXCLUDE = ['MokoStandards', '.github-private']; */ function apiGet(string $path, string $token): array { - $ch = curl_init("https://api.github.com/{$path}"); - curl_setopt_array($ch, [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => [ - 'Authorization: token ' . $token, - 'User-Agent: MokoStandards-ComposerCheck', - 'Accept: application/vnd.github.v3+json', - ], - ]); - $body = (string) curl_exec($ch); - $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - return [$status, json_decode($body, true) ?? []]; + global $_api; + try { + $result = $_api->get("/{$path}"); + return [200, $result]; + } catch (\Exception $e) { + return [500, ['message' => $e->getMessage()]]; + } } /** diff --git a/validate/check_repo_health.php b/validate/check_repo_health.php index 4a51770..5d44601 100755 --- a/validate/check_repo_health.php +++ b/validate/check_repo_health.php @@ -44,6 +44,7 @@ class RepoHealthChecker extends CliFramework private MetricsCollector $metrics; private PluginFactory $pluginFactory; private ?object $projectPlugin = null; + private string $apiBaseUrl = 'https://git.mokoconsulting.tech/api/v1'; private array $results = [ 'categories' => [], @@ -67,11 +68,18 @@ class RepoHealthChecker extends CliFramework protected function initialize(): void { parent::initialize(); - + $this->logger = new AuditLogger('repo_health_checker'); $this->metrics = new MetricsCollector(); $this->pluginFactory = new PluginFactory($this->logger, $this->metrics); - + + // Resolve API base URL from platform config + $config = \MokoEnterprise\Config::load(); + $platform = $config->getString('platform', 'gitea'); + $this->apiBaseUrl = $platform === 'github' + ? 'https://api.github.com' + : rtrim($config->getString('gitea.url', 'https://git.mokoconsulting.tech'), '/') . '/api/v1'; + $this->log('Repository health checker initialized with plugin system'); } @@ -408,7 +416,7 @@ class RepoHealthChecker extends CliFramework */ private function fetchRulesets(string $repo, string $token): array { - $url = "https://api.github.com/repos/{$repo}/rulesets?per_page=100&includes_parents=true"; + $url = "{$this->apiBaseUrl}/repos/{$repo}/rulesets?per_page=100&includes_parents=true"; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, @@ -555,7 +563,7 @@ class RepoHealthChecker extends CliFramework */ private function githubVarExists(string $resourcePath, string $token): bool { - $url = "https://api.github.com/{$resourcePath}"; + $url = "{$this->apiBaseUrl}/{$resourcePath}"; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, @@ -592,7 +600,7 @@ class RepoHealthChecker extends CliFramework $perPage = 100; do { - $url = "https://api.github.com/{$resourcePath}?per_page={$perPage}&page={$page}"; + $url = "{$this->apiBaseUrl}/{$resourcePath}?per_page={$perPage}&page={$page}"; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, diff --git a/validate/scan_drift.php b/validate/scan_drift.php index c400030..4d383e7 100755 --- a/validate/scan_drift.php +++ b/validate/scan_drift.php @@ -62,15 +62,16 @@ class DriftScanner extends CliFramework $this->logger = new AuditLogger('drift_scanner'); $this->metrics = new MetricsCollector(); - // Initialize API client - $token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN'); - if (empty($token)) { - $this->error("GH_TOKEN or GITHUB_TOKEN environment variable required"); + // Initialize API client via platform adapter + $config = \MokoEnterprise\Config::load(); + try { + $this->adapter = \MokoEnterprise\PlatformAdapterFactory::create($config); + $this->apiClient = $this->adapter->getApiClient(); + } catch (\Exception $e) { + $this->error("Platform initialization failed: " . $e->getMessage()); exit(1); } - $this->apiClient = new ApiClient($token, ['base_url' => 'https://api.github.com']); - $this->log("Standards Drift Scanner v" . self::VERSION); }