diff --git a/lib/changelog.sh b/lib/changelog.sh index a333819..974b4a8 100644 --- a/lib/changelog.sh +++ b/lib/changelog.sh @@ -215,6 +215,13 @@ changelog_shape_problem() { local sentinel="$dir/shape" declared="" if [ -f "$sentinel" ]; then + # The one-line contract is checked on the file itself: command + # substitution strips every trailing newline, so the captured word + # cannot tell 'grouped' from 'grouped' plus blank lines. + if [ "$(wc -l <"$sentinel")" -gt 1 ]; then + printf "'%s' declares neither shape — its whole content must be 'flat' or 'grouped', one line\n" "$sentinel" + return 1 + fi declared="$(cat "$sentinel")" case "$declared" in flat | grouped) ;; diff --git a/test/changelog-armed.test.sh b/test/changelog-armed.test.sh index fdb3700..66c0f88 100644 --- a/test/changelog-armed.test.sh +++ b/test/changelog-armed.test.sh @@ -404,6 +404,11 @@ check "fragment mode: a malformed sentinel is refused, file named" 1 \ "'changelog.d/shape' declares neither shape" \ in_tree fragments-dev-flip +printf 'grouped\n\n' >"$TMP/fragments-dev-flip/changelog.d/shape" +check "fragment mode: a sentinel with a trailing blank line is refused, file named" 1 \ + "'changelog.d/shape' declares neither shape" \ + in_tree fragments-dev-flip + fragment_tree fragments-dev-no-published 1.2.4-dev <<'EOF' # Changelog diff --git a/test/changelog.test.sh b/test/changelog.test.sh index 57f7b74..0c9979d 100755 --- a/test/changelog.test.sh +++ b/test/changelog.test.sh @@ -540,6 +540,16 @@ printf 'grouped\nflat\n' >"$SHAPE_DIR/shape" check "shape: a two-line sentinel is refused" 1 \ "'$SHAPE_DIR/shape' declares neither shape" \ changelog_shape_problem "$SHAPE_CHANGELOG" "$SHAPE_DIR" +# Trailing blank lines are the case command substitution launders away: the +# captured word is a clean 'grouped', only the file's line count still knows. +printf 'grouped\n\n' >"$SHAPE_DIR/shape" +check "shape: 'grouped' with a trailing blank line is refused, file named" 1 \ + "'$SHAPE_DIR/shape' declares neither shape" \ + changelog_shape_problem "$SHAPE_CHANGELOG" "$SHAPE_DIR" +printf 'flat\n\n' >"$SHAPE_DIR/shape" +check "shape: 'flat' with a trailing blank line is refused, file named" 1 \ + "'$SHAPE_DIR/shape' declares neither shape" \ + changelog_shape_problem "$SHAPE_CHANGELOG" "$SHAPE_DIR" # The sentinel is not a fragment (#182 D3): the *.md glob is the mechanism, # but the assertion is on the list itself, so a glob change cannot silently