diff --git a/internal/pkg/githubapi/promotion.go b/internal/pkg/githubapi/promotion.go index b2f8211e..cde9bbaf 100644 --- a/internal/pkg/githubapi/promotion.go +++ b/internal/pkg/githubapi/promotion.go @@ -111,12 +111,21 @@ func getComponentConfig(ghPrClientDetails GhPrClientDetails, componentPath strin func GeneratePromotionPlan(ghPrClientDetails GhPrClientDetails, config *cfg.Config, configBranch string) (map[string]PromotionInstance, error) { promotions := make(map[string]PromotionInstance) + opts := &github.ListOptions{} + prFiles := []*github.CommitFile{} - prFiles, resp, err := ghPrClientDetails.GhClientPair.v3Client.PullRequests.ListFiles(ghPrClientDetails.Ctx, ghPrClientDetails.Owner, ghPrClientDetails.Repo, ghPrClientDetails.PrNumber, &github.ListOptions{}) - prom.InstrumentGhCall(resp) - if err != nil { - ghPrClientDetails.PrLogger.Errorf("could not get file list from GH API: err=%s\nresponse=%v", err, resp) - return promotions, err + for { + perPagePrFiles, resp, err := ghPrClientDetails.GhClientPair.v3Client.PullRequests.ListFiles(ghPrClientDetails.Ctx, ghPrClientDetails.Owner, ghPrClientDetails.Repo, ghPrClientDetails.PrNumber, opts) + prom.InstrumentGhCall(resp) + if err != nil { + ghPrClientDetails.PrLogger.Errorf("could not get file list from GH API: err=%s\nstatus code=%v", err, resp.Response.Status) + return promotions, err + } + prFiles = append(prFiles, perPagePrFiles...) + if resp.NextPage == 0 { + break + } + opts.Page = resp.NextPage } //first we build a **unique** list of relevant directories diff --git a/internal/pkg/githubapi/promotion_test.go b/internal/pkg/githubapi/promotion_test.go index 411171ac..a1e3d2d5 100644 --- a/internal/pkg/githubapi/promotion_test.go +++ b/internal/pkg/githubapi/promotion_test.go @@ -481,3 +481,55 @@ func TestGenerateNestedSourceRegexPromotionPlan(t *testing.T) { ) generatePromotionPlanTestHelper(t, config, expectedPromotion, mockedHTTPClient) } + +func TestGeneratePromotionPlanWithPagination(t *testing.T) { + t.Parallel() + config := &cfg.Config{ + PromotionPaths: []cfg.PromotionPath{ + { + SourcePath: "prod/us-east-4/", + PromotionPrs: []cfg.PromotionPr{ + { + TargetPaths: []string{ + "prod/eu-west-1/", + "prod/eu-east-1/", + }, + }, + }, + }, + }, + } + expectedPromotion := map[string]PromotionInstance{ + "prod/us-east-4/>prod/eu-east-1/|prod/eu-west-1/": { + ComputedSyncPaths: map[string]string{ + "prod/eu-east-1/componentA": "prod/us-east-4/componentA", + "prod/eu-west-1/componentA": "prod/us-east-4/componentA", + }, + }, + } + // Note the "relevant" files are in the second page, to ensure pagination is working + mockedHTTPClient := mock.NewMockedHTTPClient( + mock.WithRequestMatchPages( + mock.GetReposPullsFilesByOwnerByRepoByPullNumber, + []github.CommitFile{ + {Filename: github.String(".ci-config/random-file.json")}, + {Filename: github.String(".ci-config/random-file2.json")}, + }, + []github.CommitFile{ + {Filename: github.String("prod/us-east-4/componentA/file.yaml")}, + {Filename: github.String("prod/us-east-4/componentA/file2.yaml")}, + }, + ), + mock.WithRequestMatchHandler( + mock.GetReposContentsByOwnerByRepoByPath, + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mock.WriteError( + w, + http.StatusNotFound, + "no *optional* in-component telefonistka config file", + ) + }), + ), + ) + generatePromotionPlanTestHelper(t, config, expectedPromotion, mockedHTTPClient) +}