Skip to content

Commit 09e09eb

Browse files
authored
chore: fix changelog validation to run on macOS (#1450)
Signed-off-by: Vincent Link <[email protected]>
1 parent 38acd07 commit 09e09eb

2 files changed

Lines changed: 86 additions & 60 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ None
101101

102102
### Breaking Changes
103103

104-
- **General**: Migrate from deprecated `v1.Endpoints` to `discoveryv1.EndpointSlices` ([#1297](https://github.com/kedacore/http-add-on/issues/1297)).
104+
- **General**: Migrate from deprecated `v1.Endpoints` to `discoveryv1.EndpointSlices` ([#1297](https://github.com/kedacore/http-add-on/issues/1297))
105105

106106
### New
107107

hack/validate-changelog.sh

Lines changed: 85 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,99 @@
1-
#!/bin/bash
1+
#!/usr/bin/env bash
2+
set -euo pipefail
23

34
SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
5+
CHANGELOG="${1:-$SCRIPT_ROOT/CHANGELOG.md}"
46

5-
# Define filename
6-
filename="$SCRIPT_ROOT/CHANGELOG.md"
7-
8-
# Check if file exists
9-
if [[ ! -f "$filename" ]]; then
10-
echo "Error: $filename does not exist."
7+
if [[ ! -f "$CHANGELOG" ]]; then
8+
echo "Error: $CHANGELOG not found" >&2
119
exit 1
1210
fi
1311

14-
# Storing the version to be checked
15-
mapfile -t versions < <(awk '/## History/{flag=1;next}/## /{flag=0}flag' "$filename" | grep -o '\[[^]]*\]' | grep -v "v1." | sed 's/[][]//g')
16-
17-
# Define a function to extract and sort sections
18-
function extract_and_check() {
19-
local section=$1
20-
local content_block=$2
21-
local content=$(awk "/### $section/{flag=1;next}/### /{flag=0}flag" <<< "$content_block" | grep '^- \*\*')
22-
23-
# Skip if content does not exist
24-
if [[ -z "$content" ]]; then
25-
return
26-
fi
27-
28-
# Separate and sort the **General**: lines
29-
local sorted_general_lines=$(echo "$content" | grep '^- \*\*General\*\*:' | LC_ALL=en_US sort --ignore-case)
30-
31-
# Sort the remaining lines
32-
local sorted_content=$(echo "$content" | grep -v '^- \*\*General\*\*:' | LC_ALL=en_US sort --ignore-case)
33-
34-
# Check if sorted_general_lines is not empty, then concatenate
35-
if [[ -n "$sorted_general_lines" ]]; then
36-
sorted_content=$(printf "%s\n%s" "$sorted_general_lines" "$sorted_content")
37-
fi
38-
39-
# Check pattern and throw error if wrong pattern found
40-
while IFS= read -r line; do
41-
echo "Error: Wrong pattern found in section: $section , line: $line"
42-
exit 1
43-
done < <(grep -Pv '^(-\s\*\*[^*]+\*\*: .*\(\[#([\d|TODO]+)\]\(https:\/\/github\.com\/kedacore\/(http-add-on|charts|governance)\/(pull|issues|discussions)\/\2\)(?:\|\[#(\d+)\]\(https:\/\/github\.com\/kedacore\/(http-add-on|charts|governance)\/(pull|issues|discussions)\/(?:\5)\)){0,}\))$' <<< "$content")
44-
45-
if [ "$content" != "$sorted_content" ]; then
46-
echo "Error: Section: $section is not sorted correctly. Correct order:"
47-
echo "$sorted_content"
48-
exit 1
49-
fi
50-
}
12+
# Format: - **Component**: description ([#NUM](URL)|...) where NUM matches URL path
13+
LINK='\[#([0-9]+|TODO)\]\(https://github\.com/kedacore/[^/]+/(pull|issues|discussions)/([0-9]+|TODO)\)'
14+
LINE_PATTERN="^- \\*\\*[^*]+\\*\\*: .+\\($LINK(\\|$LINK)*\\)\$"
5115

16+
SECTIONS=("Breaking Changes" "New" "Improvements" "Fixes" "Deprecations" "Other")
5217

53-
# Extract release sections, including "Unreleased", and check them
54-
for version in "${versions[@]}"; do
55-
release_content=$(awk "/## $version/{flag=1;next}/## v[0-9\.]+/{flag=0}flag" "$filename")
18+
errors=0
5619

20+
# Get content between two markdown headers
21+
get_section() {
22+
local version="$1"
23+
local section="$2"
24+
# Match until next ## header (v* or Unreleased) or EOF
25+
sed -n "/^## $version\$/,/^## [vU]/p" "$CHANGELOG" | sed -n "/^### $section\$/,/^### /p" | grep '^- \*\*' || true
26+
}
5727

58-
if [[ -z "$release_content" ]]; then
59-
echo "No content found for $version Skipping."
60-
continue
61-
fi
28+
# Validate [#NUM] matches URL path number (skips TODO links)
29+
validate_link_numbers() {
30+
local line="$1" link link_num url_num valid=0
31+
for link in $(echo "$line" | grep -oE '\[#[0-9]+\]\([^)]+\)'); do
32+
link_num=$(echo "$link" | grep -oE '\[#[0-9]+\]' | tr -d '[]#')
33+
url_num=$(echo "$link" | grep -oE '(pull|issues|discussions)/[0-9]+' | grep -oE '[0-9]+$' || true)
34+
if [[ -z "$url_num" ]]; then
35+
echo "could not extract URL number from: $link" >&2
36+
valid=1
37+
elif [[ "$link_num" != "$url_num" ]]; then
38+
echo "link [#$link_num] does not match URL number $url_num" >&2
39+
valid=1
40+
fi
41+
done
42+
return $valid
43+
}
6244

63-
echo "Checking section: $version"
45+
# Sort: General lines first, then rest alphabetically
46+
sort_section() {
47+
local input general_lines other_lines
48+
input=$(cat)
49+
general_lines=$(echo "$input" | grep '^- \*\*General\*\*:' | LC_ALL=C sort -f || true)
50+
other_lines=$(echo "$input" | grep -v '^- \*\*General\*\*:' | LC_ALL=C sort -f || true)
51+
# Output non-empty parts, avoiding extra newlines
52+
[[ -n "$general_lines" ]] && echo "$general_lines"
53+
[[ -n "$other_lines" ]] && echo "$other_lines"
54+
true
55+
}
6456

65-
# Separate content into different sections and check sorting for each release
66-
extract_and_check "New" "$release_content"
67-
extract_and_check "Experimental" "$release_content"
68-
extract_and_check "Improvements" "$release_content"
69-
extract_and_check "Fixes" "$release_content"
70-
extract_and_check "Deprecations" "$release_content"
71-
extract_and_check "Other" "$release_content"
57+
# Get versions from History section
58+
versions=$(sed -n '/^## History/,/^## /p' "$CHANGELOG" | grep -o '\[[^]]*\]' | tr -d '[]' || true)
7259

60+
if [[ -z "$versions" ]]; then
61+
echo "Error: No versions found in ## History section" >&2
62+
exit 1
63+
fi
64+
65+
for version in $versions; do
66+
echo "Checking: $version"
67+
68+
for section in "${SECTIONS[@]}"; do
69+
content=$(get_section "$version" "$section")
70+
[[ -z "$content" ]] && continue
71+
72+
# Check format and link numbers
73+
while IFS= read -r line; do
74+
if ! echo "$line" | grep -qE "$LINE_PATTERN"; then
75+
echo " Error: [$section] Invalid format: $line" >&2
76+
errors=1
77+
elif ! validate_link_numbers "$line"; then
78+
echo " Error: [$section] $line" >&2
79+
errors=1
80+
fi
81+
done <<< "$content"
82+
83+
# Check sorting
84+
sorted=$(echo "$content" | sort_section)
85+
if [[ "$content" != "$sorted" ]]; then
86+
echo " Error: [$section] Not sorted. Expected:" >&2
87+
echo "$sorted" | sed 's/^/ /' >&2
88+
errors=1
89+
fi
90+
done
7391
done
92+
93+
if [[ $errors -eq 0 ]]; then
94+
echo "OK"
95+
else
96+
echo "Validation failed" >&2
97+
fi
98+
99+
exit $errors

0 commit comments

Comments
 (0)