Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show failed command after atmos workflow failure #767

Merged
merged 11 commits into from
Dec 5, 2024
5 changes: 4 additions & 1 deletion cmd/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ var workflowCmd = &cobra.Command{
Example: "atmos workflow\n" +
"atmos workflow <name> -f <file>\n" +
"atmos workflow <name> -f <file> -s <stack>\n" +
"atmos workflow <name> -f <file> --from-step <step-name>",
"atmos workflow <name> -f <file> --from-step <step-name>\n\n" +
"To resume the workflow from this step, run:\n" +
"atmos workflow deploy-infra -f workflow1 --from-step deploy-vpc\n\n" +
"For more details refer to https://atmos.tools/cli/commands/workflow/",
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
Run: func(cmd *cobra.Command, args []string) {
err := e.ExecuteWorkflowCmd(cmd, args)
Expand Down
29 changes: 23 additions & 6 deletions internal/exec/workflow_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path"
"path/filepath"
"sort"
"strings"

Expand Down Expand Up @@ -70,11 +71,10 @@ func ExecuteWorkflow(
commandType = "atmos"
}

var err error
if commandType == "shell" {
commandName := fmt.Sprintf("%s-step-%d", workflow, stepIdx)
if err := ExecuteShell(cliConfig, command, commandName, ".", []string{}, dryRun); err != nil {
return err
}
err = ExecuteShell(cliConfig, command, commandName, ".", []string{}, dryRun)
} else if commandType == "atmos" {
args := strings.Fields(command)

Expand All @@ -101,12 +101,29 @@ func ExecuteWorkflow(
logFunc(cliConfig, fmt.Sprintf("Stack: %s", finalStack))
}

if err := ExecuteShellCommand(cliConfig, "atmos", args, ".", []string{}, dryRun, ""); err != nil {
return err
}
err = ExecuteShellCommand(cliConfig, "atmos", args, ".", []string{}, dryRun, "")
} else {
return fmt.Errorf("invalid workflow step type '%s'. Supported types are 'atmos' and 'shell'", commandType)
}

if err != nil {
workflowFileName := filepath.Base(workflowPath)
workflowFileName = strings.TrimSuffix(workflowFileName, filepath.Ext(workflowFileName))

failedMsg := color.New(color.FgRed).Sprintf("\nStep '%s' failed!", step.Name)

u.LogDebug(cliConfig, fmt.Sprintf("\nCommand failed: %s", command))
u.LogDebug(cliConfig, fmt.Sprintf("Error: %v", err))

resumeMsg := color.New(color.FgGreen).Sprintf(
"\nTo resume the workflow from this step, run:\natmos workflow %s -f %s --from-step %s",
workflow,
workflowFileName,
step.Name,
)

return fmt.Errorf("%s\n%s", failedMsg, resumeMsg)
}
}

return nil
Expand Down
34 changes: 34 additions & 0 deletions website/docs/core-concepts/workflows/workflows.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,40 @@ The Atmos stack used by the workflow commands of type `atmos` can be specified i
atmos workflow my-workflow -f workflow1 -s tenant1-ue2-dev
```

## Workflow Failure Handling and Resume

When a workflow step fails, Atmos will:
1. Display which step failed
2. Show the exact command that failed
3. Provide a ready-to-use command to resume the workflow from the failed step

Given this workflow:

```yaml title="stacks/workflows/networking.yaml"
workflows:
provision-vpcs:
description: "Deploy vpc components"
steps:
- command: terraform plan vpc -s plat-ue2-dev
name: step-1
- command: terraform plan vpc -s plat-ue2-staging
name: step-2
- command: terraform plan vpc -s plat-ue2-prod
name: step-3
```

If step-2 fails, you'll see:

```console
Step 'step-2' failed!

Command failed:
terraform plan vpc -s plat-ue2-staging
Cerebrovinny marked this conversation as resolved.
Show resolved Hide resolved

To resume the workflow from this step, run:
atmos workflow provision-vpcs -f networking --from-step step-2
```

### Stack Precedence

The stack defined inline in the command itself has the lowest priority, it can and will be overridden by any other stack definition.
Expand Down
Loading