forked from heavy-duty/stoke
feat: extract publishable changelog sections
This commit is contained in:
parent
1aa6dc26a1
commit
e3f4703e13
2 changed files with 75 additions and 2 deletions
73
scripts/changelog-section.sh
Executable file
73
scripts/changelog-section.sh
Executable file
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vendored from heavy-duty/ceremony 0.6.3:
|
||||||
|
# lib/changelog.sh (changelog_section + changelog_section_problem)
|
||||||
|
# bin/changelog-section
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
changelog_section() {
|
||||||
|
awk -v ver="$2" '
|
||||||
|
/^## / { if (found) exit; found = ($2 == ver); next }
|
||||||
|
found && !body && /^[[:space:]]*$/ { next }
|
||||||
|
found { body = 1; print }
|
||||||
|
' "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
changelog_section_problem() {
|
||||||
|
local file="$1" ver="$2" notes problem
|
||||||
|
|
||||||
|
if ! awk -v ver="$ver" '/^## / && $2 == ver { found = 1; exit } END { exit !found }' "$file"; then
|
||||||
|
printf "no section for '%s'\n" "$ver"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$ver" = "Unreleased" ] && return 0
|
||||||
|
|
||||||
|
notes="$(changelog_section "$file" "$ver")"
|
||||||
|
if ! printf '%s\n' "$notes" | awk '/^[[:space:]]*[-*][[:space:]]/ { found = 1; exit } END { exit !found }'; then
|
||||||
|
printf "section '%s' has no entries — a heading is not an entry\n" "$ver"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
problem="$(
|
||||||
|
printf '%s\n' "$notes" | awk '
|
||||||
|
/^### / {
|
||||||
|
if (heading != "" && !entry) {
|
||||||
|
reported = 1
|
||||||
|
print heading
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
heading = $0
|
||||||
|
entry = 0
|
||||||
|
next
|
||||||
|
}
|
||||||
|
heading != "" && /^[[:space:]]*[-*][[:space:]]/ { entry = 1 }
|
||||||
|
END {
|
||||||
|
if (!reported && heading != "" && !entry) print heading
|
||||||
|
}
|
||||||
|
'
|
||||||
|
)"
|
||||||
|
if [ -n "$problem" ]; then
|
||||||
|
printf "section '%s' has an empty heading: '%s'\n" "$ver" "$problem"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ver="${1:-}"
|
||||||
|
changelog="${2:-CHANGELOG.md}"
|
||||||
|
if [ -z "$ver" ]; then
|
||||||
|
echo "usage: changelog-section.sh <version> [<changelog>]" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
[ -f "$changelog" ] || {
|
||||||
|
echo "changelog-section: no such file: $changelog" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! diagnosis="$(changelog_section_problem "$changelog" "$ver")"; then
|
||||||
|
echo "changelog-section: $changelog has no publishable section for '$ver'" >&2
|
||||||
|
printf 'changelog-section: %s\n' "$diagnosis" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
notes="$(changelog_section "$changelog" "$ver")"
|
||||||
|
printf '%s\n' "$notes"
|
||||||
|
|
@ -48,7 +48,7 @@ test('heading without a list entry is rejected as empty', () => {
|
||||||
|
|
||||||
assert.equal(result.status, 1);
|
assert.equal(result.status, 1);
|
||||||
assert.equal(result.stdout, '');
|
assert.equal(result.stdout, '');
|
||||||
assert.match(result.stderr, /section for '2\.0\.0' has no changelog entries/);
|
assert.match(result.stderr, /section '2\.0\.0' has no entries/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ test('extraction stops before the next version heading', () => {
|
||||||
const result = extract('2.0.0', changelog);
|
const result = extract('2.0.0', changelog);
|
||||||
|
|
||||||
assert.equal(result.status, 0, result.stderr);
|
assert.equal(result.status, 0, result.stderr);
|
||||||
assert.equal(result.stdout, '### Added\n\n- Current change.\n\n');
|
assert.equal(result.stdout, '### Added\n\n- Current change.\n');
|
||||||
assert.doesNotMatch(result.stdout, /Older change/);
|
assert.doesNotMatch(result.stdout, /Older change/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue