Skip to content

Commit

Permalink
markdown start point implementation for workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
Cerebrovinny committed Dec 18, 2024
1 parent b145a49 commit 991d653
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 22 deletions.
128 changes: 107 additions & 21 deletions cmd/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,144 @@ package cmd

import (
"fmt"
"strings"

"github.com/spf13/cobra"

e "github.com/cloudposse/atmos/internal/exec"
"github.com/cloudposse/atmos/internal/tui/utils"
"github.com/cloudposse/atmos/pkg/schema"
"github.com/cloudposse/atmos/pkg/ui/markdown"
u "github.com/cloudposse/atmos/pkg/utils"
)

// ErrorMessage represents a structured error message
type ErrorMessage struct {
Title string
Details string
Suggestion string
}

// String returns the markdown representation of the error message
func (e ErrorMessage) String() string {
var sb strings.Builder
sb.WriteString(fmt.Sprintf("# ❌ %s\n\n", e.Title))

if e.Details != "" {
sb.WriteString(fmt.Sprintf("## Details\n%s\n\n", e.Details))
}

if e.Suggestion != "" {
sb.WriteString(fmt.Sprintf("## Suggestion\n%s\n\n", e.Suggestion))
}

return sb.String()
}

// renderError renders an error message using the markdown renderer
func renderError(msg ErrorMessage) error {
renderer, err := markdown.NewRenderer(
markdown.WithWidth(80),
)
if err != nil {
return fmt.Errorf("failed to create markdown renderer: %w", err)
}

rendered, err := renderer.Render(msg.String())
if err != nil {
return fmt.Errorf("failed to render error message: %w", err)
}

fmt.Print(rendered)
return nil
}

// workflowCmd executes a workflow
var workflowCmd = &cobra.Command{
Use: "workflow",
Short: "Execute a workflow",
Long: `This command executes a workflow: atmos workflow <name> --file <file>`,
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>\n\n" +
"atmos workflow <name> --file <file>\n" +
"atmos workflow <name> --file <file> --stack <stack>\n" +
"atmos workflow <name> --file <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" +
"atmos workflow deploy-infra --file 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) {
// If the first arg is "list", show a clear error message
if len(args) > 0 && args[0] == "list" {
errorMsg := "# Error! Invalid command.\n\n" +
"## Usage\n" +
"`atmos workflow <name> --file <file>`\n\n" +
"Run `atmos workflow --help` for more information."

rendered, err := utils.RenderMarkdown(errorMsg, "dark")
// If no arguments are provided, start the workflow UI
if len(args) == 0 {
err := e.ExecuteWorkflowCmd(cmd, args)
if err != nil {
fmt.Println(errorMsg) // Fallback to plain text if rendering fails
} else {
fmt.Print(rendered)
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
return
}

// Check if the workflow name is "list" (invalid command)
if args[0] == "list" {
err := renderError(ErrorMessage{
Title: "Invalid Command",
Details: "The command `atmos workflow list` is not valid.",
Suggestion: "Use `atmos workflow --file <file>` to execute a workflow, or run `atmos workflow` without arguments to use the interactive UI.",
})
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
return
}

// Get the --file flag value
workflowFile, _ := cmd.Flags().GetString("file")
if workflowFile == "" {
err := renderError(ErrorMessage{
Title: "Missing Required Flag",
Details: "The `--file` flag is required to specify a workflow manifest.",
Suggestion: "Example:\n`atmos workflow deploy-infra --file workflow1`",
})
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
return
}

// Execute the workflow command
err := e.ExecuteWorkflowCmd(cmd, args)
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
// Format common error messages
if strings.Contains(err.Error(), "does not exist") {
err := renderError(ErrorMessage{
Title: "Workflow File Not Found",
Details: fmt.Sprintf("The workflow manifest file '%s' could not be found.", workflowFile),
Suggestion: "Check if the file exists in the workflows directory and the path is correct.",
})
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
} else if strings.Contains(err.Error(), "does not have the") {
err := renderError(ErrorMessage{
Title: "Invalid Workflow",
Details: err.Error(),
Suggestion: fmt.Sprintf("Check the available workflows in '%s' and make sure you're using the correct workflow name.", workflowFile),
})
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
} else {
// For other errors, use the standard error handler
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
return
}
},
}

func init() {
workflowCmd.DisableFlagParsing = false
workflowCmd.PersistentFlags().StringP("file", "f", "", "atmos workflow <name> -f <file>")
workflowCmd.PersistentFlags().Bool("dry-run", false, "atmos workflow <name> -f <file> --dry-run")
workflowCmd.PersistentFlags().StringP("stack", "s", "", "atmos workflow <name> -f <file> -s <stack>")
workflowCmd.PersistentFlags().String("from-step", "", "atmos workflow <name> -f <file> -from-step <step-name>")
workflowCmd.PersistentFlags().StringP("file", "f", "", "atmos workflow <name> --file <file>")
workflowCmd.PersistentFlags().Bool("dry-run", false, "atmos workflow <name> --file <file> --dry-run")
workflowCmd.PersistentFlags().StringP("stack", "s", "", "atmos workflow <name> --file <file> --stack <stack>")
workflowCmd.PersistentFlags().String("from-step", "", "atmos workflow <name> --file <file> --from-step <step-name>")

RootCmd.AddCommand(workflowCmd)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/go-wordwrap v1.0.1
github.com/mitchellh/mapstructure v1.5.0
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a
github.com/open-policy-agent/opa v0.70.0
github.com/otiai10/copy v1.14.0
github.com/pkg/errors v0.9.1
Expand Down Expand Up @@ -194,7 +195,6 @@ require (
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
Expand Down

0 comments on commit 991d653

Please sign in to comment.