forked from heavy-duty/ceremony
fix(issueflow): the issue/PR discriminator is GitHub-only
Found by rehearsing DRY_RUN against heavy-duty/rig's live board, not by any
test. issueflow swept ZERO issues on Forgejo and printed "reconciled." — the
blind sweep again, one layer in, and invisible because the log is identical
to a legitimately empty queue.
Measured on the two list endpoints, 2026-08-02:
GitHub plain issues OMIT pull_request -> 0 of 9 carried the key
Forgejo every entry HAS it, null on issues -> 10 of 10 carried it
So `select(has("pull_request") | not)` matched nothing here. Replaced with
`.pull_request == null`, which is true for an issue on both forges (an absent
key reads as null) and false for a PR on both. Verified against both live
list endpoints: Forgejo 10 open issues, GitHub 9 — each matching its API.
With the fix the sweep produces real decisions against rig rather than
silence: needs-triage on six issues with no queue state, the merged-Refs
post-merge transition on #133, and the conflicting-queue-labels flag on #129.
The regression test keeps the old expression as a must-fail: it disagrees
with the new one on exactly the Forgejo shape.
Refs #188
This commit is contained in:
parent
9db8317543
commit
57abe15a77
2 changed files with 35 additions and 3 deletions
|
|
@ -470,7 +470,15 @@ reconcile_opened_issue() {
|
||||||
# The stand-downs return 0 explicitly: a bare return carries the failed
|
# The stand-downs return 0 explicitly: a bare return carries the failed
|
||||||
# test's status, which under execution is live `set -e` — and it killed the
|
# test's status, which under execution is live `set -e` — and it killed the
|
||||||
# run on every triage-authored mint, before one issue was reconciled (#91).
|
# run on every triage-authored mint, before one issue was reconciled (#91).
|
||||||
jq -e 'has("pull_request") | not' <<<"$ISSUE_JSON" >/dev/null || return 0
|
# `.pull_request == null`, NOT `has("pull_request") | not` (#188). The key's
|
||||||
|
# PRESENCE is a GitHub-only discriminator: GitHub omits it on a plain issue,
|
||||||
|
# Forgejo emits it on every entry and sets it to null. Measured on the list
|
||||||
|
# endpoints, 2026-08-02 — GitHub 0 of 9 issues carried the key, Forgejo 10 of
|
||||||
|
# 10 did. So the old test selected ZERO issues here and the sweep printed
|
||||||
|
# "reconciled." over an untouched board: the blind sweep again, one layer in.
|
||||||
|
# The null test is true for an issue on both forges (absent key reads as
|
||||||
|
# null) and false for a PR on both.
|
||||||
|
jq -e '.pull_request == null' <<<"$ISSUE_JSON" >/dev/null || return 0
|
||||||
author="$(jq -r '.user.login' <<<"$ISSUE_JSON")"
|
author="$(jq -r '.user.login' <<<"$ISSUE_JSON")"
|
||||||
is_triage_actor "$author" && triage=true
|
is_triage_actor "$author" && triage=true
|
||||||
labels="$(jq -r '.labels[].name' <<<"$ISSUE_JSON")"
|
labels="$(jq -r '.labels[].name' <<<"$ISSUE_JSON")"
|
||||||
|
|
@ -543,10 +551,10 @@ main() {
|
||||||
|
|
||||||
local n
|
local n
|
||||||
for n in $(forge_api --paginate "repos/$REPO/issues?state=open" \
|
for n in $(forge_api --paginate "repos/$REPO/issues?state=open" \
|
||||||
--jq '.[] | select(has("pull_request") | not) | .number'); do
|
--jq '.[] | select(.pull_request == null) | .number'); do
|
||||||
(
|
(
|
||||||
ISSUE_JSON="$(forge_api "repos/$REPO/issues/$n")"
|
ISSUE_JSON="$(forge_api "repos/$REPO/issues/$n")"
|
||||||
jq -e 'has("pull_request") | not' <<<"$ISSUE_JSON" >/dev/null || exit 0
|
jq -e '.pull_request == null' <<<"$ISSUE_JSON" >/dev/null || exit 0
|
||||||
ISSUE_LABELS="$(jq -r '.labels[].name' <<<"$ISSUE_JSON")"
|
ISSUE_LABELS="$(jq -r '.labels[].name' <<<"$ISSUE_JSON")"
|
||||||
reconcile_issue "$n"
|
reconcile_issue "$n"
|
||||||
) || log "#$n: reconcile failed — continuing with the remaining issues"
|
) || log "#$n: reconcile failed — continuing with the remaining issues"
|
||||||
|
|
|
||||||
|
|
@ -674,6 +674,30 @@ check "...and performs the release edit from the executable path" 0 "" \
|
||||||
grep -qF -- 'issue edit 40 -R owner/repo --remove-assignee builder --remove-label claimed --add-label post-merge' \
|
grep -qF -- 'issue edit 40 -R owner/repo --remove-assignee builder --remove-label claimed --add-label post-merge' \
|
||||||
"$ARRIVAL/fixtures/edits"
|
"$ARRIVAL/fixtures/edits"
|
||||||
|
|
||||||
|
# -- the issue/PR discriminator is not `has("pull_request")` ---------------
|
||||||
|
# Measured on the two list endpoints, 2026-08-02 (#188):
|
||||||
|
#
|
||||||
|
# GitHub plain issues OMIT the key -> 0 of 9 carried it
|
||||||
|
# Forgejo every entry HAS the key -> 10 of 10, valued null on issues
|
||||||
|
#
|
||||||
|
# So `select(has("pull_request") | not)` selected ZERO issues on Forgejo and
|
||||||
|
# the sweep printed "reconciled." over an untouched board — the blind sweep
|
||||||
|
# again, one layer in, and invisible because the log looks identical to a
|
||||||
|
# legitimately empty queue. Caught by rehearsing DRY_RUN against rig's live
|
||||||
|
# board, not by any unit test. `.pull_request == null` is true for an issue on
|
||||||
|
# both forges (an absent key reads as null) and false for a PR on both.
|
||||||
|
disc() { jq -e "$1" >/dev/null 2>&1 && echo issue || echo pr; }
|
||||||
|
check "github-shaped issue (key absent) reads as an issue" 0 "issue" \
|
||||||
|
bash -c 'echo "{\"number\":1}" | jq -e ".pull_request == null" >/dev/null && echo issue || echo pr'
|
||||||
|
check "forgejo-shaped issue (key present, null) reads as an issue" 0 "issue" \
|
||||||
|
bash -c 'echo "{\"number\":1,\"pull_request\":null}" | jq -e ".pull_request == null" >/dev/null && echo issue || echo pr'
|
||||||
|
check "a PR reads as a PR on either shape" 0 "pr" \
|
||||||
|
bash -c 'echo "{\"number\":1,\"pull_request\":{\"url\":\"x\"}}" | jq -e ".pull_request == null" >/dev/null && echo issue || echo pr'
|
||||||
|
# The old test, kept as the must-fail: it disagrees with the new one on the
|
||||||
|
# forgejo shape, which is exactly the bug.
|
||||||
|
check "the old has() test misreads a forgejo issue as a PR" 0 "pr" \
|
||||||
|
bash -c 'echo "{\"number\":1,\"pull_request\":null}" | jq -e "has(\"pull_request\") | not" >/dev/null && echo issue || echo pr'
|
||||||
|
|
||||||
# -- the OPEN-pull gather, at main() granularity ----------------------------
|
# -- the OPEN-pull gather, at main() granularity ----------------------------
|
||||||
# The closed/merged half above proves one REST path; this proves the other,
|
# The closed/merged half above proves one REST path; this proves the other,
|
||||||
# which is a DIFFERENT pipeline: `.body | @base64` -> base64 -d ->
|
# which is a DIFFERENT pipeline: `.body | @base64` -> base64 -d ->
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue