Merge pull request 'fix: restore Forgejo workflow names' (#261) from build/243-forgejo-workflow-name into main
All checks were successful
CI / test (push) Successful in 3m50s
CI / release-exercise (push) Has been skipped
CI / self-guards (push) Successful in 21s
CI / action-exercise (push) Successful in 20s
CI / docs-sync-exercise (push) Successful in 20s
release / release (push) Successful in 20s
All checks were successful
CI / test (push) Successful in 3m50s
CI / release-exercise (push) Has been skipped
CI / self-guards (push) Successful in 21s
CI / action-exercise (push) Successful in 20s
CI / docs-sync-exercise (push) Successful in 20s
release / release (push) Successful in 20s
Reviewed-on: #261 Reviewed-by: kimi-bot-andresmgsl <andres+4@heavyduty.builders> Reviewed-by: claude-bot-andresmgsl <andres+1@heavyduty.builders> Reviewed-by: glm-bot-andresmgsl <andres+5@heavyduty.builders>
This commit is contained in:
commit
484eb79623
4 changed files with 81 additions and 2 deletions
3
changelog.d/243.md
Normal file
3
changelog.d/243.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Preserve Forgejo workflow names in status rollups so the label reconciler excludes only its own checks. (#243).
|
||||||
|
|
@ -468,6 +468,10 @@ forge_pr_view() {
|
||||||
$st.statuses[]? | {
|
$st.statuses[]? | {
|
||||||
__typename: "StatusContext",
|
__typename: "StatusContext",
|
||||||
context: .context,
|
context: .context,
|
||||||
|
# Forgejo carries the workflow name only as the context prefix;
|
||||||
|
# no separator means no proven workflow, so never guess (#243).
|
||||||
|
workflowName: ((.context // "")
|
||||||
|
| if contains(" / ") then split(" / ")[0] else "" end),
|
||||||
state: (.status | ascii_upcase),
|
state: (.status | ascii_upcase),
|
||||||
# checks_state groups repeated contexts and takes the NEWEST by
|
# checks_state groups repeated contexts and takes the NEWEST by
|
||||||
# [.startedAt, .createdAt, .completedAt]. Without a timestamp the
|
# [.startedAt, .createdAt, .completedAt]. Without a timestamp the
|
||||||
|
|
|
||||||
|
|
@ -693,8 +693,11 @@ pr_view_stub() {
|
||||||
}
|
}
|
||||||
# The FAILURE is older but listed second — array order would pick it.
|
# The FAILURE is older but listed second — array order would pick it.
|
||||||
FAKE_STATUS='{"state":"failure","statuses":[
|
FAKE_STATUS='{"state":"failure","statuses":[
|
||||||
{"context":"ci / check","status":"success","created_at":"2026-08-02T10:00:00Z","updated_at":"2026-08-02T10:00:00Z"},
|
{"context":"labels / labels (pull_request)","status":"success","created_at":"2026-08-02T10:00:00Z","updated_at":"2026-08-02T10:00:00Z"},
|
||||||
{"context":"ci / check","status":"failure","created_at":"2026-08-02T09:00:00Z","updated_at":"2026-08-02T09:00:00Z"}]}'
|
{"context":"labels / labels (pull_request)","status":"failure","created_at":"2026-08-02T09:00:00Z","updated_at":"2026-08-02T09:00:00Z"},
|
||||||
|
{"context":"CI / test (pull_request)","status":"success","created_at":"2026-08-02T10:00:00Z","updated_at":"2026-08-02T10:00:00Z"},
|
||||||
|
{"context":"Refs guard / refs-not-closing (pull_request)","status":"success","created_at":"2026-08-02T10:00:00Z","updated_at":"2026-08-02T10:00:00Z"},
|
||||||
|
{"context":"codecov","status":"success","created_at":"2026-08-02T10:00:00Z","updated_at":"2026-08-02T10:00:00Z"}]}'
|
||||||
FAKE_PR='{"head":{"sha":"abc"},"base":{"sha":"base"},"merge_base":"ancestor","draft":false,"mergeable":true}'
|
FAKE_PR='{"head":{"sha":"abc"},"base":{"sha":"base"},"merge_base":"ancestor","draft":false,"mergeable":true}'
|
||||||
pr_view_stub
|
pr_view_stub
|
||||||
view_json="$(REPO=o/r forge_pr_view 5)"
|
view_json="$(REPO=o/r forge_pr_view 5)"
|
||||||
|
|
@ -702,6 +705,20 @@ check "pr_view maps createdAt" 0 "" \
|
||||||
grep -q '"createdAt": "2026-08-02T10:00:00Z"' <<<"$view_json"
|
grep -q '"createdAt": "2026-08-02T10:00:00Z"' <<<"$view_json"
|
||||||
check "pr_view maps completedAt" 0 "" \
|
check "pr_view maps completedAt" 0 "" \
|
||||||
grep -q '"completedAt":' <<<"$view_json"
|
grep -q '"completedAt":' <<<"$view_json"
|
||||||
|
check "pr_view derives workflowName from the first context separator" 0 "" \
|
||||||
|
jq -e '[.statusCheckRollup[]
|
||||||
|
| select(.context == "labels / labels (pull_request)"
|
||||||
|
or .context == "CI / test (pull_request)"
|
||||||
|
or .context == "Refs guard / refs-not-closing (pull_request)")
|
||||||
|
| [.workflowName, .context]]
|
||||||
|
| unique == [
|
||||||
|
["CI", "CI / test (pull_request)"],
|
||||||
|
["Refs guard", "Refs guard / refs-not-closing (pull_request)"],
|
||||||
|
["labels", "labels / labels (pull_request)"]
|
||||||
|
]' >/dev/null <<<"$view_json"
|
||||||
|
check "pr_view leaves workflowName empty when the context has no separator" 0 "" \
|
||||||
|
jq -e 'any(.statusCheckRollup[];
|
||||||
|
.context == "codecov" and .workflowName == "")' >/dev/null <<<"$view_json"
|
||||||
check "pr_view maps mergeable to the UI string" 0 "" \
|
check "pr_view maps mergeable to the UI string" 0 "" \
|
||||||
grep -q '"mergeable": "MERGEABLE"' <<<"$view_json"
|
grep -q '"mergeable": "MERGEABLE"' <<<"$view_json"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -589,6 +589,61 @@ expect "a rollup of ONLY self entries is honestly NONE, never SUCCESS" NONE \
|
||||||
expect "a genuine foreign FAILURE still blocks beside a cancelled self entry" FAILURE \
|
expect "a genuine foreign FAILURE still blocks beside a cancelled self entry" FAILURE \
|
||||||
"$(rollup "[$(run_ a FAILURE),\
|
"$(rollup "[$(run_ a FAILURE),\
|
||||||
$(rec_ CANCELLED 2026-08-01T15:17:56Z 2026-08-01T15:17:59Z)]" | checks_state)"
|
$(rec_ CANCELLED 2026-08-01T15:17:56Z 2026-08-01T15:17:59Z)]" | checks_state)"
|
||||||
|
|
||||||
|
# Forgejo exposes Actions checks only as commit statuses. Drive the real
|
||||||
|
# backend mapper here: fixtures that hand-write workflowName repeat the field
|
||||||
|
# omission that hid #243 instead of proving the adapter supplies it.
|
||||||
|
forgejo_rollup() {
|
||||||
|
local statuses="$1"
|
||||||
|
(
|
||||||
|
# shellcheck source=lib/forge-forgejo.sh
|
||||||
|
. lib/forge-forgejo.sh
|
||||||
|
forge_api() {
|
||||||
|
case "$1" in
|
||||||
|
repos/o/r/pulls/5)
|
||||||
|
printf '%s\n' '{"head":{"sha":"abc"},"base":{"sha":"base"},"merge_base":"ancestor","draft":false,"mergeable":true}'
|
||||||
|
;;
|
||||||
|
repos/o/r/commits/abc/status)
|
||||||
|
printf '%s\n' "$statuses"
|
||||||
|
;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
REPO=o/r forge_pr_view 5
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
forgejo_self_red='{"state":"failure","statuses":[
|
||||||
|
{"context":"labels / labels (pull_request)","status":"failure","created_at":"2026-08-23T18:32:00Z","updated_at":"2026-08-23T18:32:00Z"},
|
||||||
|
{"context":"CI / test (pull_request)","status":"pending","created_at":"2026-08-23T18:32:00Z","updated_at":"2026-08-23T18:32:00Z"}]}'
|
||||||
|
expect "Forgejo StatusContexts exclude a self FAILURE and retain pending work" PENDING \
|
||||||
|
"$(forgejo_rollup "$forgejo_self_red" | checks_state)"
|
||||||
|
|
||||||
|
forgejo_self_only='{"state":"failure","statuses":[
|
||||||
|
{"context":"labels / labels (pull_request)","status":"failure","created_at":"2026-08-23T18:32:00Z","updated_at":"2026-08-23T18:32:00Z"}]}'
|
||||||
|
expect "Forgejo StatusContexts containing only the self workflow are NONE" NONE \
|
||||||
|
"$(forgejo_rollup "$forgejo_self_only" | checks_state)"
|
||||||
|
|
||||||
|
forgejo_foreign_red='{"state":"failure","statuses":[
|
||||||
|
{"context":"labels / labels (pull_request)","status":"failure","created_at":"2026-08-23T18:32:00Z","updated_at":"2026-08-23T18:32:00Z"},
|
||||||
|
{"context":"CI / test (pull_request)","status":"failure","created_at":"2026-08-23T18:32:00Z","updated_at":"2026-08-23T18:32:00Z"}]}'
|
||||||
|
expect "Forgejo StatusContexts retain a genuine foreign FAILURE" FAILURE \
|
||||||
|
"$(forgejo_rollup "$forgejo_foreign_red" | checks_state)"
|
||||||
|
|
||||||
|
forgejo_bare_red='{"state":"failure","statuses":[
|
||||||
|
{"context":"codecov","status":"failure","created_at":"2026-08-23T18:32:00Z","updated_at":"2026-08-23T18:32:00Z"}]}'
|
||||||
|
expect "a bare Forgejo context survives a named self-workflow exclusion" FAILURE \
|
||||||
|
"$(forgejo_rollup "$forgejo_bare_red" | checks_state)"
|
||||||
|
|
||||||
|
forgejo_nested_name='{"state":"failure","statuses":[
|
||||||
|
{"context":"labels / nested / check","status":"failure","created_at":"2026-08-23T18:32:00Z","updated_at":"2026-08-23T18:32:00Z"}]}'
|
||||||
|
SELF_WORKFLOW="labels / nested"
|
||||||
|
expect "a Forgejo workflow name containing a separator is never guessed" FAILURE \
|
||||||
|
"$(forgejo_rollup "$forgejo_nested_name" | checks_state)"
|
||||||
|
|
||||||
|
SELF_WORKFLOW=""
|
||||||
|
expect "a bare Forgejo context also survives an empty self-workflow exclusion" FAILURE \
|
||||||
|
"$(forgejo_rollup "$forgejo_bare_red" | checks_state)"
|
||||||
# ...and an empty self filters NOTHING: outside Actions no workflow name is
|
# ...and an empty self filters NOTHING: outside Actions no workflow name is
|
||||||
# ambient, and the exclusion must never drop entries on a guess — the same
|
# ambient, and the exclusion must never drop entries on a guess — the same
|
||||||
# displaced-self rollup keeps blocking there, all-cancelled context intact.
|
# displaced-self rollup keeps blocking there, all-cancelled context intact.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue