feat(#2327): surface forgejo stale/dismissed review flags in pr-status/reviews/merge

This commit is contained in:
damocles 2026-07-10 14:50:19 +02:00 committed by mara
commit cd092a8ae4
4 changed files with 77 additions and 26 deletions

View file

@ -135,6 +135,13 @@ fn list_reviews_json(client: &Client, number: u64, reviews: &[Value]) -> Result<
json!({
"id": r.get("id"),
"state": r.get("state"),
// forgejo's staleness bits: `stale` = head moved since the
// review (branch protection wants a fresh one); `dismissed`
// = explicitly dismissed. A stale/dismissed APPROVED no
// longer satisfies the merge gate despite `state` reading
// APPROVED — surface them so callers don't over-trust it.
"stale": r.get("stale"),
"dismissed": r.get("dismissed"),
"user": r.get("user").and_then(|u| u.get("login")),
"body": r.get("body"),
"comments_count": r.get("comments_count"),
@ -161,7 +168,18 @@ fn list_reviews_text(client: &Client, number: u64, reviews: &[Value]) {
.unwrap_or("?");
let state = r.get("state").and_then(Value::as_str).unwrap_or("?");
let body = r.get("body").and_then(Value::as_str).unwrap_or("").trim();
println!("### review by {user} ({state})");
// Flag reviews forgejo considers no-longer-current so a stale
// APPROVED doesn't read as still-satisfying branch protection.
let is_stale = r.get("stale").and_then(Value::as_bool).unwrap_or(false);
let is_dismissed = r.get("dismissed").and_then(Value::as_bool).unwrap_or(false);
let flag = if is_stale {
" [stale — needs re-review]"
} else if is_dismissed {
" [dismissed]"
} else {
""
};
println!("### review by {user} ({state}){flag}");
if !body.is_empty() {
println!("{body}");
}