mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-07 22:44:16 +00:00
chore(pr): enforce changelog placement and reduce merge sync churn
This commit is contained in:
@@ -103,6 +103,7 @@
|
||||
- Live tests (real keys): `CLAWDBOT_LIVE_TEST=1 pnpm test:live` (OpenClaw-only) or `LIVE=1 pnpm test:live` (includes provider live tests). Docker: `pnpm test:docker:live-models`, `pnpm test:docker:live-gateway`. Onboarding Docker E2E: `pnpm test:docker:onboard`.
|
||||
- Full kit + what’s covered: `docs/testing.md`.
|
||||
- Changelog: user-facing changes only; no internal/meta notes (version alignment, appcast reminders, release process).
|
||||
- Changelog placement: in the active version block, append new entries to the end of the target section (`### Changes` or `### Fixes`); do not insert new entries at the top of a section.
|
||||
- Pure test additions/fixes generally do **not** need a changelog entry unless they alter user-facing behavior or the user asks for one.
|
||||
- Mobile: before using a simulator, check for connected real devices (iOS + Android) and prefer them when available.
|
||||
|
||||
|
||||
197
scripts/pr
197
scripts/pr
@@ -1040,6 +1040,107 @@ validate_changelog_entry_for_pr() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local diff_file
|
||||
diff_file=$(mktemp)
|
||||
git diff --unified=0 origin/main...HEAD -- CHANGELOG.md > "$diff_file"
|
||||
|
||||
if ! awk -v pr_pattern="$pr_pattern" '
|
||||
BEGIN {
|
||||
line_no = 0
|
||||
file_line_count = 0
|
||||
issue_count = 0
|
||||
}
|
||||
FNR == NR {
|
||||
if ($0 ~ /^@@ /) {
|
||||
if (match($0, /\+[0-9]+/)) {
|
||||
line_no = substr($0, RSTART + 1, RLENGTH - 1) + 0
|
||||
} else {
|
||||
line_no = 0
|
||||
}
|
||||
next
|
||||
}
|
||||
if ($0 ~ /^\+\+\+/) {
|
||||
next
|
||||
}
|
||||
if ($0 ~ /^\+/) {
|
||||
if (line_no > 0) {
|
||||
added[line_no] = 1
|
||||
added_text = substr($0, 2)
|
||||
if (added_text ~ pr_pattern) {
|
||||
pr_added_lines[++pr_added_count] = line_no
|
||||
pr_added_text[line_no] = added_text
|
||||
}
|
||||
line_no++
|
||||
}
|
||||
next
|
||||
}
|
||||
if ($0 ~ /^-/) {
|
||||
next
|
||||
}
|
||||
if (line_no > 0) {
|
||||
line_no++
|
||||
}
|
||||
next
|
||||
}
|
||||
{
|
||||
changelog[FNR] = $0
|
||||
file_line_count = FNR
|
||||
}
|
||||
END {
|
||||
for (idx = 1; idx <= pr_added_count; idx++) {
|
||||
entry_line = pr_added_lines[idx]
|
||||
section_line = 0
|
||||
for (i = entry_line; i >= 1; i--) {
|
||||
if (changelog[i] ~ /^### /) {
|
||||
section_line = i
|
||||
break
|
||||
}
|
||||
if (changelog[i] ~ /^## /) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (section_line == 0) {
|
||||
printf "CHANGELOG.md entry must be inside a subsection (### ...): line %d: %s\n", entry_line, pr_added_text[entry_line]
|
||||
issue_count++
|
||||
continue
|
||||
}
|
||||
|
||||
section_name = changelog[section_line]
|
||||
next_heading = file_line_count + 1
|
||||
for (i = entry_line + 1; i <= file_line_count; i++) {
|
||||
if (changelog[i] ~ /^### / || changelog[i] ~ /^## /) {
|
||||
next_heading = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for (i = entry_line + 1; i < next_heading; i++) {
|
||||
line_text = changelog[i]
|
||||
if (line_text ~ /^[[:space:]]*$/) {
|
||||
continue
|
||||
}
|
||||
if (i in added) {
|
||||
continue
|
||||
}
|
||||
printf "CHANGELOG.md PR-linked entry must be appended at the end of section %s: line %d: %s\n", section_name, entry_line, pr_added_text[entry_line]
|
||||
printf "Found existing non-added line below it at line %d: %s\n", i, line_text
|
||||
issue_count++
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (issue_count > 0) {
|
||||
print "Move this PR changelog entry to the end of its section (just before the next heading)."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
' "$diff_file" CHANGELOG.md; then
|
||||
rm -f "$diff_file"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$diff_file"
|
||||
echo "changelog placement validated: PR-linked entries are appended at section tail"
|
||||
|
||||
if [ -n "$contrib" ] && [ "$contrib" != "null" ]; then
|
||||
local with_pr_and_thanks
|
||||
with_pr_and_thanks=$(printf '%s\n' "$added_lines" | rg -in "$pr_pattern" | rg -i "thanks @$contrib" || true)
|
||||
@@ -1541,6 +1642,92 @@ prepare_run() {
|
||||
echo "prepare-run complete for PR #$pr"
|
||||
}
|
||||
|
||||
is_mainline_drift_critical_path_for_merge() {
|
||||
local path="$1"
|
||||
case "$path" in
|
||||
package.json|pnpm-lock.yaml|pnpm-workspace.yaml|.npmrc|.oxlintrc.json|.oxfmtrc.json|tsconfig.json|tsconfig.*.json|vitest.config.ts|vitest.*.config.ts|scripts/*|.github/workflows/*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
print_file_list_with_limit() {
|
||||
local label="$1"
|
||||
local file_path="$2"
|
||||
local limit="${3:-12}"
|
||||
|
||||
if [ ! -s "$file_path" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local count
|
||||
count=$(wc -l < "$file_path" | tr -d ' ')
|
||||
echo "$label ($count):"
|
||||
sed -n "1,${limit}p" "$file_path" | sed 's/^/ - /'
|
||||
if [ "$count" -gt "$limit" ]; then
|
||||
echo " ... +$((count - limit)) more"
|
||||
fi
|
||||
}
|
||||
|
||||
mainline_drift_requires_sync() {
|
||||
local prep_head_sha="$1"
|
||||
|
||||
require_artifact .local/pr-meta.json
|
||||
|
||||
if ! git cat-file -e "${prep_head_sha}^{commit}" 2>/dev/null; then
|
||||
echo "Mainline drift relevance: prep head $prep_head_sha is missing locally; require sync."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local delta_file
|
||||
local pr_files_file
|
||||
local overlap_file
|
||||
local critical_file
|
||||
delta_file=$(mktemp)
|
||||
pr_files_file=$(mktemp)
|
||||
overlap_file=$(mktemp)
|
||||
critical_file=$(mktemp)
|
||||
|
||||
git diff --name-only "${prep_head_sha}..origin/main" | sed '/^$/d' | sort -u > "$delta_file"
|
||||
jq -r '.files[]?.path // empty' .local/pr-meta.json | sed '/^$/d' | sort -u > "$pr_files_file"
|
||||
comm -12 "$delta_file" "$pr_files_file" > "$overlap_file" || true
|
||||
|
||||
local path
|
||||
while IFS= read -r path; do
|
||||
[ -n "$path" ] || continue
|
||||
if is_mainline_drift_critical_path_for_merge "$path"; then
|
||||
printf '%s\n' "$path" >> "$critical_file"
|
||||
fi
|
||||
done < "$delta_file"
|
||||
|
||||
local delta_count
|
||||
local overlap_count
|
||||
local critical_count
|
||||
delta_count=$(wc -l < "$delta_file" | tr -d ' ')
|
||||
overlap_count=$(wc -l < "$overlap_file" | tr -d ' ')
|
||||
critical_count=$(wc -l < "$critical_file" | tr -d ' ')
|
||||
|
||||
if [ "$delta_count" -eq 0 ]; then
|
||||
echo "Mainline drift relevance: unable to enumerate drift files; require sync."
|
||||
rm -f "$delta_file" "$pr_files_file" "$overlap_file" "$critical_file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$overlap_count" -gt 0 ] || [ "$critical_count" -gt 0 ]; then
|
||||
echo "Mainline drift relevance: sync required before merge."
|
||||
print_file_list_with_limit "Mainline files overlapping PR touched files" "$overlap_file"
|
||||
print_file_list_with_limit "Mainline files touching merge-critical infrastructure" "$critical_file"
|
||||
rm -f "$delta_file" "$pr_files_file" "$overlap_file" "$critical_file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Mainline drift relevance: no overlap with PR files and no critical infra drift."
|
||||
print_file_list_with_limit "Mainline-only drift files" "$delta_file"
|
||||
rm -f "$delta_file" "$pr_files_file" "$overlap_file" "$critical_file"
|
||||
return 1
|
||||
}
|
||||
|
||||
merge_verify() {
|
||||
local pr="$1"
|
||||
enter_worktree "$pr" false
|
||||
@@ -1608,10 +1795,14 @@ merge_verify() {
|
||||
|
||||
git fetch origin main
|
||||
git fetch origin "pull/$pr/head:pr-$pr" --force
|
||||
git merge-base --is-ancestor origin/main "pr-$pr" || {
|
||||
if ! git merge-base --is-ancestor origin/main "pr-$pr"; then
|
||||
echo "PR branch is behind main."
|
||||
exit 1
|
||||
}
|
||||
if mainline_drift_requires_sync "$PREP_HEAD_SHA"; then
|
||||
echo "Merge verify failed: mainline drift is relevant to this PR; refresh prep head before merge."
|
||||
exit 1
|
||||
fi
|
||||
echo "Merge verify: continuing without prep-head sync because behind-main drift is unrelated."
|
||||
fi
|
||||
|
||||
echo "merge-verify passed for PR #$pr"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user