Skip to content

Commit 182de19

Browse files
authored
Support more than 30 status (#48)
* support more than 30 status * fix logic * add tests * paginate check runs; fix mock functions
1 parent ad082d8 commit 182de19

File tree

2 files changed

+220
-5
lines changed

2 files changed

+220
-5
lines changed

internal/validators/status/validator.go

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ const (
2727
checkRunSkipConclusion = "skipped"
2828
)
2929

30+
const (
31+
maxStatusesPerPage = 100
32+
maxCheckRunsPerPage = 100
33+
)
34+
3035
var (
3136
ErrInvalidCombinedStatusResponse = errors.New("github combined status response is invalid")
3237
ErrInvalidCheckRunResponse = errors.New("github checkRun response is invalid")
@@ -140,8 +145,45 @@ func (sv *statusValidator) Validate(ctx context.Context) (validators.Status, err
140145
return st, nil
141146
}
142147

148+
func (sv *statusValidator) getCombinedStatus(ctx context.Context) ([]*github.RepoStatus, error) {
149+
var combined []*github.RepoStatus
150+
page := 1
151+
for {
152+
c, _, err := sv.client.GetCombinedStatus(ctx, sv.owner, sv.repo, sv.ref, &github.ListOptions{PerPage: maxStatusesPerPage, Page: page})
153+
if err != nil {
154+
return nil, err
155+
}
156+
combined = append(combined, c.Statuses...)
157+
if c.GetTotalCount() < maxStatusesPerPage {
158+
break
159+
}
160+
page++
161+
}
162+
return combined, nil
163+
}
164+
165+
func (sv *statusValidator) listCheckRunsForRef(ctx context.Context) ([]*github.CheckRun, error) {
166+
var runResults []*github.CheckRun
167+
page := 1
168+
for {
169+
cr, _, err := sv.client.ListCheckRunsForRef(ctx, sv.owner, sv.repo, sv.ref, &github.ListCheckRunsOptions{ListOptions: github.ListOptions{
170+
Page: page,
171+
PerPage: maxCheckRunsPerPage,
172+
}})
173+
if err != nil {
174+
return nil, err
175+
}
176+
runResults = append(runResults, cr.CheckRuns...)
177+
if cr.GetTotal() < maxCheckRunsPerPage {
178+
break
179+
}
180+
page++
181+
}
182+
return runResults, nil
183+
}
184+
143185
func (sv *statusValidator) listGhaStatuses(ctx context.Context) ([]*ghaStatus, error) {
144-
combined, _, err := sv.client.GetCombinedStatus(ctx, sv.owner, sv.repo, sv.ref, &github.ListOptions{})
186+
combined, err := sv.getCombinedStatus(ctx)
145187
if err != nil {
146188
return nil, err
147189
}
@@ -150,8 +192,8 @@ func (sv *statusValidator) listGhaStatuses(ctx context.Context) ([]*ghaStatus, e
150192
// only the latest job should be managed.
151193
currentJobs := make(map[string]struct{})
152194

153-
ghaStatuses := make([]*ghaStatus, 0, len(combined.Statuses))
154-
for _, s := range combined.Statuses {
195+
ghaStatuses := make([]*ghaStatus, 0, len(combined))
196+
for _, s := range combined {
155197
if s.Context == nil || s.State == nil {
156198
return nil, fmt.Errorf("%w context: %v, status: %v", ErrInvalidCombinedStatusResponse, s.Context, s.State)
157199
}
@@ -166,12 +208,12 @@ func (sv *statusValidator) listGhaStatuses(ctx context.Context) ([]*ghaStatus, e
166208
})
167209
}
168210

169-
runResult, _, err := sv.client.ListCheckRunsForRef(ctx, sv.owner, sv.repo, sv.ref, &github.ListCheckRunsOptions{})
211+
runResults, err := sv.listCheckRunsForRef(ctx)
170212
if err != nil {
171213
return nil, err
172214
}
173215

174-
for _, run := range runResult.CheckRuns {
216+
for _, run := range runResults {
175217
if run.Name == nil || run.Status == nil {
176218
return nil, fmt.Errorf("%w name: %v, status: %v", ErrInvalidCheckRunResponse, run.Name, run.Status)
177219
}

internal/validators/status/validator_test.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package status
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"reflect"
78
"testing"
89

@@ -15,6 +16,13 @@ func stringPtr(str string) *string {
1516
return &str
1617
}
1718

19+
func min(a, b int) int {
20+
if a < b {
21+
return a
22+
}
23+
return b
24+
}
25+
1826
func TestCreateValidator(t *testing.T) {
1927
tests := map[string]struct {
2028
c github.Client
@@ -734,6 +742,171 @@ func Test_statusValidator_listStatues(t *testing.T) {
734742
},
735743
}
736744
}(),
745+
"succeeds to retrieve 100 statuses": func() test {
746+
num_statuses := 100
747+
statuses := make([]*github.RepoStatus, num_statuses)
748+
checkRuns := make([]*github.CheckRun, num_statuses)
749+
expectedGhaStatuses := make([]*ghaStatus, num_statuses)
750+
for i := 0; i < num_statuses; i++ {
751+
statuses[i] = &github.RepoStatus{
752+
Context: stringPtr(fmt.Sprintf("job-%d", i)),
753+
State: stringPtr(successState),
754+
}
755+
756+
checkRuns[i] = &github.CheckRun{
757+
Name: stringPtr(fmt.Sprintf("job-%d", i)),
758+
Status: stringPtr(checkRunCompletedStatus),
759+
Conclusion: stringPtr(checkRunNeutralConclusion),
760+
}
761+
762+
expectedGhaStatuses[i] = &ghaStatus{
763+
Job: fmt.Sprintf("job-%d", i),
764+
State: successState,
765+
}
766+
}
767+
768+
c := &mock.Client{
769+
GetCombinedStatusFunc: func(ctx context.Context, owner, repo, ref string, opts *github.ListOptions) (*github.CombinedStatus, *github.Response, error) {
770+
max := min(opts.Page*opts.PerPage, len(statuses))
771+
sts := statuses[(opts.Page-1)*opts.PerPage : max]
772+
l := len(sts)
773+
return &github.CombinedStatus{
774+
Statuses: sts,
775+
TotalCount: &l,
776+
}, nil, nil
777+
},
778+
ListCheckRunsForRefFunc: func(ctx context.Context, owner, repo, ref string, opts *github.ListCheckRunsOptions) (*github.ListCheckRunsResults, *github.Response, error) {
779+
max := min(opts.ListOptions.Page*opts.ListOptions.PerPage, len(checkRuns))
780+
sts := checkRuns[(opts.ListOptions.Page-1)*opts.ListOptions.PerPage : max]
781+
l := len(sts)
782+
return &github.ListCheckRunsResults{
783+
CheckRuns: checkRuns,
784+
Total: &l,
785+
}, nil, nil
786+
},
787+
}
788+
return test{
789+
fields: fields{
790+
client: c,
791+
selfJobName: "self-job",
792+
owner: "test-owner",
793+
repo: "test-repo",
794+
ref: "main",
795+
},
796+
wantErr: false,
797+
want: expectedGhaStatuses,
798+
}
799+
}(),
800+
"succeeds to retrieve 162 statuses": func() test {
801+
num_statuses := 162
802+
statuses := make([]*github.RepoStatus, num_statuses)
803+
checkRuns := make([]*github.CheckRun, num_statuses)
804+
expectedGhaStatuses := make([]*ghaStatus, num_statuses)
805+
for i := 0; i < num_statuses; i++ {
806+
statuses[i] = &github.RepoStatus{
807+
Context: stringPtr(fmt.Sprintf("job-%d", i)),
808+
State: stringPtr(successState),
809+
}
810+
811+
checkRuns[i] = &github.CheckRun{
812+
Name: stringPtr(fmt.Sprintf("job-%d", i)),
813+
Status: stringPtr(checkRunCompletedStatus),
814+
Conclusion: stringPtr(checkRunNeutralConclusion),
815+
}
816+
817+
expectedGhaStatuses[i] = &ghaStatus{
818+
Job: fmt.Sprintf("job-%d", i),
819+
State: successState,
820+
}
821+
}
822+
823+
c := &mock.Client{
824+
GetCombinedStatusFunc: func(ctx context.Context, owner, repo, ref string, opts *github.ListOptions) (*github.CombinedStatus, *github.Response, error) {
825+
max := min(opts.Page*opts.PerPage, len(statuses))
826+
sts := statuses[(opts.Page-1)*opts.PerPage : max]
827+
l := len(sts)
828+
return &github.CombinedStatus{
829+
Statuses: sts,
830+
TotalCount: &l,
831+
}, nil, nil
832+
},
833+
ListCheckRunsForRefFunc: func(ctx context.Context, owner, repo, ref string, opts *github.ListCheckRunsOptions) (*github.ListCheckRunsResults, *github.Response, error) {
834+
max := min(opts.ListOptions.Page*opts.ListOptions.PerPage, len(checkRuns))
835+
sts := checkRuns[(opts.ListOptions.Page-1)*opts.ListOptions.PerPage : max]
836+
l := len(sts)
837+
return &github.ListCheckRunsResults{
838+
CheckRuns: checkRuns,
839+
Total: &l,
840+
}, nil, nil
841+
},
842+
}
843+
return test{
844+
fields: fields{
845+
client: c,
846+
selfJobName: "self-job",
847+
owner: "test-owner",
848+
repo: "test-repo",
849+
ref: "main",
850+
},
851+
wantErr: false,
852+
want: expectedGhaStatuses,
853+
}
854+
}(),
855+
"succeeds to retrieve 587 statuses": func() test {
856+
num_statuses := 587
857+
statuses := make([]*github.RepoStatus, num_statuses)
858+
checkRuns := make([]*github.CheckRun, num_statuses)
859+
expectedGhaStatuses := make([]*ghaStatus, num_statuses)
860+
for i := 0; i < num_statuses; i++ {
861+
statuses[i] = &github.RepoStatus{
862+
Context: stringPtr(fmt.Sprintf("job-%d", i)),
863+
State: stringPtr(successState),
864+
}
865+
866+
checkRuns[i] = &github.CheckRun{
867+
Name: stringPtr(fmt.Sprintf("job-%d", i)),
868+
Status: stringPtr(checkRunCompletedStatus),
869+
Conclusion: stringPtr(checkRunNeutralConclusion),
870+
}
871+
872+
expectedGhaStatuses[i] = &ghaStatus{
873+
Job: fmt.Sprintf("job-%d", i),
874+
State: successState,
875+
}
876+
}
877+
878+
c := &mock.Client{
879+
GetCombinedStatusFunc: func(ctx context.Context, owner, repo, ref string, opts *github.ListOptions) (*github.CombinedStatus, *github.Response, error) {
880+
max := min(opts.Page*opts.PerPage, len(statuses))
881+
sts := statuses[(opts.Page-1)*opts.PerPage : max]
882+
l := len(sts)
883+
return &github.CombinedStatus{
884+
Statuses: sts,
885+
TotalCount: &l,
886+
}, nil, nil
887+
},
888+
ListCheckRunsForRefFunc: func(ctx context.Context, owner, repo, ref string, opts *github.ListCheckRunsOptions) (*github.ListCheckRunsResults, *github.Response, error) {
889+
max := min(opts.ListOptions.Page*opts.ListOptions.PerPage, len(checkRuns))
890+
sts := checkRuns[(opts.ListOptions.Page-1)*opts.ListOptions.PerPage : max]
891+
l := len(sts)
892+
return &github.ListCheckRunsResults{
893+
CheckRuns: checkRuns,
894+
Total: &l,
895+
}, nil, nil
896+
},
897+
}
898+
return test{
899+
fields: fields{
900+
client: c,
901+
selfJobName: "self-job",
902+
owner: "test-owner",
903+
repo: "test-repo",
904+
ref: "main",
905+
},
906+
wantErr: false,
907+
want: expectedGhaStatuses,
908+
}
909+
}(),
737910
}
738911
for name, tt := range tests {
739912
t.Run(name, func(t *testing.T) {

0 commit comments

Comments
 (0)