diff --git a/internal/cmd/deploy/deploy.go b/internal/cmd/deploy/deploy.go index df08101..b14a50d 100644 --- a/internal/cmd/deploy/deploy.go +++ b/internal/cmd/deploy/deploy.go @@ -19,6 +19,11 @@ type Options struct { // create will create a new service instead of selecting one if true create bool + + // specify a service ID and environment ID to deploy on + + serviceID string + environmentID string } func NewCmdDeploy(f *cmdutil.Factory) *cobra.Command { @@ -33,6 +38,8 @@ func NewCmdDeploy(f *cmdutil.Factory) *cobra.Command { }, } + cmd.Flags().StringVar(&opts.serviceID, "service-id", "", "Service ID to redeploy on") + cmd.Flags().StringVar(&opts.environmentID, "environment-id", "", "Environment ID to redeploy on") cmd.Flags().StringVar(&opts.name, "name", "", "Service name") cmd.Flags().StringVar(&opts.domainName, "domain", "", "Domain name") cmd.Flags().BoolVar(&opts.create, "create", false, "Create a new service") @@ -41,6 +48,72 @@ func NewCmdDeploy(f *cmdutil.Factory) *cobra.Command { } func runDeploy(f *cmdutil.Factory, opts *Options) error { + var environment *model.Environment + var service *model.Service + var err error + + bytes, fileName, err := util.PackZip() + if err != nil { + return fmt.Errorf("packing zip: %w", err) + } + opts.name = fileName + + if opts.serviceID == "" { + service, environment, err = selectInteractively(f, opts) + if err != nil { + return err + } + } else { + service, err = f.ApiClient.GetService(context.Background(), opts.serviceID, "", "", "") + if err != nil { + return err + } + + environment, err = f.ApiClient.GetEnvironment(context.Background(), opts.environmentID) + if err != nil { + return err + } + } + + s := spinner.New(cmdutil.SpinnerCharSet, cmdutil.SpinnerInterval, + spinner.WithColor(cmdutil.SpinnerColor), + spinner.WithSuffix(" Uploading codes to Zeabur ..."), + ) + s.Start() + + _, err = f.ApiClient.UploadZipToService(context.Background(), service.Project.ID, service.ID, environment.ID, bytes) + if err != nil { + return err + } + s.Stop() + + domainName := opts.domainName + + if domainName == "" { + fmt.Println("Service deployed successfully, you can access it via:") + fmt.Println("https://dash.zeabur.com/projects/" + service.Project.ID + "/services/" + service.ID + "?envID=" + environment.ID) + return nil + } + + s = spinner.New(cmdutil.SpinnerCharSet, cmdutil.SpinnerInterval, + spinner.WithColor(cmdutil.SpinnerColor), + spinner.WithSuffix(" Creating domain ..."), + ) + s.Start() + + domain, err := f.ApiClient.AddDomain(context.Background(), service.ID, environment.ID, false, domainName) + if err != nil { + return err + } + + fmt.Println("Domain created: ", "https://"+*domain) + + s.Stop() + + return nil +} + +func selectInteractively(f *cmdutil.Factory, opts *Options) (*model.Service, *model.Environment, error) { s := spinner.New(cmdutil.SpinnerCharSet, cmdutil.SpinnerInterval, spinner.WithColor(cmdutil.SpinnerColor), spinner.WithSuffix(" Fetching projects ..."), @@ -48,25 +121,25 @@ func runDeploy(f *cmdutil.Factory, opts *Options) error { s.Start() projects, err := f.ApiClient.ListAllProjects(context.Background()) if err != nil { - return err + return nil, nil, err } s.Stop() if len(projects) == 0 { - confirm, err := f.Prompter.Confirm("No projects found, would you like to create one now?", true) + confirm, err := f.Prompter.Confirm("No projects found. Would you like to create one now?", true) if err != nil { - return err + return nil, nil, err } if confirm { project, err := f.ApiClient.CreateProject(context.Background(), "default", nil) if err != nil { f.Log.Error("Failed to create project: ", err) - return err + return nil, nil, err } - f.Log.Infof("Project %s created", project.Name) + f.Log.Infof("Project %s created. Run this command again to deploy on it.", project.Name) f.Config.GetContext().SetProject(zcontext.NewBasicInfo(project.ID, project.Name)) - return nil + return nil, nil, nil } } @@ -74,14 +147,14 @@ func runDeploy(f *cmdutil.Factory, opts *Options) error { _, project, err := f.Selector.SelectProject() if err != nil { - return err + return nil, nil, err } f.Config.GetContext().SetProject(zcontext.NewBasicInfo(project.ID, project.Name)) _, environment, err := f.Selector.SelectEnvironment(project.ID) if err != nil { - return err + return nil, nil, err } f.Log.Info("Select one service to deploy or create a new one.") @@ -97,15 +170,10 @@ func runDeploy(f *cmdutil.Factory, opts *Options) error { }, }) if err != nil { - return err + return nil, nil, err } } - bytes, fileName, err := util.PackZip() - if err != nil { - return err - } - if service == nil { f.Log.Info("No service found, create a new one.") @@ -115,53 +183,15 @@ func runDeploy(f *cmdutil.Factory, opts *Options) error { ) s.Start() - name := fileName - if opts.name != "" { - name = opts.name - } + name := opts.name service, err = f.ApiClient.CreateEmptyService(context.Background(), project.ID, name) if err != nil { - return err + return nil, nil, err } s.Stop() } - s = spinner.New(cmdutil.SpinnerCharSet, cmdutil.SpinnerInterval, - spinner.WithColor(cmdutil.SpinnerColor), - spinner.WithSuffix(" Uploading codes to Zeabur ..."), - ) - s.Start() - - _, err = f.ApiClient.UploadZipToService(context.Background(), project.ID, service.ID, environment.ID, bytes) - if err != nil { - return err - } - s.Stop() - - domainName := opts.domainName - - if domainName == "" { - fmt.Println("Service deployed successfully, you can access it via:") - fmt.Println("https://dash.zeabur.com/projects/" + project.ID + "/services/" + service.ID + "?envID=" + environment.ID) - return nil - } - - s = spinner.New(cmdutil.SpinnerCharSet, cmdutil.SpinnerInterval, - spinner.WithColor(cmdutil.SpinnerColor), - spinner.WithSuffix(" Creating domain ..."), - ) - s.Start() - - domain, err := f.ApiClient.AddDomain(context.Background(), service.ID, environment.ID, false, domainName) - if err != nil { - return err - } - - fmt.Println("Domain created: ", "https://"+*domain) - - s.Stop() - - return nil + return service, environment, nil } diff --git a/pkg/model/service.go b/pkg/model/service.go index c1e52ec..e9809b3 100644 --- a/pkg/model/service.go +++ b/pkg/model/service.go @@ -13,8 +13,10 @@ import ( type Service struct { ID string `graphql:"_id"` Name string `graphql:"name"` - //Template ServiceTemplate `graphql:"template"` - //Project *Project `graphql:"project"` + // Template ServiceTemplate `graphql:"template"` + Project *struct { + ID string `graphql:"_id"` + } `graphql:"project"` CreatedAt time.Time `graphql:"createdAt"`