elsa-core/scripts/adr/generate-toc.sh
Sipke Schoorstra f6d2d38536
test(user-tasks): add a persistence conformance suite with fault injection (#7986)
Runs one suite unchanged against every implementation of IUserTaskRepository,
IUserTaskGuestSessionIssuer, and IUserTaskInvitationOutbox, plus a fault-injection
suite driving the real DefaultUserTaskManager and DefaultUserTaskInvitationService
against a real store. Gated providers report as skipped with a reason rather than
passing vacuously; ConformanceCoverageTests fails when a provider that must run is
unreachable or its variable is set but empty.

The suite found three defects, fixed here:

- VNextUserTaskRepository supplied no index values for WorkflowDefinitionId,
  WorkflowInstanceId, ActivityInstanceId, CreatedAt, or CompletedAt, all declared by
  its own schema provider, so every write through the VNext provider threw.
- The same provider resolved invitation token hashes by scanning on Status alone,
  which matched no declared index, so anonymous invitation verification always threw.
- EFCoreUserTaskInvitationOutbox persisted the delivery recipient but never read it
  back, so durably queued invitations reached the dispatcher with no address.

Also switches new ADRs to date-prefixed identifiers and generates doc/adr/toc.md via
scripts/adr/generate-toc.sh, with a --check mode and pull-request workflow so the
index is never hand-edited again.
2026-08-25 04:36:18 +02:00

92 lines
3 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Regenerates doc/adr/toc.md from the ADR files themselves.
#
# The index is generated, never hand-edited: it drifted from the documents it indexes precisely because
# every ADR merge asked a human to retype it. Run with --check to verify it is current without writing.
#
# scripts/adr/generate-toc.sh # rewrite doc/adr/toc.md
# scripts/adr/generate-toc.sh --check # exit 1 if doc/adr/toc.md is out of date
#
set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
adr_dir="$repo_root/doc/adr"
toc_path="$adr_dir/toc.md"
check_only=false
if [[ "${1:-}" == "--check" ]]; then
check_only=true
elif [[ $# -gt 0 ]]; then
echo "usage: $(basename "$0") [--check]" >&2
exit 2
fi
# The heading is the source of truth for the title. A legacy "NN. " prefix is stripped so the identifier
# is rendered once, from the filename, rather than depending on whether an author remembered to type it.
title_of() {
local heading
heading="$(grep -m 1 '^# ' "$1" || true)"
[[ -n "$heading" ]] || return 1
heading="${heading#\# }"
sed -E 's/^[0-9]+\.[[:space:]]+//' <<<"$heading"
}
entries=()
add_entry() {
local file="$1" prefix="$2" title
if ! title="$(title_of "$file")"; then
echo "error: $(basename "$file") has no '# ' heading to take a title from." >&2
exit 1
fi
entries+=("$(printf '* [%s. %s](%s)' "$prefix" "$title" "$(basename "$file")")")
}
numbered=()
dated=()
while IFS= read -r file; do
case "$(basename "$file")" in
toc.md) continue ;;
# Dated first: a date also opens with four digits, so testing NNNN- first would swallow it.
[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-*.md) dated+=("$file") ;;
[0-9][0-9][0-9][0-9]-*.md) numbered+=("$file") ;;
*)
echo "error: $(basename "$file") matches neither the NNNN- nor the YYYY-MM-DD- naming convention." >&2
exit 1
;;
esac
done < <(LC_ALL=C find "$adr_dir" -maxdepth 1 -name '*.md' | LC_ALL=C sort)
# Numbered records first, then dated ones: every dated record postdates every numbered one, so one flat
# list stays chronological across the change of convention.
for file in ${numbered[@]+"${numbered[@]}"}; do
identifier="$(basename "$file")"
identifier="${identifier%%-*}"
# 10# so a zero-padded identifier is never read as octal.
add_entry "$file" "$((10#$identifier))"
done
for file in ${dated[@]+"${dated[@]}"}; do
identifier="$(basename "$file")"
add_entry "$file" "${identifier:0:10}"
done
generated="$(
echo '# Architecture Decision Records'
echo
echo '<!-- Generated by scripts/adr/generate-toc.sh. Do not edit by hand. -->'
echo
printf '%s\n' ${entries[@]+"${entries[@]}"}
)"
if [[ "$check_only" == true ]]; then
if ! diff -u "$toc_path" <(printf '%s\n' "$generated"); then
echo "doc/adr/toc.md is out of date. Run scripts/adr/generate-toc.sh and commit the result." >&2
exit 1
fi
echo "doc/adr/toc.md is up to date."
else
printf '%s\n' "$generated" > "$toc_path"
echo "Wrote doc/adr/toc.md."
fi