github.com/hazelops/ize@v1.1.12-0.20230915191306-97d7c0e48f11/internal/commands/deploy.go (about)

     1  package commands
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/aws/aws-sdk-go/aws"
     7  	"github.com/hazelops/ize/internal/config"
     8  	"github.com/hazelops/ize/internal/manager"
     9  	"github.com/hazelops/ize/internal/manager/alias"
    10  	"github.com/hazelops/ize/internal/manager/ecs"
    11  	"github.com/hazelops/ize/internal/manager/serverless"
    12  	"github.com/hazelops/ize/internal/requirements"
    13  	"github.com/hazelops/ize/pkg/templates"
    14  	"github.com/hazelops/ize/pkg/terminal"
    15  	"github.com/spf13/cobra"
    16  )
    17  
    18  type DeployOptions struct {
    19  	Config                 *config.Project
    20  	AppName                string
    21  	Image                  string
    22  	TaskDefinitionRevision string
    23  	Unsafe                 bool
    24  	Force                  bool
    25  }
    26  
    27  var deployLongDesc = templates.LongDesc(`
    28  	Deploy service.
    29      App name must be specified for a app deploy. 
    30  
    31  	If you install a revision of the task definition, the application will be redeployed (ECS only).
    32  	Warning: Redeployment using the docker runtime, a new task definition will be deployed based on the specified revision.
    33  `)
    34  
    35  var deployExample = templates.Examples(`
    36  	# Deploy app (config file required)
    37  	ize deploy <app name>
    38  
    39  	# Deploy app via config file
    40  	ize --config-file (or -c) /path/to/config deploy <app name>
    41  
    42  	# Deploy app via config file installed from env
    43  	export IZE_CONFIG_FILE=/path/to/config
    44  	ize deploy <app name>
    45  
    46  	# Redeploy app (ECS only)
    47  	ize deploy <app name> --task-definition-revision <task definition revision>
    48  `)
    49  
    50  func NewDeployFlags(project *config.Project) *DeployOptions {
    51  	return &DeployOptions{
    52  		Config: project,
    53  	}
    54  }
    55  
    56  func NewCmdDeploy(project *config.Project) *cobra.Command {
    57  	o := NewDeployFlags(project)
    58  
    59  	cmd := &cobra.Command{
    60  		Use:               "deploy [flags] <app name>",
    61  		Example:           deployExample,
    62  		Short:             "Manage deployments",
    63  		Long:              deployLongDesc,
    64  		Args:              cobra.MaximumNArgs(1),
    65  		ValidArgsFunction: config.GetApps,
    66  		RunE: func(cmd *cobra.Command, args []string) error {
    67  			cmd.SilenceUsage = true
    68  
    69  			err := o.Complete(cmd)
    70  			if err != nil {
    71  				return err
    72  			}
    73  
    74  			err = o.Validate()
    75  			if err != nil {
    76  				return err
    77  			}
    78  
    79  			err = o.Run()
    80  			if err != nil {
    81  				return err
    82  			}
    83  
    84  			return nil
    85  		},
    86  	}
    87  
    88  	cmd.Flags().StringVar(&o.TaskDefinitionRevision, "task-definition-revision", "", "set task definition revision (ECS only)")
    89  	cmd.Flags().BoolVar(&o.Unsafe, "unsafe", false, "set unsafe healthcheck options (accelerates deployment if possible)")
    90  	cmd.Flags().BoolVar(&o.Force, "force", false, "forces a deployment to take place (only serverless)")
    91  
    92  	return cmd
    93  }
    94  
    95  func (o *DeployOptions) Complete(cmd *cobra.Command) error {
    96  	if err := requirements.CheckRequirements(requirements.WithIzeStructure(), requirements.WithConfigFile()); err != nil {
    97  		return err
    98  	}
    99  
   100  	if len(o.Config.Serverless) != 0 {
   101  		if err := requirements.CheckRequirements(requirements.WithNVM()); err != nil {
   102  			return err
   103  		}
   104  	}
   105  
   106  	o.AppName = cmd.Flags().Args()[0]
   107  
   108  	return nil
   109  }
   110  
   111  func (o *DeployOptions) Validate() error {
   112  	if len(o.Config.Env) == 0 {
   113  		return fmt.Errorf("can't validate options: env must be specified")
   114  	}
   115  
   116  	if len(o.Config.Namespace) == 0 {
   117  		return fmt.Errorf("can't validate options: namespace must be specified")
   118  	}
   119  
   120  	if len(o.AppName) == 0 {
   121  		return fmt.Errorf("can't validate options: app name must be specified")
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  func (o *DeployOptions) Run() error {
   128  	ui := terminal.ConsoleUI(aws.BackgroundContext(), o.Config.PlainText)
   129  
   130  	ui.Output("Deploying %s app...\n", o.AppName, terminal.WithHeaderStyle())
   131  	sg := ui.StepGroup()
   132  	defer sg.Wait()
   133  
   134  	var m manager.Manager
   135  
   136  	m = &ecs.Manager{
   137  		Project: o.Config,
   138  		App: &config.Ecs{
   139  			Name:                   o.AppName,
   140  			TaskDefinitionRevision: o.TaskDefinitionRevision,
   141  			Unsafe:                 o.Unsafe,
   142  		},
   143  	}
   144  
   145  	if app, ok := o.Config.Serverless[o.AppName]; ok {
   146  		app.Name = o.AppName
   147  		app.Force = o.Force
   148  		m = &serverless.Manager{
   149  			Project: o.Config,
   150  			App:     app,
   151  		}
   152  	}
   153  	if app, ok := o.Config.Alias[o.AppName]; ok {
   154  		app.Name = o.AppName
   155  		m = &alias.Manager{
   156  			Project: o.Config,
   157  			App:     app,
   158  		}
   159  	}
   160  	if app, ok := o.Config.Ecs[o.AppName]; ok {
   161  		app.Name = o.AppName
   162  		app.TaskDefinitionRevision = o.TaskDefinitionRevision
   163  		app.Unsafe = o.Unsafe
   164  		m = &ecs.Manager{
   165  			Project: o.Config,
   166  			App:     app,
   167  		}
   168  	}
   169  
   170  	if len(o.TaskDefinitionRevision) != 0 {
   171  		err := m.Redeploy(ui)
   172  		if err != nil {
   173  			return err
   174  		}
   175  
   176  		ui.Output("Redeploy app %s completed\n", o.AppName, terminal.WithSuccessStyle())
   177  
   178  		return nil
   179  	}
   180  
   181  	err := m.Deploy(ui)
   182  	if err != nil {
   183  		return err
   184  	}
   185  
   186  	ui.Output("Deploy app %s completed\n", o.AppName, terminal.WithSuccessStyle())
   187  
   188  	return nil
   189  }