07ea171af9
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 1s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 43s
New CLI tools: - manifest_element.php — extract element/type/prefix from any platform manifest - release_create.php — create/overwrite Gitea releases with proper naming - release_package.php — build ZIP+tar.gz, SHA-256, upload assets - release_promote.php — promote releases between channels (dev→RC→stable) - version_reset_dev.php — reset platform version on dev branch after release Updated CLI tools: - version_bump.php — now writes to manifests, Dolibarr mod, composer.json (not just README) - release_cascade.php — added --version for version-aware deletion of stale releases - release_validate.php — auto-detect platform, --github-output, source dir check Workflow changes (auto-release.yml): - Draft PR to main → auto-promote highest pre-release to RC - Merged PR to main → promote RC to stable (skip rebuild when RC exists) - Removed paths filter for Go/Node/generic repo compatibility - Fixed cascade --api-base parameter bug Workflow changes (pre-release.yml): - Auto-trigger development pre-release on feature branch merge to dev - Removed paths filter Infrastructure: - RepositorySynchronizer: fixed template repo names, .mokogitea/workflows path, universal workflow cascade (Template-Generic → other templates) - bulk_sync.php: syncs universal workflows to templates before repo sync - PHPDoc added to 4 classes missing class-level docs - Version bump 09.00.00 → 09.01.00 Closes #152 #153 #154 #155 #156 #157 #158 #159 #161 #162 Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
320 lines
10 KiB
PHP
320 lines
10 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/version_reset_dev.php
|
|
* BRIEF: Reset platform version to 'development' on a branch via Gitea API
|
|
*
|
|
* Usage:
|
|
* php version_reset_dev.php --token TOKEN --api-base URL
|
|
* php version_reset_dev.php --token TOKEN --api-base URL --branch dev
|
|
* php version_reset_dev.php --token TOKEN --api-base URL --platform dolibarr
|
|
* php version_reset_dev.php --token TOKEN --api-base URL --path /repo/root
|
|
*
|
|
* This replaces the inline curl+python3+sed block previously used in
|
|
* auto-release.yml to reset Dolibarr's $this->version on the dev branch
|
|
* after a stable release.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
// ── Argument parsing ─────────────────────────────────────────────────────────
|
|
|
|
$token = null;
|
|
$apiBase = null;
|
|
$branch = 'dev';
|
|
$platform = null;
|
|
$path = null;
|
|
|
|
foreach ($argv as $i => $arg) {
|
|
if ($arg === '--token' && isset($argv[$i + 1])) {
|
|
$token = $argv[$i + 1];
|
|
}
|
|
if ($arg === '--api-base' && isset($argv[$i + 1])) {
|
|
$apiBase = rtrim($argv[$i + 1], '/');
|
|
}
|
|
if ($arg === '--branch' && isset($argv[$i + 1])) {
|
|
$branch = $argv[$i + 1];
|
|
}
|
|
if ($arg === '--platform' && isset($argv[$i + 1])) {
|
|
$platform = $argv[$i + 1];
|
|
}
|
|
if ($arg === '--path' && isset($argv[$i + 1])) {
|
|
$path = $argv[$i + 1];
|
|
}
|
|
if ($arg === '--help' || $arg === '-h') {
|
|
printUsage();
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
// Allow token from environment
|
|
if ($token === null) {
|
|
$envToken = getenv('GA_TOKEN');
|
|
if ($envToken !== false && $envToken !== '') {
|
|
$token = $envToken;
|
|
}
|
|
}
|
|
if ($token === null) {
|
|
$envToken = getenv('GITEA_TOKEN');
|
|
if ($envToken !== false && $envToken !== '') {
|
|
$token = $envToken;
|
|
}
|
|
}
|
|
|
|
if ($token === null || $apiBase === null) {
|
|
fwrite(STDERR, "Error: --token and --api-base are required.\n\n");
|
|
printUsage();
|
|
exit(1);
|
|
}
|
|
|
|
// ── Platform detection ───────────────────────────────────────────────────────
|
|
|
|
if ($platform === null && $path !== null) {
|
|
$platform = detectPlatform($path);
|
|
if ($platform !== null) {
|
|
echo "Detected platform: {$platform}\n";
|
|
}
|
|
}
|
|
|
|
if ($platform === null) {
|
|
fwrite(STDERR, "Error: could not determine platform. Use --platform or --path.\n");
|
|
exit(1);
|
|
}
|
|
|
|
// ── Dispatch by platform ─────────────────────────────────────────────────────
|
|
|
|
$changed = 0;
|
|
|
|
if (in_array($platform, ['dolibarr', 'crm-module'], true)) {
|
|
$changed = 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";
|
|
exit(0);
|
|
|
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
// Helper functions
|
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
|
|
/**
|
|
* Print usage information to stdout.
|
|
*
|
|
* @return void
|
|
*/
|
|
function printUsage(): void
|
|
{
|
|
echo <<<'USAGE'
|
|
Reset platform version to 'development' on a branch via Gitea API.
|
|
|
|
Usage:
|
|
php version_reset_dev.php --token TOKEN --api-base URL [options]
|
|
|
|
Required:
|
|
--token TOKEN Gitea API token (also reads GA_TOKEN / GITEA_TOKEN env)
|
|
--api-base URL Gitea API base URL for the repo
|
|
e.g. https://git.mokoconsulting.tech/api/v1/repos/Org/Repo
|
|
|
|
Options:
|
|
--branch BRANCH Target branch (default: dev)
|
|
--platform TYPE Platform type: dolibarr, crm-module, joomla, waas-component
|
|
--path DIR Repo root for auto-detecting platform from manifest.xml
|
|
--help Show this help
|
|
|
|
USAGE;
|
|
}
|
|
|
|
/**
|
|
* Detect the platform type from a repo's .mokogitea/manifest.xml file.
|
|
*
|
|
* @param string $repoPath Path to the repository root
|
|
* @return string|null The detected platform, or null if detection fails
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Make a Gitea API call and return the decoded JSON response.
|
|
*
|
|
* @param string $url Full API URL
|
|
* @param string $token Gitea API token
|
|
* @param string $method HTTP method (GET, PUT, POST, DELETE)
|
|
* @param string|null $body JSON request body, or null for bodiless requests
|
|
* @return array<string, mixed>|null Decoded JSON response, or null on failure
|
|
*/
|
|
function giteaApiCall(string $url, string $token, string $method = 'GET', ?string $body = null): ?array
|
|
{
|
|
$ch = curl_init($url);
|
|
if ($ch === false) {
|
|
fwrite(STDERR, "Error: curl_init() failed for {$url}\n");
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Reset Dolibarr module version to 'development' on the target branch.
|
|
*
|
|
* Searches the repository tree for mod*.class.php files that contain
|
|
* `extends DolibarrModules`, then replaces `$this->version = '...'`
|
|
* with `$this->version = 'development'` via the Gitea file contents API.
|
|
*
|
|
* @param string $apiBase Gitea API base URL for the repo
|
|
* @param string $token Gitea API token
|
|
* @param string $branch Target branch name
|
|
* @return int Number of files modified
|
|
*/
|
|
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 = giteaApiCall($treeUrl, $token);
|
|
|
|
if ($tree === null || !isset($tree['tree']) || !is_array($tree['tree'])) {
|
|
fwrite(STDERR, "Error: could not read repository tree for branch '{$branch}'.\n");
|
|
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 = 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 = giteaApiCall($putUrl, $token, 'PUT', $putBody);
|
|
|
|
if ($result !== null) {
|
|
echo "Reset: {$filePath} -> \$this->version = 'development'\n";
|
|
$changed++;
|
|
} else {
|
|
fwrite(STDERR, "Error: failed to update {$filePath} on branch '{$branch}'.\n");
|
|
}
|
|
}
|
|
|
|
return $changed;
|
|
}
|