diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go index 8f36761..7cba1e4 100644 --- a/cmd/bootstrap.go +++ b/cmd/bootstrap.go @@ -121,8 +121,16 @@ func runBootstrap(cmd *cobra.Command, args []string) error { return err } manager := forgejo.NewRepoManager(cfg.Git.BaseURL, cfg.Git.Token, cfg.Git.Owner, cfg.Git.Username, "", "", cfg.Flux.Branch, "") - if err := manager.MergePullRequest(cfg.Flux.RepoName, "maidn/bootstrap-"+cfg.ClusterID); err != nil { - return err + for _, repository := range []string{cfg.Flux.ManifestsRepo, cfg.Flux.RepoName} { + open, err := manager.HasOpenPullRequest(repository, "maidn/bootstrap-"+cfg.ClusterID) + if err != nil { + return err + } + if open { + if err := manager.MergePullRequest(repository, "maidn/bootstrap-"+cfg.ClusterID); err != nil { + return err + } + } } } if bootstrapConfigPath != "" { diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go index 3b4f129..02d7882 100644 --- a/internal/bootstrap/bootstrap.go +++ b/internal/bootstrap/bootstrap.go @@ -343,14 +343,16 @@ func (r Runner) Run() error { } func (r Runner) reconcileBootstrapMigration(manager *forgejo.RepoManager) error { - if !manager.MigrationPending { + if len(manager.MigrationRepositories) == 0 { return nil } if !r.AutoMergeBootstrapMigration { - return errors.New("existing repository migration PR created; merge and rerun bootstrap before infrastructure changes") + return fmt.Errorf("repository migration PRs created for %s; merge and rerun bootstrap before infrastructure changes", strings.Join(manager.MigrationRepositories, ", ")) } - if err := manager.MergePullRequest(r.Config.Flux.RepoName, manager.MigrationBranch); err != nil { - return fmt.Errorf("merge bootstrap migration PR: %w", err) + for _, repository := range manager.MigrationRepositories { + if err := manager.MergePullRequest(repository, manager.MigrationBranch); err != nil { + return fmt.Errorf("merge bootstrap migration PR for %s: %w", repository, err) + } } return nil } diff --git a/internal/bootstrap/bootstrap_test.go b/internal/bootstrap/bootstrap_test.go index 2f3a50c..ff227f9 100644 --- a/internal/bootstrap/bootstrap_test.go +++ b/internal/bootstrap/bootstrap_test.go @@ -908,15 +908,16 @@ func TestRunnerEnableDeliveryAppliesDefaults(t *testing.T) { func TestRunnerAutoMergesBootstrapMigration(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { - switch request.Method + " " + request.URL.Path { - case http.MethodGet + " /api/v1/repos/test-org/cluster/pulls": + if request.Method == http.MethodGet && (request.URL.Path == "/api/v1/repos/test-org/manifests/pulls" || request.URL.Path == "/api/v1/repos/test-org/cluster/pulls") { if request.URL.Query().Get("state") != "open" || request.URL.Query().Get("head") != "maidn/bootstrap-test-cluster" { t.Fatalf("unexpected migration lookup query: %q", request.URL.RawQuery) } _ = json.NewEncoder(writer).Encode([]struct { Number int `json:"number"` }{{Number: 4}}) - case http.MethodPost + " /api/v1/repos/test-org/cluster/pulls/4/merge": + return + } + if request.Method == http.MethodPost && (request.URL.Path == "/api/v1/repos/test-org/manifests/pulls/4/merge" || request.URL.Path == "/api/v1/repos/test-org/cluster/pulls/4/merge") { var body struct { Do string `json:"Do"` } @@ -924,15 +925,15 @@ func TestRunnerAutoMergesBootstrapMigration(t *testing.T) { t.Fatalf("unexpected migration merge request: %#v, %v", body, err) } writer.WriteHeader(http.StatusOK) - default: - t.Fatalf("unexpected Forgejo request %s %s", request.Method, request.URL.Path) + return } + t.Fatalf("unexpected Forgejo request %s %s", request.Method, request.URL.Path) })) defer server.Close() manager := forgejo.NewRepoManager(server.URL, "test-token", "test-org", "bot", "manifests", "cluster", "main", "maidn/bootstrap-test-cluster") manager.HTTPClient = server.Client() - manager.MigrationPending = true + manager.MigrationRepositories = []string{"manifests", "cluster"} if err := (Runner{Config: config.Config{Flux: config.FluxConfig{RepoName: "cluster"}}, AutoMergeBootstrapMigration: true}).reconcileBootstrapMigration(manager); err != nil { t.Fatal(err) } @@ -946,7 +947,7 @@ func TestRunnerRetainsMigrationApprovalGate(t *testing.T) { manager := forgejo.NewRepoManager(server.URL, "test-token", "test-org", "bot", "manifests", "cluster", "main", "maidn/bootstrap-test-cluster") manager.HTTPClient = server.Client() - manager.MigrationPending = true + manager.MigrationRepositories = []string{"manifests"} if err := (Runner{Config: config.Config{Flux: config.FluxConfig{RepoName: "cluster"}}}).reconcileBootstrapMigration(manager); err == nil || !strings.Contains(err.Error(), "merge and rerun bootstrap") { t.Fatalf("normal bootstrap migration gate = %v", err) } diff --git a/internal/forgejo/repo.go b/internal/forgejo/repo.go index dde234e..df2a3a3 100644 --- a/internal/forgejo/repo.go +++ b/internal/forgejo/repo.go @@ -16,16 +16,16 @@ import ( ) type RepoManager struct { - BaseURL string - Token string - Owner string - Username string - ManifestsRepoName string - FluxRepoName string - Branch string - MigrationBranch string - MigrationPending bool - HTTPClient *http.Client + BaseURL string + Token string + Owner string + Username string + ManifestsRepoName string + FluxRepoName string + Branch string + MigrationBranch string + MigrationRepositories []string + HTTPClient *http.Client } type createRepoRequest struct { @@ -379,7 +379,12 @@ func (rm *RepoManager) setupRepository(repoURL, repoName string, existing bool, if err != nil || !changed || !existing { return err } - rm.MigrationPending = true + for _, repository := range rm.MigrationRepositories { + if repository == repoName { + return rm.createMigrationPullRequest(repoName, targetBranch) + } + } + rm.MigrationRepositories = append(rm.MigrationRepositories, repoName) return rm.createMigrationPullRequest(repoName, targetBranch) }