diff --git a/cmd/commands/deploy/deploy.go b/cmd/commands/deploy/deploy.go index 23f7996..5541963 100644 --- a/cmd/commands/deploy/deploy.go +++ b/cmd/commands/deploy/deploy.go @@ -14,20 +14,22 @@ import ( func NewFuncCmd(env deployaction.EnvConfig) *cobra.Command { stage := env.Stage() return &cobra.Command{ - Use: fmt.Sprintf("deploy:func:%s ", stage), - Short: fmt.Sprintf("Deploy a single Lambda function to %s", stage), - Long: fmt.Sprintf(`Package and deploy a single Lambda function to %s. + Use: fmt.Sprintf("deploy:func:%s [function-name...]", stage), + Short: fmt.Sprintf("Deploy one or more Lambda functions to %s", stage), + Long: fmt.Sprintf(`Package and deploy one or more Lambda functions to %s. The service argument can be a service name (from serverless.yml) or a path. +All functions must belong to the same service; the service is packaged once. Examples: draft deploy:func:%s gamestats storegamestats - draft deploy:func:%s services/gamestats storegamestats`, stage, stage, stage), - Args: cobra.ExactArgs(2), + draft deploy:func:%s gamestats storegamestats otherlambda + draft deploy:func:%s services/gamestats storegamestats`, stage, stage, stage, stage), + Args: cobra.MinimumNArgs(2), Run: func(c *cobra.Command, args []string) { common.ChDir(c) - if err := deployaction.DeployFunction(env, args[0], args[1]); err != nil { + if err := deployaction.DeployFunction(env, args[0], args[1:]); err != nil { log.Exitf(1, "deploy:func:%s failed: %v", stage, err) } }, diff --git a/internal/actions/deploy/function.go b/internal/actions/deploy/function.go index dde88dc..0c5ba47 100644 --- a/internal/actions/deploy/function.go +++ b/internal/actions/deploy/function.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strings" + "sync" "github.com/Drafteame/draft/internal/pkg/aws" "github.com/Drafteame/draft/internal/pkg/exec" @@ -14,9 +15,9 @@ import ( const deployRegion = "us-east-2" -// DeployFunction packages and deploys a single Lambda function using the given env config. -// serviceArg can be a service name or a path. -func DeployFunction(env EnvConfig, serviceArg, functionName string) error { +// DeployFunction packages and deploys one or more Lambda functions using the given env config. +// serviceArg can be a service name or a path. All functions must belong to the same service. +func DeployFunction(env EnvConfig, serviceArg string, functionNames []string) error { absPath, err := resolveService(serviceArg) if err != nil { return err @@ -62,6 +63,47 @@ func DeployFunction(env EnvConfig, serviceArg, functionName string) error { return err } + type result struct { + name string + err error + } + + results := make([]result, len(functionNames)) + var wg sync.WaitGroup + + for i, functionName := range functionNames { + wg.Add(1) + go func(i int, functionName string) { + defer wg.Done() + results[i] = result{ + name: functionName, + err: deployOneFunction(env, absPath, serviceName, stage, functionName), + } + }(i, functionName) + } + + wg.Wait() + + hasError := false + if len(functionNames) > 1 { + log.Info("\n─── Deploy Summary ───") + } + for _, r := range results { + if r.err != nil { + log.Errorf("✗ %s: %v", r.name, r.err) + hasError = true + } else { + log.Successf("✓ %s", r.name) + } + } + + if hasError { + return fmt.Errorf("one or more function deploys failed") + } + return nil +} + +func deployOneFunction(env EnvConfig, absPath, serviceName, stage, functionName string) error { fullLambdaName := fmt.Sprintf("%s-%s-%s", serviceName, stage, functionName) log.Infof("Lambda function: %s", fullLambdaName) @@ -80,7 +122,6 @@ func DeployFunction(env EnvConfig, serviceArg, functionName string) error { return fmt.Errorf("lambda update failed: %w\n%s", err, out) } - log.Success("✓ Lambda deployed: ", fullLambdaName) return nil }