#!/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/branch_rename.php * VERSION: 09.21.00 * BRIEF: Rename a git branch via Gitea API (create new, update PR, delete old) * * Usage: * php branch_rename.php --from dev --to rc --token TOKEN --api-base URL [--pr 42] * php branch_rename.php --from dev --to rc --token TOKEN --api-base URL --pr 42 --dry-run */ declare(strict_types=1); $from = ''; $to = ''; $token = ''; $apiBase = ''; $prNum = ''; $dryRun = false; foreach ($argv as $i => $arg) { if ($arg === '--from' && isset($argv[$i + 1])) $from = $argv[$i + 1]; if ($arg === '--to' && isset($argv[$i + 1])) $to = $argv[$i + 1]; if ($arg === '--token' && isset($argv[$i + 1])) $token = $argv[$i + 1]; if ($arg === '--api-base' && isset($argv[$i + 1])) $apiBase = $argv[$i + 1]; if ($arg === '--pr' && isset($argv[$i + 1])) $prNum = $argv[$i + 1]; if ($arg === '--dry-run') $dryRun = true; } if (empty($from) || empty($to) || empty($token) || empty($apiBase)) { fwrite(STDERR, "Usage: branch_rename.php --from BRANCH --to BRANCH --token TOKEN --api-base URL [--pr NUM] [--dry-run]\n"); exit(1); } if ($from === $to) { echo "Source and target are the same ({$from}) — nothing to do\n"; exit(0); } $headers = [ "Authorization: token {$token}", 'Content-Type: application/json', 'Accept: application/json', ]; /** * Make an API request. */ function apiRequest(string $method, string $url, array $headers, ?array $body = null): array { $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_TIMEOUT => 30, ]); if ($body !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body)); } $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return [ 'code' => $httpCode, 'body' => json_decode($response ?: '{}', true) ?: [], ]; } // Step 1: Verify source branch exists echo "Checking source branch: {$from}\n"; $check = apiRequest('GET', "{$apiBase}/branches/{$from}", $headers); if ($check['code'] !== 200) { fwrite(STDERR, "Source branch '{$from}' not found (HTTP {$check['code']})\n"); exit(1); } // Step 2: Delete target branch if it already exists $targetCheck = apiRequest('GET', "{$apiBase}/branches/{$to}", $headers); if ($targetCheck['code'] === 200) { echo "Target branch '{$to}' already exists — deleting\n"; if (!$dryRun) { apiRequest('DELETE', "{$apiBase}/branches/{$to}", $headers); } } // Step 3: Create new branch from source echo "Creating branch: {$to} (from {$from})\n"; if (!$dryRun) { $create = apiRequest('POST', "{$apiBase}/branches", $headers, [ 'new_branch_name' => $to, 'old_branch_name' => $from, ]); if ($create['code'] < 200 || $create['code'] >= 300) { fwrite(STDERR, "Failed to create branch '{$to}': HTTP {$create['code']}\n"); fwrite(STDERR, json_encode($create['body']) . "\n"); exit(1); } } // Step 4: Update PR head branch if PR number provided if (!empty($prNum)) { echo "Updating PR #{$prNum} head branch: {$from} -> {$to}\n"; if (!$dryRun) { $update = apiRequest('PATCH', "{$apiBase}/pulls/{$prNum}", $headers, [ 'head' => $to, ]); if ($update['code'] < 200 || $update['code'] >= 300) { fwrite(STDERR, "Warning: Could not update PR head branch (HTTP {$update['code']})\n"); // Non-fatal — the PR may need manual update } } } // Step 5: Delete old source branch echo "Deleting old branch: {$from}\n"; if (!$dryRun) { $delete = apiRequest('DELETE', "{$apiBase}/branches/{$from}", $headers); if ($delete['code'] !== 204 && $delete['code'] !== 200) { fwrite(STDERR, "Warning: Could not delete old branch '{$from}' (HTTP {$delete['code']})\n"); // Non-fatal — branch protection may prevent deletion } } echo "Renamed: {$from} -> {$to}\n"; exit(0);