beed1e628a
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 4s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m18s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
- cli/changelog_prune.php: keeps [Unreleased] + last N versioned entries (default 5) - Register changelog:promote and changelog:prune in bin/moko COMMAND_MAP - auto-release.yml Step 4b: promote [Unreleased] to version, then prune old entries Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
135 lines
3.6 KiB
PHP
135 lines
3.6 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/changelog_prune.php
|
|
* BRIEF: Prune old CHANGELOG.md entries — keeps [Unreleased] + last N releases
|
|
*
|
|
* Usage:
|
|
* php changelog_prune.php --path /repo --keep 5
|
|
* php changelog_prune.php --path /repo --keep 3 --dry-run
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
$path = '.';
|
|
$keep = 5;
|
|
$dryRun = false;
|
|
|
|
foreach ($argv as $i => $arg) {
|
|
if ($arg === '--path' && isset($argv[$i + 1])) $path = $argv[$i + 1];
|
|
if ($arg === '--keep' && isset($argv[$i + 1])) $keep = (int)$argv[$i + 1];
|
|
if ($arg === '--dry-run') $dryRun = true;
|
|
if ($arg === '--help') {
|
|
echo "changelog_prune — Keep [Unreleased] + last N versioned entries\n\n";
|
|
echo "Usage: php changelog_prune.php --path . --keep 5 [--dry-run]\n\n";
|
|
echo "Options:\n";
|
|
echo " --path Repository path (default: .)\n";
|
|
echo " --keep Number of versioned releases to keep (default: 5)\n";
|
|
echo " --dry-run Preview without writing\n";
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
$changelog = realpath($path) . '/CHANGELOG.md';
|
|
if (!file_exists($changelog)) {
|
|
fwrite(STDERR, "No CHANGELOG.md found at {$path}\n");
|
|
exit(1);
|
|
}
|
|
|
|
$content = file_get_contents($changelog);
|
|
$lines = explode("\n", $content);
|
|
|
|
// Split into sections by ## headings
|
|
$sections = [];
|
|
$current = [];
|
|
$currentHeading = null;
|
|
|
|
foreach ($lines as $line) {
|
|
if (preg_match('/^## /', $line)) {
|
|
if ($currentHeading !== null) {
|
|
$sections[] = ['heading' => $currentHeading, 'lines' => $current];
|
|
}
|
|
$currentHeading = $line;
|
|
$current = [$line];
|
|
} else {
|
|
$current[] = $line;
|
|
}
|
|
}
|
|
if ($currentHeading !== null) {
|
|
$sections[] = ['heading' => $currentHeading, 'lines' => $current];
|
|
}
|
|
|
|
// Find the header (everything before the first ## section)
|
|
$header = [];
|
|
$contentLines = explode("\n", $content);
|
|
foreach ($contentLines as $line) {
|
|
if (preg_match('/^## /', $line)) {
|
|
break;
|
|
}
|
|
$header[] = $line;
|
|
}
|
|
|
|
// Separate [Unreleased] from versioned sections
|
|
$unreleased = null;
|
|
$versioned = [];
|
|
|
|
foreach ($sections as $section) {
|
|
if (preg_match('/\[Unreleased\]/i', $section['heading'])) {
|
|
$unreleased = $section;
|
|
} else {
|
|
$versioned[] = $section;
|
|
}
|
|
}
|
|
|
|
$totalVersioned = count($versioned);
|
|
$pruned = $totalVersioned - $keep;
|
|
|
|
if ($pruned <= 0) {
|
|
echo "CHANGELOG has {$totalVersioned} versioned entries — nothing to prune (keeping {$keep})\n";
|
|
exit(0);
|
|
}
|
|
|
|
// Keep only the first N versioned sections
|
|
$keptVersioned = array_slice($versioned, 0, $keep);
|
|
$droppedVersioned = array_slice($versioned, $keep);
|
|
|
|
// Report
|
|
echo "CHANGELOG: {$totalVersioned} versioned entries found\n";
|
|
echo " Keeping: {$keep} most recent\n";
|
|
echo " Pruning: {$pruned} old entries\n";
|
|
|
|
foreach ($droppedVersioned as $section) {
|
|
$heading = trim($section['heading']);
|
|
echo " - {$heading}\n";
|
|
}
|
|
|
|
if ($dryRun) {
|
|
echo "\n(dry-run) No changes written\n";
|
|
exit(0);
|
|
}
|
|
|
|
// Rebuild the file
|
|
$output = implode("\n", $header);
|
|
|
|
if ($unreleased !== null) {
|
|
$output .= implode("\n", $unreleased['lines']) . "\n";
|
|
}
|
|
|
|
foreach ($keptVersioned as $section) {
|
|
$output .= implode("\n", $section['lines']) . "\n";
|
|
}
|
|
|
|
// Clean up excessive blank lines at end
|
|
$output = rtrim($output) . "\n";
|
|
|
|
file_put_contents($changelog, $output);
|
|
echo "\nCHANGELOG pruned: removed {$pruned} old entries\n";
|
|
exit(0);
|