From 4c2c9d3341d9e94fcb095f41adb8282a2caa7ce3 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Fri, 2 Oct 2026 23:16:09 +0100 Subject: [PATCH] fix(gh): confirm a failing workflow with a different query string (#1) GitHub can answer one exact run-listing query from an old cached result for weeks. The same query on a new connection returned the same old failure, so a workflow whose latest runs passed still showed as failing. The confirmation request now adds page=1. The changed query skips the cached result and returns current runs. The test models a cache that serves the plain query only. --- internal/gh/fetch.go | 3 +++ internal/gh/gh_test.go | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/internal/gh/fetch.go b/internal/gh/fetch.go index e0bc6e0..c3e1b93 100644 --- a/internal/gh/fetch.go +++ b/internal/gh/fetch.go @@ -360,6 +360,9 @@ func (c *Client) workflowRuns(ctx context.Context, full string, id int64, branch path := fmt.Sprintf("/repos/%s/actions/workflows/%d/runs", full, id) get := c.getJSON if fresh { + // GitHub can keep answering one exact query from an old cached result, for weeks, whatever + // the connection. A different query string skips that entry and reads current runs. + q.Set("page", "1") get = c.getJSONFresh } if err := get(ctx, full, path, q, &out); err != nil { diff --git a/internal/gh/gh_test.go b/internal/gh/gh_test.go index b7ef89c..4a44037 100644 --- a/internal/gh/gh_test.go +++ b/internal/gh/gh_test.go @@ -460,13 +460,13 @@ func TestAPIErrorMessageParsing(t *testing.T) { } } -// staleThenFresh serves an old failing run on the first request and the current runs afterwards, -// like a lagging GitHub replica followed by a healthy one. +// staleThenFresh models GitHub answering one exact query from an old cached result: the plain +// query returns an old failing run every time, and the same query with page=1 returns current runs. func staleThenFresh(f *fakeGitHub, path string) *atomic.Int64 { var calls atomic.Int64 f.routes[path] = func(w http.ResponseWriter, r *http.Request) { - n := calls.Add(1) - if n == 1 { + calls.Add(1) + if r.URL.Query().Get("page") == "" { _, _ = w.Write([]byte(`{"workflow_runs":[ {"id":1,"html_url":"old","event":"schedule","head_branch":"main","status":"completed","conclusion":"failure","created_at":"2026-09-11T03:02:00Z"}]}`)) return @@ -482,7 +482,7 @@ func staleThenFresh(f *fakeGitHub, path string) *atomic.Int64 { return &calls } -func TestStaleFailureIsConfirmedOnANewConnection(t *testing.T) { +func TestStaleFailureIsConfirmedWithADifferentQuery(t *testing.T) { f := newFake(t) c := f.client(t, 10) f.json("/repos/o/r/actions/workflows", `{"workflows":[{"id":7,"name":"Autoupdate","html_url":"w","state":"active"}]}`)