From 7a389d2eb14f5aaf0889d1574ee6c56244a13e2c Mon Sep 17 00:00:00 2001 From: Matthew Casperson Date: Tue, 23 Jul 2024 08:35:12 +1000 Subject: [PATCH] Refactored runbook creation step for testing --- internal/steps/project_export.go | 309 ++++++++++++++++--------------- internal/steps/space_export.go | 4 +- 2 files changed, 160 insertions(+), 153 deletions(-) diff --git a/internal/steps/project_export.go b/internal/steps/project_export.go index dfc38d0..815a52d 100644 --- a/internal/steps/project_export.go +++ b/internal/steps/project_export.go @@ -3,6 +3,7 @@ package steps import ( "bytes" _ "embed" + "errors" "fmt" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" @@ -77,203 +78,209 @@ func (s ProjectExportStep) createNewProject(parent fyne.Window) { s.createProject.Disable() s.result.SetText("🔵 Creating runbooks. This can take a little while.") - go func() { - defer s.previous.Enable() - defer s.infinite.Hide() - defer s.createProject.Enable() + s.Execute(func(title string, message string, callback func(bool)) { + dialog.NewConfirm(title, message, callback, parent).Show() + }, func(message string, err error) { + s.result.SetText(message) + s.logs.SetText(err.Error()) + s.previous.Enable() + s.infinite.Hide() + s.createProject.Enable() + }, func(message string) { + s.result.SetText(message) + s.previous.Enable() + s.infinite.Hide() + s.createProject.Enable() + }) +} - myclient, err := octoclient.CreateClient(s.State) +func (s ProjectExportStep) Execute(prompt func(string, string, func(bool)), handleError func(string, error), handleSuccess func(string)) { + defer s.previous.Enable() + defer s.infinite.Hide() + defer s.createProject.Enable() - if err != nil { - s.logs.SetText("🔴 Failed to create the client:\n" + err.Error()) - return - } + myclient, err := octoclient.CreateClient(s.State) - allProjects, err := s.getProjects(myclient) + if err != nil { + handleError("🔴 Failed to create the client", err) + return + } - if err != nil { - s.logs.SetText("🔴 Failed to get all the projects:\n" + err.Error()) - return - } + allProjects, err := s.getProjects(myclient) - allProjects = lo.Filter(allProjects, func(project *projects.Project, index int) bool { - return project.Name != spaceManagementProject - }) + if err != nil { + handleError("🔴 Failed to get all the projects", err) + return + } - lvsExists, lvs, err := query.LibraryVariableSetExists(myclient) + allProjects = lo.Filter(allProjects, func(project *projects.Project, index int) bool { + return project.Name != spaceManagementProject + }) - if err != nil { - s.logs.SetText("🔴 Failed to get the library variable set Octoterra:\n" + err.Error()) - return + lvsExists, lvs, err := query.LibraryVariableSetExists(myclient) + + if err != nil { + handleError("🔴 Failed to get the library variable set Octoterra", err) + return + } + + if !lvsExists { + handleError("🔴 The library variable set Octoterra could not be found", errors.New("resource not found")) + return + } + + // First look deletes any existing projects + for _, project := range allProjects { + if project.Name == spaceManagementProject { + continue } - if !lvsExists { - s.logs.SetText("🔴 The library variable set Octoterra could not be found") + runbookExists, runbook, err := s.runbookExists(myclient, project.ID, "__ 1. Serialize Project") + + if err != nil { + handleError("🔴 Failed to find runbook", err) return } - // First look deletes any existing projects - for _, project := range allProjects { - if project.Name == spaceManagementProject { - continue + if runbookExists { + deleteRunbook1Func := func(b bool) { + if b { + if err := s.deleteRunbook(myclient, runbook); err != nil { + s.result.SetText("🔴 Failed to delete the resource") + s.logs.SetText(err.Error()) + } else if s.State.PromptForDelete { + s.Execute(prompt, handleError, handleSuccess) + } + } } - runbookExists, runbook, err := s.runbookExists(myclient, project.ID, "__ 1. Serialize Project") - - if err != nil { - s.logs.SetText("🔴 Failed to find runbook:\n" + err.Error()) + if s.State.PromptForDelete { + prompt("Project Group Exists", "The runbook \""+runbook.Name+"\" already exists in project "+project.Name+". Do you want to delete it? It is usually safe to delete this resource.", deleteRunbook1Func) return + } else { + deleteRunbook1Func(true) } + } - if runbookExists { - deleteRunbook1Func := func(b bool) { - if b { - if err := s.deleteRunbook(myclient, runbook); err != nil { - s.result.SetText("🔴 Failed to delete the resource") - s.logs.SetText(err.Error()) - } else if s.State.PromptForDelete { - s.createNewProject(parent) - } - } - } + runbook2Exists, runbook2, err := s.runbookExists(myclient, project.ID, "__ 2. Deploy Project") - if s.State.PromptForDelete { - dialog.NewConfirm("Project Group Exists", "The runbook \""+runbook.Name+"\" already exists in project "+project.Name+". Do you want to delete it? It is usually safe to delete this resource.", deleteRunbook1Func, parent).Show() + if err != nil { + handleError("🔴 Failed to find runbook", err) + return + } - // We can't go further until the resource is deleted - return - } else { - deleteRunbook1Func(true) + if runbook2Exists { + deleteRunbook2Func := func(b bool) { + if b { + if err := s.deleteRunbook(myclient, runbook2); err != nil { + s.result.SetText("🔴 Failed to delete the resource") + s.logs.SetText(err.Error()) + } else if s.State.PromptForDelete { + s.Execute(prompt, handleError, handleSuccess) + } } } - runbook2Exists, runbook2, err := s.runbookExists(myclient, project.ID, "__ 2. Deploy Project") - - if err != nil { - s.logs.SetText("🔴 Failed to find runbook:\n" + err.Error()) + if s.State.PromptForDelete { + prompt("Project Group Exists", "The runbook \""+runbook2.Name+"\" already exists in project "+project.Name+". Do you want to delete it? It is usually safe to delete this resource.", deleteRunbook2Func) return + } else { + deleteRunbook2Func(true) } + } + } - if runbook2Exists { - deleteRunbook2Func := func(b bool) { - if b { - if err := s.deleteRunbook(myclient, runbook2); err != nil { - s.result.SetText("🔴 Failed to delete the resource") - s.logs.SetText(err.Error()) - } else if s.State.PromptForDelete { - s.createNewProject(parent) - } - } - } + // Find the step template ID + serializeProjectTemplate, err, message := query.GetStepTemplateId(myclient, s.State, "Octopus - Serialize Project to Terraform") - if s.State.PromptForDelete { - dialog.NewConfirm("Project Group Exists", "The runbook \""+runbook2.Name+"\" already exists in project "+project.Name+". Do you want to delete it? It is usually safe to delete this resource.", deleteRunbook2Func, parent).Show() - // We can't go further until the resource is deleted - return - } else { - deleteRunbook2Func(true) - } - } - } + if err != nil { + handleError(message, err) + return + } - // Find the step template ID - serializeProjectTemplate, err, message := query.GetStepTemplateId(myclient, s.State, "Octopus - Serialize Project to Terraform") + deploySpaceTemplateS3, err, message := query.GetStepTemplateId(myclient, s.State, "Octopus - Populate Octoterra Space (S3 Backend)") + if err != nil { + handleError(message, err) + return + } + + for index, project := range allProjects { + // Save and apply the module + dir, err := ioutil.TempDir("", "octoterra") if err != nil { - s.result.SetText(message) - s.logs.SetText(err.Error()) + handleError("An error occurred while creating a temporary directory", err) return } - deploySpaceTemplateS3, err, message := query.GetStepTemplateId(myclient, s.State, "Octopus - Populate Octoterra Space (S3 Backend)") + filePath := filepath.Join(dir, "terraform.tf") - if err != nil { - s.result.SetText(message) - s.logs.SetText(err.Error()) + if err := os.WriteFile(filePath, []byte(runbookModule), 0644); err != nil { + handleError("🔴 An error occurred while writing the Terraform file", err) return } - for index, project := range allProjects { - // Save and apply the module - dir, err := ioutil.TempDir("", "octoterra") - if err != nil { - s.logs.SetText("An error occurred while creating a temporary directory:\n" + err.Error()) - return - } - - filePath := filepath.Join(dir, "terraform.tf") - - if err := os.WriteFile(filePath, []byte(runbookModule), 0644); err != nil { - s.logs.SetText("🔴 An error occurred while writing the Terraform file:\n" + err.Error()) - return - } + initCmd := exec.Command("terraform", "init", "-no-color") + initCmd.Dir = dir - initCmd := exec.Command("terraform", "init", "-no-color") - initCmd.Dir = dir - - var initStdout, initStderr bytes.Buffer - initCmd.Stdout = &initStdout - initCmd.Stderr = &initStderr - - if err := initCmd.Run(); err != nil { - s.result.SetText("🔴 Terraform init failed.") - s.logs.SetText(initStdout.String() + initCmd.String()) - return - } + var initStdout, initStderr bytes.Buffer + initCmd.Stdout = &initStdout + initCmd.Stderr = &initStderr - applyCmd := exec.Command("terraform", - "apply", - "-auto-approve", - "-no-color", - "-var=octopus_serialize_actiontemplateid="+serializeProjectTemplate, - "-var=octopus_deploys3_actiontemplateid="+deploySpaceTemplateS3, - "-var=octopus_server="+s.State.Server, - "-var=octopus_apikey="+s.State.ApiKey, - "-var=octopus_space_id="+s.State.Space, - "-var=octopus_project_id="+project.ID, - "-var=terraform_state_bucket="+s.State.AwsS3Bucket, - "-var=terraform_state_bucket_region="+s.State.AwsS3BucketRegion, - "-var=octopus_destination_server="+s.State.DestinationServer, - "-var=octopus_destination_apikey="+s.State.DestinationApiKey, - "-var=octopus_destination_space_id="+s.State.DestinationSpace, - "-var=octopus_project_name="+project.Name) - applyCmd.Dir = dir - - var stdout, stderr bytes.Buffer - applyCmd.Stdout = &stdout - applyCmd.Stderr = &stderr - - if err := applyCmd.Run(); err != nil { - s.result.SetText("🔴 Terraform apply failed") - s.logs.SetText(stdout.String() + stderr.String()) - return - } else { - s.result.SetText("🔵 Terraform apply succeeded (" + fmt.Sprint(index) + " / " + fmt.Sprint(len(allProjects)) + ")") - s.logs.SetText(stdout.String() + stderr.String()) - } + if err := initCmd.Run(); err != nil { + handleError("🔴 Terraform init failed.", errors.New(initStdout.String()+initCmd.String())) + return + } - // link the library variable set - project, err := myclient.Projects.GetByID(project.ID) + applyCmd := exec.Command("terraform", + "apply", + "-auto-approve", + "-no-color", + "-var=octopus_serialize_actiontemplateid="+serializeProjectTemplate, + "-var=octopus_deploys3_actiontemplateid="+deploySpaceTemplateS3, + "-var=octopus_server="+s.State.Server, + "-var=octopus_apikey="+s.State.ApiKey, + "-var=octopus_space_id="+s.State.Space, + "-var=octopus_project_id="+project.ID, + "-var=terraform_state_bucket="+s.State.AwsS3Bucket, + "-var=terraform_state_bucket_region="+s.State.AwsS3BucketRegion, + "-var=octopus_destination_server="+s.State.DestinationServer, + "-var=octopus_destination_apikey="+s.State.DestinationApiKey, + "-var=octopus_destination_space_id="+s.State.DestinationSpace, + "-var=octopus_project_name="+project.Name) + applyCmd.Dir = dir + + var stdout, stderr bytes.Buffer + applyCmd.Stdout = &stdout + applyCmd.Stderr = &stderr + + if err := applyCmd.Run(); err != nil { + handleError("🔴 Terraform apply failed", errors.New(stdout.String()+stderr.String())) + return + } else { + handleSuccess("🔵 Terraform apply succeeded (" + fmt.Sprint(index) + " / " + fmt.Sprint(len(allProjects)) + ")") + } - if err != nil { - s.logs.SetText("🔴 Failed to get the project:\n" + err.Error()) - return - } + // link the library variable set + project, err := myclient.Projects.GetByID(project.ID) - project.IncludedLibraryVariableSets = append(project.IncludedLibraryVariableSets, lvs.ID) + if err != nil { + handleError("🔴 Failed to get the project", err) + return + } - _, err = projects.Update(myclient, project) + project.IncludedLibraryVariableSets = append(project.IncludedLibraryVariableSets, lvs.ID) - if err != nil { - s.logs.SetText("🔴 Failed to update the project:\n" + err.Error()) - return - } + _, err = projects.Update(myclient, project) + if err != nil { + handleError("🔴 Failed to update the project", err) + return } - s.result.SetText("🟢 Added runbooks to all projects") - s.next.Enable() - }() + } + + handleSuccess("🟢 Added runbooks to all projects") } func (s ProjectExportStep) getProjects(myclient *client.Client) ([]*projects.Project, error) { diff --git a/internal/steps/space_export.go b/internal/steps/space_export.go index 47013ba..8007f4a 100644 --- a/internal/steps/space_export.go +++ b/internal/steps/space_export.go @@ -82,7 +82,7 @@ func (s SpaceExportStep) GetContainer(parent fyne.Window) *fyne.Container { s.logs.Disable() s.logs.MultiLine = true s.logs.SetMinRowsVisible(20) - s.createProject = widget.NewButton("Create Project", func() { s.createNewProject(parent, false, false) }) + s.createProject = widget.NewButton("Create Project", func() { s.createNewProject(parent) }) middle := container.New(layout.NewVBoxLayout(), intro, s.createProject, s.infinite, s.result, s.logs) content := container.NewBorder(nil, bottom, nil, nil, middle) @@ -90,7 +90,7 @@ func (s SpaceExportStep) GetContainer(parent fyne.Window) *fyne.Container { return content } -func (s SpaceExportStep) createNewProject(parent fyne.Window, attemptedLvsDelete bool, attemptedAccountDelete bool) { +func (s SpaceExportStep) createNewProject(parent fyne.Window) { s.logs.SetText("") s.next.Disable() s.previous.Disable()