From d4f681ad367f4da9d23838166c3138e4300c6880 Mon Sep 17 00:00:00 2001 From: Tomas <40318863+tomasmik@users.noreply.github.com> Date: Fri, 4 Aug 2023 11:18:12 +0300 Subject: [PATCH] Allow to auto confirm a run during `stack deploy` command (#170) * Allow to auto confirm a run during `stack deploy` command * Remove the `runLogs` function --- internal/cmd/stack/flags.go | 7 +++++++ internal/cmd/stack/local_preview.go | 2 +- internal/cmd/stack/run_confirm.go | 2 +- internal/cmd/stack/run_discard.go | 2 +- internal/cmd/stack/run_logs.go | 18 +++++++++++++--- internal/cmd/stack/run_retry.go | 2 +- internal/cmd/stack/run_trigger.go | 32 +++++++++++++++++++++++++++-- internal/cmd/stack/stack.go | 3 ++- internal/cmd/stack/task_command.go | 2 +- 9 files changed, 59 insertions(+), 11 deletions(-) diff --git a/internal/cmd/stack/flags.go b/internal/cmd/stack/flags.go index edc062d..0702541 100644 --- a/internal/cmd/stack/flags.go +++ b/internal/cmd/stack/flags.go @@ -72,6 +72,13 @@ var flagTail = &cli.BoolFlag{ Value: false, } +var flagAutoConfirm = &cli.BoolFlag{ + Name: "auto-confirm", + Usage: "Indicate whether to automatically confirm the run. It also forces the run log tailing.", + Value: false, + Required: false, +} + var flagNoTail = &cli.BoolFlag{ Name: "no-tail", Usage: "Indicate whether not to tail the run", diff --git a/internal/cmd/stack/local_preview.go b/internal/cmd/stack/local_preview.go index 4915488..d1207d0 100644 --- a/internal/cmd/stack/local_preview.go +++ b/internal/cmd/stack/local_preview.go @@ -131,7 +131,7 @@ func localPreview() cli.ActionFunc { return nil } - terminal, err := runLogs(ctx, stackID, triggerMutation.RunProposeLocalWorkspace.ID) + terminal, err := runLogsWithAction(ctx, stackID, triggerMutation.RunProposeLocalWorkspace.ID, nil) if err != nil { return err } diff --git a/internal/cmd/stack/run_confirm.go b/internal/cmd/stack/run_confirm.go index 024a17c..d8c4694 100644 --- a/internal/cmd/stack/run_confirm.go +++ b/internal/cmd/stack/run_confirm.go @@ -52,7 +52,7 @@ func runConfirm() cli.ActionFunc { return nil } - terminal, err := runLogs(ctx, stackID, mutation.RunConfirm.ID) + terminal, err := runLogsWithAction(ctx, stackID, mutation.RunConfirm.ID, nil) if err != nil { return err } diff --git a/internal/cmd/stack/run_discard.go b/internal/cmd/stack/run_discard.go index b3d2a4f..1ced6b0 100644 --- a/internal/cmd/stack/run_discard.go +++ b/internal/cmd/stack/run_discard.go @@ -46,7 +46,7 @@ func runDiscard() cli.ActionFunc { return nil } - terminal, err := runLogs(ctx, stackID, mutation.RunDiscard.ID) + terminal, err := runLogsWithAction(ctx, stackID, mutation.RunDiscard.ID, nil) if err != nil { return err } diff --git a/internal/cmd/stack/run_logs.go b/internal/cmd/stack/run_logs.go index a1e2b0a..3880570 100644 --- a/internal/cmd/stack/run_logs.go +++ b/internal/cmd/stack/run_logs.go @@ -11,11 +11,17 @@ import ( "github.com/spacelift-io/spacectl/internal/cmd/authenticated" ) -func runLogs(ctx context.Context, stack, run string) (terminal *structs.RunStateTransition, err error) { +// actionOnRunState is a function that can be executed on a run state. +// +// It can be used to interact with the run during the log reading, +// for example to confirm a run. +type actionOnRunState func(state structs.RunState, stackID, runID string) error + +func runLogsWithAction(ctx context.Context, stack, run string, acFn actionOnRunState) (terminal *structs.RunStateTransition, err error) { lines := make(chan string) go func() { - terminal, err = runStates(ctx, stack, run, lines) + terminal, err = runStates(ctx, stack, run, lines, acFn) close(lines) }() @@ -26,7 +32,7 @@ func runLogs(ctx context.Context, stack, run string) (terminal *structs.RunState return } -func runStates(ctx context.Context, stack, run string, sink chan<- string) (*structs.RunStateTransition, error) { +func runStates(ctx context.Context, stack, run string, sink chan<- string, acFn actionOnRunState) (*structs.RunStateTransition, error) { var query struct { Stack *struct { Run *struct { @@ -81,6 +87,12 @@ func runStates(ctx context.Context, stack, run string, sink chan<- string) (*str } } + if acFn != nil { + if err := acFn(transition.State, stack, run); err != nil { + return nil, fmt.Errorf("failed to execute action on run state: %w", err) + } + } + if transition.Terminal { return &transition, nil } diff --git a/internal/cmd/stack/run_retry.go b/internal/cmd/stack/run_retry.go index 8e5a17a..8023233 100644 --- a/internal/cmd/stack/run_retry.go +++ b/internal/cmd/stack/run_retry.go @@ -42,7 +42,7 @@ func runRetry(cliCtx *cli.Context) error { return nil } - terminal, err := runLogs(cliCtx.Context, stackID, mutation.RunRetry.ID) + terminal, err := runLogsWithAction(cliCtx.Context, stackID, mutation.RunRetry.ID, nil) if err != nil { return err } diff --git a/internal/cmd/stack/run_trigger.go b/internal/cmd/stack/run_trigger.go index f4c1ce7..f6a7dc1 100644 --- a/internal/cmd/stack/run_trigger.go +++ b/internal/cmd/stack/run_trigger.go @@ -54,11 +54,39 @@ func runTrigger(spaceliftType, humanType string) cli.ActionFunc { mutation.RunTrigger.ID, )) - if !cliCtx.Bool(flagTail.Name) { + if !cliCtx.Bool(flagTail.Name) && !cliCtx.Bool(flagAutoConfirm.Name) { return nil } - terminal, err := runLogs(ctx, stackID, mutation.RunTrigger.ID) + actionFn := func(state structs.RunState, stackID, runID string) error { + if state != "UNCONFIRMED" { + return nil + } + + if !cliCtx.Bool(flagAutoConfirm.Name) { + return nil + } + + var mutation struct { + RunConfirm struct { + ID string `graphql:"id"` + } `graphql:"runConfirm(stack: $stack, run: $run)"` + } + + variables := map[string]interface{}{ + "stack": graphql.ID(stackID), + "run": graphql.ID(runID), + } + + if err := authenticated.Client.Mutate(ctx, &mutation, variables, requestOpts...); err != nil { + return err + } + + fmt.Println("Deployment was automatically confirmed because of --auto-confirm flag") + return nil + } + + terminal, err := runLogsWithAction(ctx, stackID, mutation.RunTrigger.ID, actionFn) if err != nil { return err } diff --git a/internal/cmd/stack/stack.go b/internal/cmd/stack/stack.go index 5363915..080bed9 100644 --- a/internal/cmd/stack/stack.go +++ b/internal/cmd/stack/stack.go @@ -77,6 +77,7 @@ func Command() *cli.Command { flagCommitSHA, flagRunMetadata, flagTail, + flagAutoConfirm, }, Action: runTrigger("TRACKED", "deployment"), Before: authenticated.Ensure, @@ -139,7 +140,7 @@ func Command() *cli.Command { if err != nil { return err } - _, err = runLogs(context.Background(), stackID, cliCtx.String(flagRequiredRun.Name)) + _, err = runLogsWithAction(context.Background(), stackID, cliCtx.String(flagRequiredRun.Name), nil) return err }, Before: authenticated.Ensure, diff --git a/internal/cmd/stack/task_command.go b/internal/cmd/stack/task_command.go index 8f00573..3ae6389 100644 --- a/internal/cmd/stack/task_command.go +++ b/internal/cmd/stack/task_command.go @@ -53,7 +53,7 @@ func taskCommand(cliCtx *cli.Context) error { return nil } - terminal, err := runLogs(ctx, stackID, mutation.TaskCreate.ID) + terminal, err := runLogsWithAction(ctx, stackID, mutation.TaskCreate.ID, nil) if err != nil { return err }