Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions BUILD.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ the following command to find the next unused rule identifier.
make next-rule-id
----

== Generate Changelog

To automatically generate changelog entries from git history using AI analysis,
use the following command. The script analyzes commits since the latest changelog
entry and generates properly formatted AsciiDoc entries for rule changes.

[source,bash]
----
make changelog
----

**Prerequisites:** The `zllm` command must be installed for this target to work.

== Generate Custom CSS

In order to generate custom CSS we have to use
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ DIRWORK := $(shell pwd -P)

.PHONY: all clean install lint format pull assets rules html pdf epub force
.PHONY: check check-rules check-rules-duplicates check-rules-incorrects
.PHONY: next-rule-id watch
.PHONY: next-rule-id watch changelog

all: clean html rules
clean:
Expand Down Expand Up @@ -51,6 +51,9 @@ next-rule-id:
"RULE_IDS=($$(grep -rh "^.*\[#[0-9]\{1,5\}.*$$" $(DIRCONTENTS) | sort -r))"; \
echo $$(($$(echo $${RULE_IDS[0]} | tr -d '\[' | tr -d '\]' | tr -d '#') + 1));

changelog:
$(DIRSCRIPTS)/changelog.sh --update

assets:
mkdir -p $(DIRBUILDS);
cp -r assets $(DIRBUILDS)/;
Expand Down
11 changes: 10 additions & 1 deletion chapters/changelog.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ to see a list of all changes.
[[rule-changes]]
== Rule Changes

* `2025-11-27`: clearly separate compatibility rules for input and output schemas in <<108>>. ^https://github.com/zalando/restful-api-guidelines/pull/851[#851]^
* `2025-11-27`: deprecate {x-extensible-enum} in favor of extensible enums using `examples` in <<112>>. ^https://github.com/zalando/restful-api-guidelines/pull/837[#837]^
* `2025-10-08`: fix mixup of rules 250 and 251 in compatibility guidance. ^https://github.com/zalando/restful-api-guidelines/pull/852[#852]^
* `2025-10-01`: upgrade to OpenAPI 3.1 as recommended version in <<101>>. ^https://github.com/zalando/restful-api-guidelines/pull/850[#850]^
* `2025-05-27`: clarify interaction between {GET-with-body} and pagination in <<148>> and <<161>>. ^https://github.com/zalando/restful-api-guidelines/pull/841[#841]^
* `2025-05-27`: allow proprietary headers for Transactions Checkout Platform in <<183>>. ^https://github.com/zalando/restful-api-guidelines/pull/843[#843]^
* `2025-04-15`: update RFC links in <<243>> to use RFC 9110. ^https://github.com/zalando/restful-api-guidelines/commit/acf0dc5bf5573ae7a5bad4895ffb809c8e6890e5[acf0dc5]^
* `2025-01-21`: clarify that status codes 502 and 504 should not be documented in <<243>>. ^https://github.com/zalando/restful-api-guidelines/commit/e6a4af821cac34f7ed3a4a7d1e83519a01368263[e6a4af8]^
* `2024-09-18`: improve <<189>> to use RFC 9754 timestamp format for Deprecation header. ^https://github.com/zalando/restful-api-guidelines/pull/848[#848]^
* `2024-06-27`: Clarified usage of {x-extensible-enum} for events in <<112>>. ^https://github.com/zalando/restful-api-guidelines/pull/807[#807]^
* `2024-06-25`: Relaxed naming convention for date/time properties in <<235>>. ^https://github.com/zalando/restful-api-guidelines/pull/811[#811]^
* `2024-06-11`: Linked <<127>> (duration / period) from <<238>>. ^https://github.com/zalando/restful-api-guidelines/pull/810[#810]^
Expand Down Expand Up @@ -71,7 +80,7 @@ to see a list of all changes.
* `2020-06-30`: add details to <<114>>
* `2020-05-19`: new sections about DELETE with query parameters and {DELETE-with-Body} in <<148>>.
* `2020-02-06`: new rule <<241>>
* `2020-02-05`: add Sunset header, clarify deprecation producedure (<<185>>, <<186>>, <<187>>, <<188>>, <<189>>, <<190>>, <<191>>)
* `2020-02-05`: add Sunset header, clarify deprecation procedure (<<185>>, <<186>>, <<187>>, <<188>>, <<189>>, <<190>>, <<191>>)
* `2020-01-21`: new rule <<240>> (as MUST, changed later to SHOULD)
* `2020-01-15`: change "Warning" to "Deprecation" header in <<189>>, <<190>>.
* `2019-10-10`: remove never-implemented rule "{MUST} Permissions on events must correspond to API permissions"
Expand Down
42 changes: 42 additions & 0 deletions scripts/changelog.prompt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Write a changelog highlighting ONLY the rule changes based on the git commit messages and diffs provided.
Formatting, infrastructure, or similar non-rule changes should be omitted.

The rule numbers should always be referenced using angle brackets. For example, rule 211 should be written as <<211>>.

At the end of every changelog row, you should add a link to the related Pull Request in AsciiDoc format, like so: ^https://github.com/zalando/restful-api-guidelines/pull/<PR_NUMBER>[#PR_NUMBER]^

If there is no relevant Pull Request, you should link to a commit in asciidoc format instead, like so: ^https://github.com/zalando/restful-api-guidelines/commit/<COMMIT_HASH>[SHORT_HASH]^

Example changelog:

* `2021-12-09`: event id must not change in retry situations when producers <<211>>.
* `2021-11-24`: restructuring of the document and some rules.
* `2021-10-18`: new rule <<244>>.
* `2021-10-12`: improve clarity on {PATCH} usage in rule <<148>>.
* `2021-08-24`: improve clarity on {PUT} usage in rule <<148>>.
* `2021-08-24`: only use codes registered via IANA in rule <<243>>.
* `2021-08-17`: update formats per OpenAPI 3.1 in <<238>>.
* `2021-06-22`: <<238>> changed from {SHOULD} to {MUST}; consistency for rules around standards for data.
* `2021-06-03`: <<104>> with clear distinction of OpenAPI security schemes, favoring `bearer` to `oauth2`.
* `2021-06-01`: resolve uncertainties around 'occurred_at' semantics of <<event-metadata, event metadata>>.
* `2021-05-25`: <<172>> with <<114, API endpoint versioning>> as only custom media type usage exception.
* `2021-05-05`: define usage on resource-ids in {PUT} and {POST} in <<148>>.
* `2021-04-29`: improve clarity of <<133>>.
* `2021-03-19`: clarity on <<167>>.
* `2021-03-15`: <<242>> changed from {SHOULD} to {MUST}; improve clarity around <<203, event ordering>>.
* `2021-03-19`: best practice section <<cursor-based-pagination>>
* `2021-02-16`: define how to reference models outside the api in <<234>>.
* `2021-02-15`: improve guideline <<176>> -- clients must be prepared to not receive problem return objects.
* `2021-01-19`: more details for {GET-with-Body} and {DELETE-with-Body} (<<148>>).
* `2020-09-29`: include models for headers to be included by reference in API definitions (<<183>>)
* `2020-09-08`: add exception for legacy host names to <<224>>
* `2020-08-25`: change <<240>> from {MUST} to {SHOULD}, explain exceptions
* `2020-08-25`: add exception for `self` to <<143>> and <<134>>.
* `2020-08-24`: change "{MUST} avoid trailing slashes" to <<136>>.
* `2020-08-20`: change <<183>> from {MUST} to {SHOULD}, mention gateway-specific headers (which are not part of the public API).
* `2020-06-30`: add details to <<114>>
* `2020-05-19`: new sections about DELETE with query parameters and {DELETE-with-Body} in <<148>>.
* `2020-02-06`: new rule <<241>>
* `2020-02-05`: add Sunset header, clarify deprecation procedure (<<185>>, <<186>>, <<187>>, <<188>>, <<189>>, <<190>>, <<191>>)
* `2020-01-21`: new rule <<240>> (as MUST, changed later to SHOULD)
* `2020-01-15`: change "Warning" to "Deprecation" header in <<189>>, <<190>>.
181 changes: 181 additions & 0 deletions scripts/changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#! /bin/bash

# Generate changelog entries from git history using AI analysis
# Usage: ./changelog.sh [OPTIONS] [YEAR|DATE]
#
# By default (no arguments):
# - Detects latest changelog entry date from chapters/changelog.adoc
# - Generates entries for commits since that date
# - Outputs filtered changelog entries only
#
# Options:
# --raw Show full AI analysis output instead of filtered entries
# --update Write new entries to chapters/changelog.adoc (prepend to rule-changes section)
# --since DATE Use explicit date (format: YYYY-MM-DD) instead of auto-detecting
# --year YEAR Generate for a specific year (format: YYYY)
#
# Examples:
# ./changelog.sh # Auto-detect and generate since last entry
# ./changelog.sh --raw # Auto-detect with full output
# ./changelog.sh --update # Auto-detect and update the changelog file
# ./changelog.sh --since 2025-01-01 # Generate since specific date
# ./changelog.sh --year 2025 # Generate for entire year 2025
# ./changelog.sh 2025 --raw # Legacy: year as positional argument with --raw

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
PROMPT_FILE="$SCRIPT_DIR/changelog.prompt"
CHANGELOG_FILE="$REPO_ROOT/chapters/changelog.adoc"

# Parse arguments
MODE="auto" # auto, year, since
PARAM=""
RAW_OUTPUT=false
UPDATE_FILE=false

# Handle legacy positional arguments first
if [[ ${#@} -gt 0 ]] && [[ "$1" =~ ^[0-9]{4}$ ]]; then
MODE="year"
PARAM="$1"
shift
fi

# Parse remaining options
while [[ ${#@} -gt 0 ]]; do
case "$1" in
--raw)
RAW_OUTPUT=true
;;
--update)
UPDATE_FILE=true
;;
--year)
MODE="year"
PARAM="${2:-}"
if [[ -z "$PARAM" ]]; then
echo "Error: --year requires a year argument (YYYY)" >&2
exit 1
fi
shift
;;
--since)
MODE="since"
PARAM="${2:-}"
if [[ -z "$PARAM" ]]; then
echo "Error: --since requires a date argument (YYYY-MM-DD)" >&2
exit 1
fi
shift
;;
*)
echo "Error: Unknown option: $1" >&2
exit 1
;;
esac
shift
done

# Check dependencies
if ! command -v zllm &> /dev/null; then
echo "Error: 'zllm' command not found. Please install zllm to use this script." >&2
exit 1
fi

if [[ ! -f "$PROMPT_FILE" ]]; then
echo "Error: Prompt file not found: $PROMPT_FILE" >&2
exit 1
fi

# Determine the date range for git log
cd "$REPO_ROOT"

case "$MODE" in
auto)
# Extract latest date from changelog.adoc
if [[ ! -f "$CHANGELOG_FILE" ]]; then
echo "Error: Changelog file not found: $CHANGELOG_FILE" >&2
exit 1
fi

# Look for first date entry after "== Rule Changes" section
LATEST_DATE=$(grep -E '^\* `[0-9]{4}-[0-9]{2}-[0-9]{2}' "$CHANGELOG_FILE" | head -1 | sed -E 's/^\* `([0-9]{4}-[0-9]{2}-[0-9]{2}).*/\1/')

if [[ -z "$LATEST_DATE" ]]; then
echo "Error: Could not find any date entries in changelog" >&2
exit 1
fi

echo "Latest changelog entry: $LATEST_DATE" >&2
AFTER_DATE="$LATEST_DATE"
;;
year)
if ! [[ "$PARAM" =~ ^[0-9]{4}$ ]]; then
echo "Error: Invalid year format. Expected YYYY, got: $PARAM" >&2
exit 1
fi
AFTER_DATE="$PARAM-01-01"
BEFORE_DATE="$PARAM-12-31"
;;
since)
if ! [[ "$PARAM" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
echo "Error: Invalid date format. Expected YYYY-MM-DD, got: $PARAM" >&2
exit 1
fi
AFTER_DATE="$PARAM"
;;
esac

# Get git log with diffs
if [[ -n "${BEFORE_DATE:-}" ]]; then
GIT_LOG=$(git log -p --after="$AFTER_DATE" --before="$BEFORE_DATE")
else
GIT_LOG=$(git log -p --after="$AFTER_DATE")
fi

if [[ -z "$GIT_LOG" ]]; then
echo "No commits found since $AFTER_DATE" >&2
exit 0
fi

# Pipe prompt and git log through zllm
OUTPUT=$(cat "$PROMPT_FILE" <(echo) <(echo "$GIT_LOG") | zllm)

# Extract changelog entries (lines starting with '*')
ENTRIES=$(echo "$OUTPUT" | grep '^\*' || true)

# Output or update
if [[ "$RAW_OUTPUT" == true ]]; then
echo "$OUTPUT"
elif [[ "$UPDATE_FILE" == true ]]; then
if [[ -z "$ENTRIES" ]]; then
echo "No changelog entries generated. Not updating file." >&2
exit 0
fi

# Create temporary file with new entries inserted after "== Rule Changes" header
# Split file into: header + new entries + rest
HEADER_LINE=$(grep -n "^== Rule Changes$" "$CHANGELOG_FILE" | cut -d: -f1)
if [[ -z "$HEADER_LINE" ]]; then
echo "Error: '== Rule Changes' header not found in $CHANGELOG_FILE. Cannot update changelog." >&2
exit 1
fi

{
# Read file up to (but not including) "== Rule Changes"
head -n "$((HEADER_LINE - 1))" "$CHANGELOG_FILE"
# Add the header and blank line
echo "== Rule Changes"
echo
# Add new entries
echo "$ENTRIES"
# Add existing entries (skip "== Rule Changes" line and the blank line after it)
tail -n +"$((HEADER_LINE + 2))" "$CHANGELOG_FILE"
} > "$CHANGELOG_FILE.tmp"

mv "$CHANGELOG_FILE.tmp" "$CHANGELOG_FILE"
echo "Updated $CHANGELOG_FILE with new entries" >&2
else
echo "$ENTRIES"
fi