Update verify_changelog.sh
This commit is contained in:
@@ -1,71 +1,66 @@
|
|||||||
<?php
|
#!/usr/bin/env bash
|
||||||
/**
|
#
|
||||||
* verify_changelog.php
|
# Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
*
|
#
|
||||||
* Verifies that CHANGELOG.md is compliant with basic release governance rules.
|
# This file is part of a Moko Consulting project.
|
||||||
*
|
#
|
||||||
* Enforced rules
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
* - CHANGELOG.md must exist at repository root.
|
#
|
||||||
* - File must not contain unresolved placeholders such as "UNRELEASED" or "TBD".
|
# FILE INFORMATION
|
||||||
* - Headings must follow semantic version format: ## [NN.NN.NN]
|
# DEFGROUP: MokoStandards
|
||||||
* - The highest version must appear first.
|
# INGROUP: Tooling.Changelog
|
||||||
*
|
# FILE: verify_changelog.sh
|
||||||
* Intended usage
|
# BRIEF: Validate CHANGELOG.md governance rules for CI enforcement
|
||||||
* - CI validation step (read-only).
|
#
|
||||||
* - Does not modify files.
|
# PURPOSE:
|
||||||
*
|
# Validate that CHANGELOG.md contains only released, properly ordered entries and complies with MokoStandards governance rules.
|
||||||
* Exit codes
|
|
||||||
* - 0: Changelog is valid
|
|
||||||
* - 1: Validation failure
|
|
||||||
*/
|
|
||||||
|
|
||||||
$changelog = 'CHANGELOG.md';
|
set -euo pipefail
|
||||||
|
|
||||||
if (!file_exists($changelog)) {
|
CHANGELOG="CHANGELOG.md"
|
||||||
fwrite(STDERR, "ERROR: CHANGELOG.md not found at repository root\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = file_get_contents($changelog);
|
if [ ! -f "$CHANGELOG" ]; then
|
||||||
if ($content === false) {
|
echo "ERROR: CHANGELOG.md not found at repository root" >&2
|
||||||
fwrite(STDERR, "ERROR: Unable to read CHANGELOG.md\n");
|
exit 1
|
||||||
exit(1);
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
$errors = [];
|
CONTENT="$(cat "$CHANGELOG")"
|
||||||
|
|
||||||
// Rule: no unresolved placeholders
|
if echo "$CONTENT" | grep -Eiq '^##[[:space:]]*\[?TODO\]?'; then
|
||||||
$placeholders = ['UNRELEASED', 'TBD', 'TO DO', 'TODO'];
|
echo "ERROR: TODO section detected in CHANGELOG.md." >&2
|
||||||
foreach ($placeholders as $token) {
|
echo "CHANGELOG.md must contain released versions only." >&2
|
||||||
if (stripos($content, $token) !== false) {
|
echo "Move all TODO items to TODO.md and remove the section from CHANGELOG.md." >&2
|
||||||
$errors[] = "Unresolved placeholder detected: {$token}";
|
exit 1
|
||||||
}
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
// Rule: extract version headings
|
if echo "$CONTENT" | grep -Eiq 'UNRELEASED'; then
|
||||||
preg_match_all('/^## \[([0-9]+\.[0-9]+\.[0-9]+)\]/m', $content, $matches);
|
echo "ERROR: UNRELEASED placeholder detected in CHANGELOG.md." >&2
|
||||||
$versions = $matches[1] ?? [];
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if (empty($versions)) {
|
for token in "TBD" "TO BE DETERMINED" "PLACEHOLDER"; do
|
||||||
$errors[] = 'No version headings found (expected format: ## [NN.NN.NN])';
|
if echo "$CONTENT" | grep -Eiq "$token"; then
|
||||||
} else {
|
echo "ERROR: Unresolved placeholder detected: $token" >&2
|
||||||
// Rule: highest version first
|
exit 1
|
||||||
$sorted = $versions;
|
fi
|
||||||
usort($sorted, 'version_compare');
|
done
|
||||||
$sorted = array_reverse($sorted);
|
|
||||||
|
|
||||||
if ($versions !== $sorted) {
|
mapfile -t versions < <(
|
||||||
$errors[] = 'Versions are not ordered from newest to oldest';
|
grep -E '^## \[[0-9]+\.[0-9]+\.[0-9]+\] [0-9]{4}-[0-9]{2}-[0-9]{2}$' "$CHANGELOG" \
|
||||||
}
|
| sed -E 's/^## \[([0-9]+\.[0-9]+\.[0-9]+)\].*/\1/'
|
||||||
}
|
)
|
||||||
|
|
||||||
if (!empty($errors)) {
|
if [ "${#versions[@]}" -eq 0 ]; then
|
||||||
fwrite(STDERR, "CHANGELOG.md validation failed:\n");
|
echo "ERROR: No valid version headings found in CHANGELOG.md" >&2
|
||||||
foreach ($errors as $err) {
|
exit 1
|
||||||
fwrite(STDERR, " - {$err}\n");
|
fi
|
||||||
}
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "CHANGELOG.md validation passed\n";
|
sorted_versions="$(printf '%s\n' "${versions[@]}" | sort -Vr)"
|
||||||
exit(0);
|
|
||||||
|
if [ "$(printf '%s\n' "${versions[@]}")" != "$sorted_versions" ]; then
|
||||||
|
echo "ERROR: Versions are not ordered from newest to oldest" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "CHANGELOG.md validation passed"
|
||||||
|
exit 0
|
||||||
|
|||||||
Reference in New Issue
Block a user