Carry aggregate check state with GitHub pull requests

GitHub exposes a combined status for the head commit without requiring
individual check contexts. Include that rollup in the existing request
and startup cache so every consumer sees the same state without making a
second network request.
This commit is contained in:
Stefan Haller 2026-07-29 18:42:57 +02:00
parent 67ec23e08a
commit ff26f61ffd
6 changed files with 52 additions and 2 deletions

View file

@ -85,12 +85,25 @@ type PullRequestNode struct {
HeadRepositoryOwner GithubRepositoryOwner `json:"headRepositoryOwner"`
State string `json:"state"`
IsDraft bool `json:"isDraft"`
HeadRef GithubRef `json:"headRef"`
}
type GithubRepositoryOwner struct {
Login string `json:"login"`
}
type GithubRef struct {
Target GithubGitObject `json:"target"`
}
type GithubGitObject struct {
StatusCheckRollup GithubStatusCheckRollup `json:"statusCheckRollup"`
}
type GithubStatusCheckRollup struct {
State string `json:"state"`
}
type graphQLRequest struct {
Query string `json:"query"`
Variables map[string]string `json:"variables"`
@ -121,6 +134,15 @@ func fetchPullRequestsQuery(branches []string, owner string, repo string) (strin
number
url
isDraft
headRef {
target {
... on Commit {
statusCheckRollup {
state
}
}
}
}
headRepositoryOwner {
login
}
@ -249,6 +271,7 @@ func parsePullRequestsResponse(respBytes []byte) ([]*models.GithubPullRequest, e
Number: node.Number,
Title: node.Title,
State: lo.Ternary(node.IsDraft && node.State != "CLOSED", "DRAFT", node.State),
ChecksState: node.HeadRef.Target.StatusCheckRollup.State,
Url: node.Url,
HeadRepositoryOwner: models.GithubRepositoryOwner{
Login: node.HeadRepositoryOwner.Login,

View file

@ -76,6 +76,20 @@ func TestGraphQLEndpoint(t *testing.T) {
}
}
func TestFetchPullRequestsQueryFetchesOnlyAggregateCheckState(t *testing.T) {
query, variables := fetchPullRequestsQuery([]string{"feature"}, "owner", "repo")
assert.Contains(t, query, "headRef {")
assert.Contains(t, query, "... on Commit {")
assert.Contains(t, query, "statusCheckRollup {")
assert.NotContains(t, query, "contexts")
assert.Equal(t, map[string]string{
"owner": "owner",
"repo": "repo",
"branch1": "feature",
}, variables)
}
func TestParsePullRequestsResponse(t *testing.T) {
t.Run("flattens aliases and normalizes drafts", func(t *testing.T) {
response := []byte(`{
@ -91,7 +105,12 @@ func TestParsePullRequestsResponse(t *testing.T) {
"url": "https://github.com/jesseduffield/lazygit/pull/42",
"headRepositoryOwner": {"login": "contributor"},
"state": "OPEN",
"isDraft": false
"isDraft": false,
"headRef": {
"target": {
"statusCheckRollup": {"state": "SUCCESS"}
}
}
}
}
]
@ -106,7 +125,8 @@ func TestParsePullRequestsResponse(t *testing.T) {
"url": "https://github.com/jesseduffield/lazygit/pull/43",
"headRepositoryOwner": {"login": "contributor"},
"state": "OPEN",
"isDraft": true
"isDraft": true,
"headRef": null
}
}
]
@ -124,6 +144,7 @@ func TestParsePullRequestsResponse(t *testing.T) {
Number: 42,
Title: "Add feature",
State: "OPEN",
ChecksState: "SUCCESS",
Url: "https://github.com/jesseduffield/lazygit/pull/42",
HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"},
},
@ -176,6 +197,7 @@ func TestGenerateGithubPullRequestMap(t *testing.T) {
Number: 42,
Title: "Add feature",
State: "OPEN",
ChecksState: "PENDING",
Url: "https://github.com/jesseduffield/lazygit/pull/42",
HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
},
@ -199,6 +221,7 @@ func TestGenerateGithubPullRequestMap(t *testing.T) {
Number: 42,
Title: "Add feature",
State: "OPEN",
ChecksState: "PENDING",
Url: "https://github.com/jesseduffield/lazygit/pull/42",
HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
},

View file

@ -5,6 +5,7 @@ type GithubPullRequest struct {
Number int `json:"number"`
Title string `json:"title"`
State string `json:"state"` // "MERGED", "OPEN", "CLOSED", "DRAFT"
ChecksState string `json:"checksState"`
Url string `json:"url"`
HeadRepositoryOwner GithubRepositoryOwner `json:"headRepositoryOwner"`
}

View file

@ -850,6 +850,7 @@ type CachedPullRequest struct {
Number int `yaml:"number"`
Title string `yaml:"title"`
State string `yaml:"state"`
ChecksState string `yaml:"checksState,omitempty"`
Url string `yaml:"url"`
HeadRepositoryOwner string `yaml:"headRepositoryOwner"`
}

View file

@ -1770,6 +1770,7 @@ func (self *RefreshHelper) savePullRequestsToCache(prs []*models.GithubPullReque
Number: pr.Number,
Title: pr.Title,
State: pr.State,
ChecksState: pr.ChecksState,
Url: pr.Url,
HeadRepositoryOwner: pr.HeadRepositoryOwner.Login,
}

View file

@ -674,6 +674,7 @@ func (gui *Gui) loadCachedPullRequests() []*models.GithubPullRequest {
Number: cached.Number,
Title: cached.Title,
State: cached.State,
ChecksState: cached.ChecksState,
Url: cached.Url,
HeadRepositoryOwner: models.GithubRepositoryOwner{
Login: cached.HeadRepositoryOwner,