From 728698570385bbc9fd30ce6830a2d75f652bea3b Mon Sep 17 00:00:00 2001 From: Ariel Santos Date: Wed, 13 May 2026 22:40:26 -0300 Subject: [PATCH 1/2] feat(deploy): publish version and update alias after function deploy After uploading the zip, wait for the update to settle, publish an immutable version, and point the function's single alias to it. Errors if more than one alias is found. Co-Authored-By: Claude Sonnet 4.6 --- internal/actions/deploy/function.go | 66 +++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/internal/actions/deploy/function.go b/internal/actions/deploy/function.go index f357c28..77c60c4 100644 --- a/internal/actions/deploy/function.go +++ b/internal/actions/deploy/function.go @@ -1,6 +1,7 @@ package deploy import ( + "encoding/json" "fmt" "os" "path/filepath" @@ -127,6 +128,71 @@ func deployOneFunction(env EnvConfig, absPath, serviceName, stage, functionName return fmt.Errorf("lambda update failed: %w\n%s", err, out) } + log.Info("Waiting for Lambda update to complete...") + waitScript := fmt.Sprintf( + `aws lambda wait function-updated --function-name %q --profile %s --region %s`, + fullLambdaName, env.Profile, deployRegion, + ) + if out, err := exec.Command(waitScript); err != nil { + return fmt.Errorf("lambda wait failed: %w\n%s", err, out) + } + + log.Info("Publishing new version...") + publishScript := fmt.Sprintf( + `aws lambda publish-version --function-name %q --profile %s --region %s --output json`, + fullLambdaName, env.Profile, deployRegion, + ) + publishOut, err := exec.Command(publishScript) + if err != nil { + return fmt.Errorf("lambda publish-version failed: %w\n%s", err, publishOut) + } + + var publishResult struct { + Version string `json:"Version"` + } + if err := json.Unmarshal([]byte(publishOut), &publishResult); err != nil { + return fmt.Errorf("failed to parse publish-version response: %w", err) + } + + log.Info("Fetching aliases...") + listAliasesScript := fmt.Sprintf( + `aws lambda list-aliases --function-name %q --profile %s --region %s --output json`, + fullLambdaName, env.Profile, deployRegion, + ) + listOut, err := exec.Command(listAliasesScript) + if err != nil { + return fmt.Errorf("lambda list-aliases failed: %w\n%s", err, listOut) + } + + var aliasesResult struct { + Aliases []struct { + Name string `json:"Name"` + } `json:"Aliases"` + } + if err := json.Unmarshal([]byte(listOut), &aliasesResult); err != nil { + return fmt.Errorf("failed to parse list-aliases response: %w", err) + } + + if len(aliasesResult.Aliases) == 0 { + log.Infof("Function %s has no aliases, skipping alias update", functionName) + return nil + } + + if len(aliasesResult.Aliases) > 1 { + return fmt.Errorf("function %s has multiple aliases, cannot determine which one to update", functionName) + } + + aliasName := aliasesResult.Aliases[0].Name + + log.Infof("Updating alias %q → version %s...", aliasName, publishResult.Version) + updateAliasScript := fmt.Sprintf( + `aws lambda update-alias --function-name %q --name %s --function-version %s --profile %s --region %s`, + fullLambdaName, aliasName, publishResult.Version, env.Profile, deployRegion, + ) + if out, err := exec.Command(updateAliasScript); err != nil { + return fmt.Errorf("lambda update-alias failed: %w\n%s", err, out) + } + return nil } From 9bc9a7e74f2b2050b6bc669a4d27b2cf63a9b5e0 Mon Sep 17 00:00:00 2001 From: Ariel Santos Date: Thu, 14 May 2026 00:15:23 -0300 Subject: [PATCH 2/2] chore(deploy): remove deploy:func:prod to prevent single-function deploys to prod Full service deploy via deploy:prod remains available. Co-Authored-By: Claude Sonnet 4.6 --- cmd/commands/deploy/func/prod/prod.go | 12 ------------ main.go | 4 +--- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 cmd/commands/deploy/func/prod/prod.go diff --git a/cmd/commands/deploy/func/prod/prod.go b/cmd/commands/deploy/func/prod/prod.go deleted file mode 100644 index 5d7db83..0000000 --- a/cmd/commands/deploy/func/prod/prod.go +++ /dev/null @@ -1,12 +0,0 @@ -package prod - -import ( - "github.com/spf13/cobra" - - deploycmd "github.com/Drafteame/draft/cmd/commands/deploy" - deployaction "github.com/Drafteame/draft/internal/actions/deploy" -) - -func GetCmd() *cobra.Command { - return deploycmd.NewFuncCmd(deployaction.ProdEnv) -} diff --git a/main.go b/main.go index f5d22de..731c103 100644 --- a/main.go +++ b/main.go @@ -8,13 +8,12 @@ import ( "github.com/Drafteame/draft/cmd/commands" "github.com/Drafteame/draft/cmd/commands/config" + dbconnect "github.com/Drafteame/draft/cmd/commands/db/connect" deploydev "github.com/Drafteame/draft/cmd/commands/deploy/dev" deployfeature "github.com/Drafteame/draft/cmd/commands/deploy/feature" deployfuncdev "github.com/Drafteame/draft/cmd/commands/deploy/func/dev" deployfuncfeature "github.com/Drafteame/draft/cmd/commands/deploy/func/feature" - deployfuncprod "github.com/Drafteame/draft/cmd/commands/deploy/func/prod" deployprod "github.com/Drafteame/draft/cmd/commands/deploy/prod" - dbconnect "github.com/Drafteame/draft/cmd/commands/db/connect" "github.com/Drafteame/draft/cmd/commands/local/invoke" migratedown "github.com/Drafteame/draft/cmd/commands/local/migrate/down" migrateforce "github.com/Drafteame/draft/cmd/commands/local/migrate/force" @@ -53,7 +52,6 @@ func main() { cmd.AddCommand(deployprod.GetCmd()) cmd.AddCommand(deployfeature.GetCmd()) cmd.AddCommand(deployfuncdev.GetCmd()) - cmd.AddCommand(deployfuncprod.GetCmd()) cmd.AddCommand(deployfuncfeature.GetCmd()) if err := cmd.ExecuteContext(ctx); err != nil {