diff --git a/internal/command/deploy.go b/internal/command/deploy.go index baaaabd..b93b480 100644 --- a/internal/command/deploy.go +++ b/internal/command/deploy.go @@ -58,18 +58,7 @@ func (d *deployCommand) run(ctx context.Context, ns *docker.Namespace, cmd *cobr AutoUpdate: true, }) - progress := func(p docker.DeployProgress) { - switch p.Stage { - case docker.DeployStageDownloading: - fmt.Printf("Downloading: %d%%\n", p.Percentage) - case docker.DeployStageStarting: - fmt.Println("Starting...") - case docker.DeployStageFinished: - fmt.Println("Finished") - } - } - - if err := app.Deploy(ctx, progress); err != nil { + if err := app.Deploy(ctx, printDeployProgress); err != nil { if cleanupErr := app.Destroy(context.Background(), true); cleanupErr != nil { slog.Error("Failed to clean up after deploy failure", "app", name, "error", cleanupErr) } diff --git a/internal/command/root.go b/internal/command/root.go index 44b1b1e..a05ef06 100644 --- a/internal/command/root.go +++ b/internal/command/root.go @@ -90,3 +90,14 @@ func namespaceFlag(cmd *cobra.Command) string { namespace, _ := cmd.Root().PersistentFlags().GetString("namespace") return namespace } + +func printDeployProgress(p docker.DeployProgress) { + switch p.Stage { + case docker.DeployStageDownloading: + fmt.Printf("Downloading: %d%%\n", p.Percentage) + case docker.DeployStageStarting: + fmt.Println("Starting...") + case docker.DeployStageFinished: + fmt.Println("Finished") + } +} diff --git a/internal/command/update.go b/internal/command/update.go index 8e1a187..edbadd2 100644 --- a/internal/command/update.go +++ b/internal/command/update.go @@ -1,8 +1,12 @@ package command import ( + "context" + "fmt" + "github.com/spf13/cobra" + "github.com/basecamp/once/internal/docker" "github.com/basecamp/once/internal/version" ) @@ -13,12 +17,38 @@ type updateCommand struct { func newUpdateCommand() *updateCommand { u := &updateCommand{} u.cmd = &cobra.Command{ - Use: "update", - Short: "Update once to the latest version", - Args: cobra.NoArgs, + Use: "update [app]", + Short: "Update once to the latest version, or update a specific application", + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return version.NewUpdater().UpdateBinary() + if len(args) == 0 { + return version.NewUpdater().UpdateBinary() + } + return WithNamespace(u.run)(cmd, args) }, } return u } + +// Private + +func (u *updateCommand) run(ctx context.Context, ns *docker.Namespace, cmd *cobra.Command, args []string) error { + appName := args[0] + + var changed bool + err := withApplication(ns, appName, "updating", func(app *docker.Application) error { + var err error + changed, err = app.Update(ctx, printDeployProgress) + return err + }) + if err != nil { + return err + } + + if changed { + fmt.Printf("Updated %s\n", appName) + } else { + fmt.Printf("%s is already up to date\n", appName) + } + return nil +}