From 730bd3c390e235649e8b12e44c80844e32eb5c93 Mon Sep 17 00:00:00 2001 From: baalooos Date: Thu, 17 Oct 2024 14:16:41 +0200 Subject: [PATCH] refacto to split cmd and functions --- cmd/application_update.go | 70 +------ cmd/environment_clone.go | 57 +----- cmd/environment_deploy.go | 398 +------------------------------------ go.mod | 34 ++-- go.sum | 34 ++++ pkg/application/update.go | 82 ++++++++ pkg/environment/clone.go | 69 +++++++ pkg/environment/deploy.go | 404 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 616 insertions(+), 532 deletions(-) create mode 100644 pkg/application/update.go create mode 100644 pkg/environment/clone.go create mode 100644 pkg/environment/deploy.go diff --git a/cmd/application_update.go b/cmd/application_update.go index 8b6979b7..7b0e2a5a 100644 --- a/cmd/application_update.go +++ b/cmd/application_update.go @@ -1,12 +1,11 @@ package cmd import ( - "context" "fmt" "os" "github.com/pterm/pterm" - "github.com/qovery/qovery-client-go" + "github.com/qovery/qovery-cli/pkg/application" "github.com/spf13/cobra" "github.com/qovery/qovery-cli/utils" @@ -34,73 +33,12 @@ var applicationUpdateCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } - applications, _, err := client.ApplicationsAPI.ListApplication(context.Background(), envId).Execute() - - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - application := utils.FindByApplicationName(applications.GetResults(), applicationName) - - if application == nil { - utils.PrintlnError(fmt.Errorf("application %s not found", applicationName)) - utils.PrintlnInfo("You can list all applications with: qovery application list") - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - var storage []qovery.ServiceStorageRequestStorageInner - for _, s := range application.Storage { - storage = append(storage, qovery.ServiceStorageRequestStorageInner{ - Id: &s.Id, - Type: s.Type, - Size: s.Size, - MountPoint: s.MountPoint, - }) - } - - req := qovery.ApplicationEditRequest{ - Storage: storage, - Name: &application.Name, - Description: application.Description, - GitRepository: &qovery.ApplicationGitRepositoryRequest{ - Branch: application.GitRepository.Branch, - GitTokenId: application.GitRepository.GitTokenId, - RootPath: application.GitRepository.RootPath, - Url: application.GitRepository.Url, - }, - BuildMode: application.BuildMode, - DockerfilePath: application.DockerfilePath, - BuildpackLanguage: application.BuildpackLanguage, - Cpu: application.Cpu, - Memory: application.Memory, - MinRunningInstances: application.MinRunningInstances, - MaxRunningInstances: application.MaxRunningInstances, - Healthchecks: application.Healthchecks, - AutoPreview: application.AutoPreview, - Ports: application.Ports, - Arguments: application.Arguments, - Entrypoint: application.Entrypoint, - AutoDeploy: *qovery.NewNullableBool(application.AutoDeploy), - } - - if applicationBranch != "" { - req.GitRepository.Branch = &applicationBranch - } - + var changeAutoDeploy = false if cmd.Flags().Changed("auto-deploy") { - req.AutoDeploy = *qovery.NewNullableBool(&applicationAutoDeploy) + changeAutoDeploy = true } - _, _, err = client.ApplicationMainCallsAPI.EditApplication(context.Background(), application.Id).ApplicationEditRequest(req).Execute() - - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } + application.ApplicationUpdate(client, envId, applicationName, applicationBranch, applicationAutoDeploy, changeAutoDeploy) utils.Println(fmt.Sprintf("Application %s updated!", pterm.FgBlue.Sprintf("%s", applicationName))) }, diff --git a/cmd/environment_clone.go b/cmd/environment_clone.go index a2d55d2d..768d1e42 100644 --- a/cmd/environment_clone.go +++ b/cmd/environment_clone.go @@ -1,14 +1,10 @@ package cmd import ( - "context" - "github.com/go-errors/errors" - "io" "os" - "strings" + "github.com/qovery/qovery-cli/pkg/environment" "github.com/qovery/qovery-cli/utils" - "github.com/qovery/qovery-client-go" "github.com/spf13/cobra" ) @@ -34,56 +30,9 @@ var environmentCloneCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } - req := qovery.CloneEnvironmentRequest{ - Name: newEnvironmentName, - ApplyDeploymentRule: &applyDeploymentRule, - } - - if clusterName != "" { - clusters, _, err := client.ClustersAPI.ListOrganizationCluster(context.Background(), orgId).Execute() - - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - if err == nil { - for _, c := range clusters.GetResults() { - if strings.EqualFold(c.Name, clusterName) { - req.ClusterId = &c.Id - break - } - } - } - } - - if environmentType != "" { - switch strings.ToUpper(environmentType) { - case "DEVELOPMENT": - req.Mode = qovery.EnvironmentModeEnum.Ptr(qovery.ENVIRONMENTMODEENUM_DEVELOPMENT) - case "PRODUCTION": - req.Mode = qovery.EnvironmentModeEnum.Ptr(qovery.ENVIRONMENTMODEENUM_PRODUCTION) - case "STAGING": - req.Mode = qovery.EnvironmentModeEnum.Ptr(qovery.ENVIRONMENTMODEENUM_STAGING) - } - } - - _, res, err := client.EnvironmentActionsAPI.CloneEnvironment(context.Background(), envId).CloneEnvironmentRequest(req).Execute() - - if err != nil { - // print http body error message - if res != nil && !strings.Contains(res.Status, "200") { - result, _ := io.ReadAll(res.Body) - utils.PrintlnError(errors.Errorf("status code: %s ; body: %s", res.Status, string(result))) - } - - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } + var newEnvId = environment.EnvironmentClone(client, organizationName, projectName, environmentName, newEnvironmentName, clusterName, environmentType, applyDeploymentRule, orgId, envId) - utils.Println("Environment is cloned!") + utils.Println("your new environment ID is: " + newEnvId.Id) }, } diff --git a/cmd/environment_deploy.go b/cmd/environment_deploy.go index 17196047..a024786a 100644 --- a/cmd/environment_deploy.go +++ b/cmd/environment_deploy.go @@ -1,19 +1,11 @@ package cmd import ( - "context" - "encoding/json" - "fmt" - "github.com/pterm/pterm" "os" - "slices" - "strings" - "time" - - "github.com/qovery/qovery-client-go" - "github.com/spf13/cobra" + "github.com/qovery/qovery-cli/pkg/environment" "github.com/qovery/qovery-cli/utils" + "github.com/spf13/cobra" ) var skipPausedServicesFlag bool @@ -40,394 +32,10 @@ var environmentDeployCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } - if (servicesJson != "" || applicationNames != "" || containerNames != "" || lifecycleNames != "" || - cronjobNames != "" || helmNames != "") && skipPausedServicesFlag { - utils.PrintlnError(fmt.Errorf("you can't use --skip-paused-services flag with --services, " + - "--applications, --containers, --lifecycles, --cronjobs or --helms flags")) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - // wait until service is ready - for { - if utils.IsEnvironmentInATerminalState(envId, client) { - break - } - - utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf("%s", envId))) - time.Sleep(5 * time.Second) - } - - if servicesJson != "" { - // convert servicesJson to DeployAllRequest - var deployAllRequest qovery.DeployAllRequest - err := json.Unmarshal([]byte(servicesJson), &deployAllRequest) - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - _, _, err = client.EnvironmentActionsAPI.DeployAllServices(context.Background(), envId).DeployAllRequest(deployAllRequest).Execute() - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - utils.Println("Services are deploying!") - } else if applicationNames != "" || containerNames != "" || lifecycleNames != "" || cronjobNames != "" || helmNames != "" { - deploymentRequest := getDeploymentRequestForMultipleServices(client, envId, applicationNames, containerNames, lifecycleNames, cronjobNames, helmNames) - _, _, err = client.EnvironmentActionsAPI.DeployAllServices(context.Background(), envId).DeployAllRequest(deploymentRequest).Execute() - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - utils.Println("Services are deploying!") - } - - if skipPausedServicesFlag { - // Paused services shouldn't be deployed, let's gather services status - servicesIDsToDeploy, err := getEligibleServices(client, envId, []qovery.StateEnum{qovery.STATEENUM_STOPPED}) - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - // Deploy the non stopped services from the env - request := qovery.DeployAllRequest{} - // Adding services to be deployed - for _, applicationID := range servicesIDsToDeploy.ApplicationsIDs { - request.Applications = append(request.Applications, qovery.DeployAllRequestApplicationsInner{ApplicationId: applicationID}) - utils.Println(fmt.Sprintf("Application %s is deploying!", applicationID)) - } - for _, containerID := range servicesIDsToDeploy.ContainersIDs { - request.Containers = append(request.Containers, qovery.DeployAllRequestContainersInner{Id: containerID}) - utils.Println(fmt.Sprintf("Container %s is deploying!", containerID)) - } - for _, helmID := range servicesIDsToDeploy.HelmsIDs { - request.Helms = append(request.Helms, qovery.DeployAllRequestHelmsInner{Id: &helmID}) - utils.Println(fmt.Sprintf("Helm %s is deploying!", helmID)) - } - for _, jobID := range servicesIDsToDeploy.JobsIDs { - request.Jobs = append(request.Jobs, qovery.DeployAllRequestJobsInner{Id: &jobID}) - utils.Println(fmt.Sprintf("Job %s is deploying!", jobID)) - } - for _, databaseID := range servicesIDsToDeploy.DatabasesIDs { - request.Databases = append(request.Databases, databaseID) - utils.Println(fmt.Sprintf("Database %s is deploying!", databaseID)) - } - - _, _, err = client.EnvironmentActionsAPI.DeployAllServices(context.Background(), envId).DeployAllRequest(request).Execute() - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - } else if servicesJson == "" && applicationNames == "" && containerNames == "" && lifecycleNames == "" && - cronjobNames == "" && helmNames == "" { - // Deploy the whole env - _, _, err = client.EnvironmentActionsAPI.DeployEnvironment(context.Background(), envId).Execute() - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - utils.Println("Environment is deploying!") - } - - if watchFlag { - utils.WatchEnvironment(envId, qovery.STATEENUM_DEPLOYED, client) - } + environment.EnvironmentDeploy(client, organizationName, projectName, environmentName, newEnvironmentName, clusterName, environmentType, applyDeploymentRule, envId, servicesJson, applicationNames, containerNames, lifecycleNames, cronjobNames, helmNames, skipPausedServicesFlag, watchFlag) }, } -/** - * Get deployment request for multiple services - */ -func getDeploymentRequestForMultipleServices( - client *qovery.APIClient, - envId string, - applicationNames string, - containerNames string, - lifecycleNames string, - cronjobNames string, - helmNames string, -) qovery.DeployAllRequest { - // Deploy the services from the env - request := qovery.DeployAllRequest{} - - if applicationNames != "" { - // Adding applications to be deployed - for _, nameAndVersion := range strings.Split(applicationNames, ",") { - name, version := splitServiceNameAndVersion(nameAndVersion) - - apps, _, err := client.ApplicationsAPI.ListApplication(context.Background(), envId).Execute() - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - app := utils.FindByApplicationName(apps.GetResults(), name) - - if app == nil { - utils.PrintlnError(fmt.Errorf("application %s not found", name)) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - request.Applications = append(request.Applications, qovery.DeployAllRequestApplicationsInner{ApplicationId: app.Id, GitCommitId: version}) - } - } - - if containerNames != "" { - // Adding containers to be deployed - for _, nameAndVersion := range strings.Split(containerNames, ",") { - name, version := splitServiceNameAndVersion(nameAndVersion) - - containers, _, err := client.ContainersAPI.ListContainer(context.Background(), envId).Execute() - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - container := utils.FindByContainerName(containers.GetResults(), name) - - request.Containers = append(request.Containers, qovery.DeployAllRequestContainersInner{Id: container.Id, ImageTag: version}) - } - } - - if lifecycleNames != "" || cronjobNames != "" { - jobs, _, err := client.JobsAPI.ListJobs(context.Background(), envId).Execute() - - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - if lifecycleNames != "" { - // Adding lifecycle to be deployed - for _, nameAndVersion := range strings.Split(lifecycleNames, ",") { - name, version := splitServiceNameAndVersion(nameAndVersion) - job, gitCommitId, imageTag := getLifecycleJobGitCommitAndImageTag(jobs.GetResults(), name) - - if job == nil { - utils.PrintlnError(fmt.Errorf("lifecycle %s not found", name)) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - req := qovery.DeployAllRequestJobsInner{Id: &job.LifecycleJobResponse.Id} - if gitCommitId != nil { - req.GitCommitId = version - } else if imageTag != nil { - req.ImageTag = version - } - - request.Jobs = append(request.Jobs, req) - } - } - - if cronjobNames != "" { - // Adding cronjobs to be deployed - for _, nameAndVersion := range strings.Split(cronjobNames, ",") { - name, version := splitServiceNameAndVersion(nameAndVersion) - - job, gitCommitId, imageTag := getCronjobGitCommitAndImageTag(jobs.GetResults(), name) - - if job == nil { - utils.PrintlnError(fmt.Errorf("cronjob %s not found", name)) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - req := qovery.DeployAllRequestJobsInner{Id: &job.CronJobResponse.Id} - if gitCommitId != nil { - req.GitCommitId = version - } else if imageTag != nil { - req.ImageTag = version - } - - request.Jobs = append(request.Jobs, req) - } - } - } - - if helmNames != "" { - // Adding helms to be deployed - for _, nameAndVersion := range strings.Split(helmNames, ",") { - name, version := splitServiceNameAndVersion(nameAndVersion) - - helms, _, err := client.HelmsAPI.ListHelms(context.Background(), envId).Execute() - - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - helm := utils.FindByHelmName(helms.GetResults(), name) - - if helm == nil { - utils.PrintlnError(fmt.Errorf("helm %s not found", name)) - os.Exit(1) - panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 - } - - gitCommitId, chartVersion := getHelmCommitAndChartVersion(client, name) - - req := qovery.DeployAllRequestHelmsInner{Id: &helm.Id} - if gitCommitId != nil { - req.GitCommitId = version - } else if chartVersion != nil { - req.ChartVersion = version - } - - request.Helms = append(request.Helms, req) - } - } - - return request -} - -type Services struct { - ApplicationsIDs []string - ContainersIDs []string - HelmsIDs []string - JobsIDs []string - DatabasesIDs []string -} - -func getEligibleServices(client *qovery.APIClient, envId string, servicesStatusesToExclude []qovery.StateEnum) (Services, error) { - nonStoppedServices := Services{ - ApplicationsIDs: make([]string, 0), - ContainersIDs: make([]string, 0), - HelmsIDs: make([]string, 0), - JobsIDs: make([]string, 0), - DatabasesIDs: make([]string, 0), - } - envStatuses, _, err := client.EnvironmentMainCallsAPI.GetEnvironmentStatuses(context.Background(), envId).Execute() - if err != nil { - return nonStoppedServices, err - } - - // Gather all non-stopped services - for _, serviceStatus := range envStatuses.Applications { - if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { - nonStoppedServices.ApplicationsIDs = append(nonStoppedServices.ApplicationsIDs, serviceStatus.Id) - } - } - for _, serviceStatus := range envStatuses.Containers { - if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { - nonStoppedServices.ContainersIDs = append(nonStoppedServices.ContainersIDs, serviceStatus.Id) - } - } - for _, serviceStatus := range envStatuses.Helms { - if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { - nonStoppedServices.HelmsIDs = append(nonStoppedServices.HelmsIDs, serviceStatus.Id) - } - } - for _, serviceStatus := range envStatuses.Jobs { - if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { - nonStoppedServices.JobsIDs = append(nonStoppedServices.JobsIDs, serviceStatus.Id) - } - } - for _, serviceStatus := range envStatuses.Databases { - if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { - nonStoppedServices.DatabasesIDs = append(nonStoppedServices.DatabasesIDs, serviceStatus.Id) - } - } - - return nonStoppedServices, nil -} - -/** - * Split service name and version (if provided) - */ -func splitServiceNameAndVersion(service string) (string, *string) { - split := strings.Split(service, ":") - if len(split) == 1 { - return split[0], nil - } - - return split[0], &split[1] -} - -func getLifecycleJobGitCommitAndImageTag(jobs []qovery.JobResponse, jobName string) (*qovery.JobResponse, *string, *string) { - var commitId, imageTag *string - - job := utils.FindByJobName(jobs, jobName) - - if job == nil { - return nil, nil, nil - } - - if job.LifecycleJobResponse.Source.BaseJobResponseAllOfSourceOneOf != nil { - // image tag - image := job.LifecycleJobResponse.Source.BaseJobResponseAllOfSourceOneOf.GetImage() - tag := image.GetTag() - imageTag = &tag - } else if job.LifecycleJobResponse.Source.BaseJobResponseAllOfSourceOneOf1 != nil { - // commit id - docker := job.LifecycleJobResponse.Source.BaseJobResponseAllOfSourceOneOf1.GetDocker() - commitId = docker.GitRepository.DeployedCommitId - } - - return job, commitId, imageTag -} - -func getCronjobGitCommitAndImageTag(jobs []qovery.JobResponse, jobName string) (*qovery.JobResponse, *string, *string) { - var commitId, imageTag *string - - job := utils.FindByJobName(jobs, jobName) - - if job == nil { - return nil, nil, nil - } - - if job.CronJobResponse.Source.BaseJobResponseAllOfSourceOneOf != nil { - // image tag - image := job.CronJobResponse.Source.BaseJobResponseAllOfSourceOneOf.GetImage() - tag := image.GetTag() - imageTag = &tag - } else if job.CronJobResponse.Source.BaseJobResponseAllOfSourceOneOf1 != nil { - // commit id - docker := job.CronJobResponse.Source.BaseJobResponseAllOfSourceOneOf1.GetDocker() - commitId = docker.GitRepository.DeployedCommitId - } - - return job, commitId, imageTag -} - -func getHelmCommitAndChartVersion(client *qovery.APIClient, helmId string) (*string, *string) { - var commitId, chartVersion *string - - // check if the helm version is a chart version or a commit id - helm, _, err := client.HelmMainCallsAPI.GetHelm(context.Background(), helmId).Execute() - if err != nil { - utils.PrintlnError(err) - os.Exit(1) - } - - if helm.Source.HelmResponseAllOfSourceOneOf != nil { - // chart version - git := helm.Source.HelmResponseAllOfSourceOneOf.GetGit() - commitId = git.GitRepository.DeployedCommitId - } else if helm.Source.HelmResponseAllOfSourceOneOf1 != nil { - // commit id - git := helm.Source.HelmResponseAllOfSourceOneOf1.GetRepository() - chartVersion = &git.ChartVersion - } - - return commitId, chartVersion -} - func init() { environmentCmd.AddCommand(environmentDeployCmd) environmentDeployCmd.Flags().StringVarP(&organizationName, "organization", "", "", "Organization Name") diff --git a/go.mod b/go.mod index 22140b1e..52959ea8 100644 --- a/go.mod +++ b/go.mod @@ -22,15 +22,15 @@ require ( github.com/pkg/errors v0.9.1 github.com/posthog/posthog-go v1.2.24 github.com/pterm/pterm v0.12.79 - github.com/qovery/qovery-client-go v0.0.0-20240918181134-faa9e7a86f41 + github.com/qovery/qovery-client-go v0.0.0-20241008150925-aa04cba97a04 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 github.com/xlab/treeprint v1.2.0 - golang.org/x/net v0.29.0 - golang.org/x/sys v0.25.0 + golang.org/x/net v0.30.0 + golang.org/x/sys v0.26.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -38,12 +38,12 @@ require ( atomicgo.dev/cursor v0.2.0 // indirect atomicgo.dev/keyboard v0.2.9 // indirect atomicgo.dev/schedule v0.1.0 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect - github.com/go-jose/go-jose/v4 v4.0.1 // indirect + github.com/go-jose/go-jose/v4 v4.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/gookit/color v1.5.4 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -51,31 +51,31 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect - github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/klauspost/compress v1.16.0 // indirect - github.com/klauspost/pgzip v1.2.5 // indirect + github.com/klauspost/compress v1.17.10 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/nwaples/rardecode v1.1.3 // indirect - github.com/pierrec/lz4/v4 v4.1.17 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.4.4 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/ulikunitz/xz v0.5.11 // indirect + github.com/ulikunitz/xz v0.5.12 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/term v0.24.0 // indirect - golang.org/x/text v0.18.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.19.0 // indirect + golang.org/x/time v0.7.0 // indirect ) diff --git a/go.sum b/go.sum index 3f0ecbbc..433f2708 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDe github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc h1:LoL75er+LKDHDUfU5tRvFwxH0LjPpZN8OoG8Ll+liGU= github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc/go.mod h1:w648aMHEgFYS6xb0KVMMtZ2uMeemhiKCuD2vj6gY52A= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -59,6 +61,8 @@ github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8b github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= @@ -93,11 +97,15 @@ github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5O github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 h1:iBt4Ew4XEGLfh6/bPk4rSYmuZJGizr6/x/AEizP0CQc= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8/go.mod h1:aiJI+PIApBRQG7FZTEBx5GiiX+HbOHilUdNxUZi4eV0= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= +github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.15.0 h1:O24FYQCWwhwKnF7CuSqP30S51rTV7vz1iACXE/pj5DA= @@ -118,6 +126,8 @@ github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0= +github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -127,6 +137,8 @@ github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y7 github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -148,6 +160,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= @@ -168,6 +182,8 @@ github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWk github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -188,9 +204,13 @@ github.com/pterm/pterm v0.12.79 h1:lH3yrYMhdpeqX9y5Ep1u7DejyHy7NSQg9qrBjF9dFT4= github.com/pterm/pterm v0.12.79/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo= github.com/qovery/qovery-client-go v0.0.0-20240918181134-faa9e7a86f41 h1:O31SMjmmJOSzdZbXPg++TetM0Q3TmvuYa/jOMDkiR4A= github.com/qovery/qovery-client-go v0.0.0-20240918181134-faa9e7a86f41/go.mod h1:9eHj5a4EtXGIyfbvVL3HVYW9k7Xmiwi00OqHrP4dc10= +github.com/qovery/qovery-client-go v0.0.0-20241008150925-aa04cba97a04 h1:bQf+9U+mh6xPsIs1ZlA8noOWNz6U6BC8QOWFNv42yWU= +github.com/qovery/qovery-client-go v0.0.0-20241008150925-aa04cba97a04/go.mod h1:9eHj5a4EtXGIyfbvVL3HVYW9k7Xmiwi00OqHrP4dc10= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= @@ -215,6 +235,8 @@ github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= @@ -227,6 +249,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -237,6 +261,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -260,6 +286,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -267,6 +295,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -275,8 +305,12 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/pkg/application/update.go b/pkg/application/update.go new file mode 100644 index 00000000..78354cc6 --- /dev/null +++ b/pkg/application/update.go @@ -0,0 +1,82 @@ +package application + +import ( + "context" + "fmt" + "os" + + "github.com/qovery/qovery-client-go" + + "github.com/qovery/qovery-cli/utils" +) + +func ApplicationUpdate(client *qovery.APIClient, envId string, applicationName string, applicationBranch string, applicationAutoDeploy bool, changeAutoDeploy bool) { + applications, _, err := client.ApplicationsAPI.ListApplication(context.Background(), envId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + application := utils.FindByApplicationName(applications.GetResults(), applicationName) + + if application == nil { + utils.PrintlnError(fmt.Errorf("application %s not found", applicationName)) + utils.PrintlnInfo("You can list all applications with: qovery application list") + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var storage []qovery.ServiceStorageRequestStorageInner + for _, s := range application.Storage { + storage = append(storage, qovery.ServiceStorageRequestStorageInner{ + Id: &s.Id, + Type: s.Type, + Size: s.Size, + MountPoint: s.MountPoint, + }) + } + + req := qovery.ApplicationEditRequest{ + Storage: storage, + Name: &application.Name, + Description: application.Description, + GitRepository: &qovery.ApplicationGitRepositoryRequest{ + Branch: application.GitRepository.Branch, + GitTokenId: application.GitRepository.GitTokenId, + RootPath: application.GitRepository.RootPath, + Url: application.GitRepository.Url, + }, + BuildMode: application.BuildMode, + DockerfilePath: application.DockerfilePath, + BuildpackLanguage: application.BuildpackLanguage, + Cpu: application.Cpu, + Memory: application.Memory, + MinRunningInstances: application.MinRunningInstances, + MaxRunningInstances: application.MaxRunningInstances, + Healthchecks: application.Healthchecks, + AutoPreview: application.AutoPreview, + Ports: application.Ports, + Arguments: application.Arguments, + Entrypoint: application.Entrypoint, + AutoDeploy: *qovery.NewNullableBool(application.AutoDeploy), + } + + if applicationBranch != "" { + req.GitRepository.Branch = &applicationBranch + } + + if changeAutoDeploy { + req.AutoDeploy = *qovery.NewNullableBool(&applicationAutoDeploy) + } + + _, _, err = client.ApplicationMainCallsAPI.EditApplication(context.Background(), application.Id).ApplicationEditRequest(req).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + +} diff --git a/pkg/environment/clone.go b/pkg/environment/clone.go new file mode 100644 index 00000000..152f92d7 --- /dev/null +++ b/pkg/environment/clone.go @@ -0,0 +1,69 @@ +package environment + +import ( + "context" + "io" + "os" + "strings" + + "github.com/go-errors/errors" + + "github.com/qovery/qovery-cli/utils" + "github.com/qovery/qovery-client-go" +) + +func EnvironmentClone(client *qovery.APIClient, organizationName string, projectName string, environmentName string, newEnvironmentName string, clusterName string, environmentType string, applyDeploymentRule bool, orgId string, envId string) *qovery.Environment { + + req := qovery.CloneEnvironmentRequest{ + Name: newEnvironmentName, + ApplyDeploymentRule: &applyDeploymentRule, + } + + if clusterName != "" { + clusters, _, err := client.ClustersAPI.ListOrganizationCluster(context.Background(), orgId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if err == nil { + for _, c := range clusters.GetResults() { + if strings.EqualFold(c.Name, clusterName) { + req.ClusterId = &c.Id + break + } + } + } + } + + if environmentType != "" { + switch strings.ToUpper(environmentType) { + case "DEVELOPMENT": + req.Mode = qovery.EnvironmentModeEnum.Ptr(qovery.ENVIRONMENTMODEENUM_DEVELOPMENT) + case "PRODUCTION": + req.Mode = qovery.EnvironmentModeEnum.Ptr(qovery.ENVIRONMENTMODEENUM_PRODUCTION) + case "STAGING": + req.Mode = qovery.EnvironmentModeEnum.Ptr(qovery.ENVIRONMENTMODEENUM_STAGING) + } + } + + cloneRequestAnswer, res, err := client.EnvironmentActionsAPI.CloneEnvironment(context.Background(), envId).CloneEnvironmentRequest(req).Execute() + + if err != nil { + // print http body error message + if res != nil && !strings.Contains(res.Status, "200") { + result, _ := io.ReadAll(res.Body) + utils.PrintlnError(errors.Errorf("status code: %s ; body: %s", res.Status, string(result))) + } + + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + utils.Println("Environment is cloned!") + + return cloneRequestAnswer +} diff --git a/pkg/environment/deploy.go b/pkg/environment/deploy.go new file mode 100644 index 00000000..c568debe --- /dev/null +++ b/pkg/environment/deploy.go @@ -0,0 +1,404 @@ +package environment + +import ( + "context" + "encoding/json" + "fmt" + "github.com/pterm/pterm" + "os" + "slices" + "strings" + "time" + + "github.com/qovery/qovery-cli/utils" + "github.com/qovery/qovery-client-go" +) + +func EnvironmentDeploy(client *qovery.APIClient, organizationName string, projectName string, environmentName string, newEnvironmentName string, clusterName string, environmentType string, applyDeploymentRule bool, envId string, servicesJson string, applicationNames string, containerNames string, lifecycleNames string, cronjobNames string, helmNames string, skipPausedServicesFlag bool, watchFlag bool) { + + if (servicesJson != "" || applicationNames != "" || containerNames != "" || lifecycleNames != "" || + cronjobNames != "" || helmNames != "") && skipPausedServicesFlag { + utils.PrintlnError(fmt.Errorf("you can't use --skip-paused-services flag with --services, " + + "--applications, --containers, --lifecycles, --cronjobs or --helms flags")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + if servicesJson != "" { + // convert servicesJson to DeployAllRequest + var deployAllRequest qovery.DeployAllRequest + err := json.Unmarshal([]byte(servicesJson), &deployAllRequest) + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + _, _, err = client.EnvironmentActionsAPI.DeployAllServices(context.Background(), envId).DeployAllRequest(deployAllRequest).Execute() + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + utils.Println("Services are deploying!") + } else if applicationNames != "" || containerNames != "" || lifecycleNames != "" || cronjobNames != "" || helmNames != "" { + deploymentRequest := getDeploymentRequestForMultipleServices(client, envId, applicationNames, containerNames, lifecycleNames, cronjobNames, helmNames) + _, _, err := client.EnvironmentActionsAPI.DeployAllServices(context.Background(), envId).DeployAllRequest(deploymentRequest).Execute() + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + utils.Println("Services are deploying!") + } + + if skipPausedServicesFlag { + // Paused services shouldn't be deployed, let's gather services status + servicesIDsToDeploy, err := getEligibleServices(client, envId, []qovery.StateEnum{qovery.STATEENUM_STOPPED}) + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + // Deploy the non stopped services from the env + request := qovery.DeployAllRequest{} + // Adding services to be deployed + for _, applicationID := range servicesIDsToDeploy.ApplicationsIDs { + request.Applications = append(request.Applications, qovery.DeployAllRequestApplicationsInner{ApplicationId: applicationID}) + utils.Println(fmt.Sprintf("Application %s is deploying!", applicationID)) + } + for _, containerID := range servicesIDsToDeploy.ContainersIDs { + request.Containers = append(request.Containers, qovery.DeployAllRequestContainersInner{Id: containerID}) + utils.Println(fmt.Sprintf("Container %s is deploying!", containerID)) + } + for _, helmID := range servicesIDsToDeploy.HelmsIDs { + request.Helms = append(request.Helms, qovery.DeployAllRequestHelmsInner{Id: &helmID}) + utils.Println(fmt.Sprintf("Helm %s is deploying!", helmID)) + } + for _, jobID := range servicesIDsToDeploy.JobsIDs { + request.Jobs = append(request.Jobs, qovery.DeployAllRequestJobsInner{Id: &jobID}) + utils.Println(fmt.Sprintf("Job %s is deploying!", jobID)) + } + for _, databaseID := range servicesIDsToDeploy.DatabasesIDs { + request.Databases = append(request.Databases, databaseID) + utils.Println(fmt.Sprintf("Database %s is deploying!", databaseID)) + } + + _, _, err = client.EnvironmentActionsAPI.DeployAllServices(context.Background(), envId).DeployAllRequest(request).Execute() + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + } else if servicesJson == "" && applicationNames == "" && containerNames == "" && lifecycleNames == "" && + cronjobNames == "" && helmNames == "" { + // Deploy the whole env + _, _, err := client.EnvironmentActionsAPI.DeployEnvironment(context.Background(), envId).Execute() + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + utils.Println("Environment is deploying!") + } + + if watchFlag { + utils.WatchEnvironment(envId, qovery.STATEENUM_DEPLOYED, client) + } +} + +/** + * Get deployment request for multiple services + */ +func getDeploymentRequestForMultipleServices( + client *qovery.APIClient, + envId string, + applicationNames string, + containerNames string, + lifecycleNames string, + cronjobNames string, + helmNames string, +) qovery.DeployAllRequest { + // Deploy the services from the env + request := qovery.DeployAllRequest{} + + if applicationNames != "" { + // Adding applications to be deployed + for _, nameAndVersion := range strings.Split(applicationNames, ",") { + name, version := splitServiceNameAndVersion(nameAndVersion) + + apps, _, err := client.ApplicationsAPI.ListApplication(context.Background(), envId).Execute() + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + app := utils.FindByApplicationName(apps.GetResults(), name) + + if app == nil { + utils.PrintlnError(fmt.Errorf("application %s not found", name)) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + request.Applications = append(request.Applications, qovery.DeployAllRequestApplicationsInner{ApplicationId: app.Id, GitCommitId: version}) + } + } + + if containerNames != "" { + // Adding containers to be deployed + for _, nameAndVersion := range strings.Split(containerNames, ",") { + name, version := splitServiceNameAndVersion(nameAndVersion) + + containers, _, err := client.ContainersAPI.ListContainer(context.Background(), envId).Execute() + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + container := utils.FindByContainerName(containers.GetResults(), name) + + request.Containers = append(request.Containers, qovery.DeployAllRequestContainersInner{Id: container.Id, ImageTag: version}) + } + } + + if lifecycleNames != "" || cronjobNames != "" { + jobs, _, err := client.JobsAPI.ListJobs(context.Background(), envId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if lifecycleNames != "" { + // Adding lifecycle to be deployed + for _, nameAndVersion := range strings.Split(lifecycleNames, ",") { + name, version := splitServiceNameAndVersion(nameAndVersion) + job, gitCommitId, imageTag := getLifecycleJobGitCommitAndImageTag(jobs.GetResults(), name) + + if job == nil { + utils.PrintlnError(fmt.Errorf("lifecycle %s not found", name)) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + req := qovery.DeployAllRequestJobsInner{Id: &job.LifecycleJobResponse.Id} + if gitCommitId != nil { + req.GitCommitId = version + } else if imageTag != nil { + req.ImageTag = version + } + + request.Jobs = append(request.Jobs, req) + } + } + + if cronjobNames != "" { + // Adding cronjobs to be deployed + for _, nameAndVersion := range strings.Split(cronjobNames, ",") { + name, version := splitServiceNameAndVersion(nameAndVersion) + + job, gitCommitId, imageTag := getCronjobGitCommitAndImageTag(jobs.GetResults(), name) + + if job == nil { + utils.PrintlnError(fmt.Errorf("cronjob %s not found", name)) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + req := qovery.DeployAllRequestJobsInner{Id: &job.CronJobResponse.Id} + if gitCommitId != nil { + req.GitCommitId = version + } else if imageTag != nil { + req.ImageTag = version + } + + request.Jobs = append(request.Jobs, req) + } + } + } + + if helmNames != "" { + // Adding helms to be deployed + for _, nameAndVersion := range strings.Split(helmNames, ",") { + name, version := splitServiceNameAndVersion(nameAndVersion) + + helms, _, err := client.HelmsAPI.ListHelms(context.Background(), envId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + helm := utils.FindByHelmName(helms.GetResults(), name) + + if helm == nil { + utils.PrintlnError(fmt.Errorf("helm %s not found", name)) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + gitCommitId, chartVersion := getHelmCommitAndChartVersion(client, name) + + req := qovery.DeployAllRequestHelmsInner{Id: &helm.Id} + if gitCommitId != nil { + req.GitCommitId = version + } else if chartVersion != nil { + req.ChartVersion = version + } + + request.Helms = append(request.Helms, req) + } + } + + return request +} + +type Services struct { + ApplicationsIDs []string + ContainersIDs []string + HelmsIDs []string + JobsIDs []string + DatabasesIDs []string +} + +func getEligibleServices(client *qovery.APIClient, envId string, servicesStatusesToExclude []qovery.StateEnum) (Services, error) { + nonStoppedServices := Services{ + ApplicationsIDs: make([]string, 0), + ContainersIDs: make([]string, 0), + HelmsIDs: make([]string, 0), + JobsIDs: make([]string, 0), + DatabasesIDs: make([]string, 0), + } + envStatuses, _, err := client.EnvironmentMainCallsAPI.GetEnvironmentStatuses(context.Background(), envId).Execute() + if err != nil { + return nonStoppedServices, err + } + + // Gather all non-stopped services + for _, serviceStatus := range envStatuses.Applications { + if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { + nonStoppedServices.ApplicationsIDs = append(nonStoppedServices.ApplicationsIDs, serviceStatus.Id) + } + } + for _, serviceStatus := range envStatuses.Containers { + if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { + nonStoppedServices.ContainersIDs = append(nonStoppedServices.ContainersIDs, serviceStatus.Id) + } + } + for _, serviceStatus := range envStatuses.Helms { + if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { + nonStoppedServices.HelmsIDs = append(nonStoppedServices.HelmsIDs, serviceStatus.Id) + } + } + for _, serviceStatus := range envStatuses.Jobs { + if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { + nonStoppedServices.JobsIDs = append(nonStoppedServices.JobsIDs, serviceStatus.Id) + } + } + for _, serviceStatus := range envStatuses.Databases { + if !slices.Contains(servicesStatusesToExclude, serviceStatus.GetState()) { + nonStoppedServices.DatabasesIDs = append(nonStoppedServices.DatabasesIDs, serviceStatus.Id) + } + } + + return nonStoppedServices, nil +} + +/** + * Split service name and version (if provided) + */ +func splitServiceNameAndVersion(service string) (string, *string) { + split := strings.Split(service, ":") + if len(split) == 1 { + return split[0], nil + } + + return split[0], &split[1] +} + +func getLifecycleJobGitCommitAndImageTag(jobs []qovery.JobResponse, jobName string) (*qovery.JobResponse, *string, *string) { + var commitId, imageTag *string + + job := utils.FindByJobName(jobs, jobName) + + if job == nil { + return nil, nil, nil + } + + if job.LifecycleJobResponse.Source.BaseJobResponseAllOfSourceOneOf != nil { + // image tag + image := job.LifecycleJobResponse.Source.BaseJobResponseAllOfSourceOneOf.GetImage() + tag := image.GetTag() + imageTag = &tag + } else if job.LifecycleJobResponse.Source.BaseJobResponseAllOfSourceOneOf1 != nil { + // commit id + docker := job.LifecycleJobResponse.Source.BaseJobResponseAllOfSourceOneOf1.GetDocker() + commitId = docker.GitRepository.DeployedCommitId + } + + return job, commitId, imageTag +} + +func getCronjobGitCommitAndImageTag(jobs []qovery.JobResponse, jobName string) (*qovery.JobResponse, *string, *string) { + var commitId, imageTag *string + + job := utils.FindByJobName(jobs, jobName) + + if job == nil { + return nil, nil, nil + } + + if job.CronJobResponse.Source.BaseJobResponseAllOfSourceOneOf != nil { + // image tag + image := job.CronJobResponse.Source.BaseJobResponseAllOfSourceOneOf.GetImage() + tag := image.GetTag() + imageTag = &tag + } else if job.CronJobResponse.Source.BaseJobResponseAllOfSourceOneOf1 != nil { + // commit id + docker := job.CronJobResponse.Source.BaseJobResponseAllOfSourceOneOf1.GetDocker() + commitId = docker.GitRepository.DeployedCommitId + } + + return job, commitId, imageTag +} + +func getHelmCommitAndChartVersion(client *qovery.APIClient, helmId string) (*string, *string) { + var commitId, chartVersion *string + + // check if the helm version is a chart version or a commit id + helm, _, err := client.HelmMainCallsAPI.GetHelm(context.Background(), helmId).Execute() + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + } + + if helm.Source.HelmResponseAllOfSourceOneOf != nil { + // chart version + git := helm.Source.HelmResponseAllOfSourceOneOf.GetGit() + commitId = git.GitRepository.DeployedCommitId + } else if helm.Source.HelmResponseAllOfSourceOneOf1 != nil { + // commit id + git := helm.Source.HelmResponseAllOfSourceOneOf1.GetRepository() + chartVersion = &git.ChartVersion + } + + return commitId, chartVersion +}