Skip to content

Commit

Permalink
Add atmos describe workflows CLI command. Add interactive UI for `a…
Browse files Browse the repository at this point in the history
…tmos workflow` command (#519)

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* chore: update repo banner image

---------

Co-authored-by: screenshot-action 📷 <[email protected]>
  • Loading branch information
aknysh and actions-user authored Jan 22, 2024
1 parent 71efbe3 commit 8f00ba2
Show file tree
Hide file tree
Showing 40 changed files with 1,305 additions and 61 deletions.
Binary file modified .github/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions cmd/describe_workflows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cmd

import (
"github.com/spf13/cobra"

e "github.com/cloudposse/atmos/internal/exec"
u "github.com/cloudposse/atmos/pkg/utils"
)

// describeWorkflowsCmd executes 'atmos describe workflows' CLI commands
var describeWorkflowsCmd = &cobra.Command{
Use: "workflows",
Short: "Execute 'describe workflows' commands",
Long: `This command executes 'atmos describe workflows' CLI command`,
Example: "describe workflows\n" +
"describe workflows --format json\n" +
"describe workflows -f yaml\n" +
"describe workflows --output list\n" +
"describe workflows -o map -f json\n" +
"describe workflows -o map\n" +
"describe workflows -o all",
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
Run: func(cmd *cobra.Command, args []string) {
err := e.ExecuteDescribeWorkflowsCmd(cmd, args)
if err != nil {
u.LogErrorAndExit(err)
}
},
}

func init() {
describeWorkflowsCmd.PersistentFlags().StringP("format", "f", "yaml", "Specify the output format: atmos describe workflows --format=<yaml|json> ('yaml' is default)")
describeWorkflowsCmd.PersistentFlags().StringP("output", "o", "list", "Specify the output type: atmos describe workflows --output=<list|map|all> ('list' is default)")

describeCmd.AddCommand(describeWorkflowsCmd)
}
1 change: 1 addition & 0 deletions cmd/helmfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
// helmfileCmd represents the base command for all helmfile sub-commands
var helmfileCmd = &cobra.Command{
Use: "helmfile",
Aliases: []string{"hf"},
Short: "Execute 'helmfile' commands",
Long: `This command runs helmfile commands`,
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: true},
Expand Down
3 changes: 2 additions & 1 deletion cmd/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import (
// terraformCmd represents the base command for all terraform sub-commands
var terraformCmd = &cobra.Command{
Use: "terraform",
Aliases: []string{"tf"},
Short: "Execute 'terraform' commands",
Long: `This command runs terraform commands`,
Long: `This command executes 'terraform'' commands`,
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: true},
Run: func(cmd *cobra.Command, args []string) {
var argsAfterDoubleDash []string
Expand Down
24 changes: 18 additions & 6 deletions cmd/validate_component.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,41 @@ import (
"github.com/spf13/cobra"

e "github.com/cloudposse/atmos/internal/exec"
cfg "github.com/cloudposse/atmos/pkg/config"
"github.com/cloudposse/atmos/pkg/schema"
u "github.com/cloudposse/atmos/pkg/utils"
)

// validateComponentCmd validates atmos components
var validateComponentCmd = &cobra.Command{
Use: "component",
Short: "Execute 'validate component' command",
Long: `This command validates an atmos component in a stack using Json Schema, OPA or CUE policies: atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type <jsonschema|opa|cue>`,
Use: "component",
Short: "Execute 'validate component' command",
Long: `This command validates an atmos component in a stack using Json Schema or OPA policies: atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type <jsonschema|opa>`,
Example: "atmos validate component <component> -s <stack>\n" +
"atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type <jsonschema|opa>\n" +
"atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type opa --module-paths catalog",
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
Run: func(cmd *cobra.Command, args []string) {
err := e.ExecuteValidateComponentCmd(cmd, args)
if err != nil {
u.LogErrorAndExit(err)
}

cliConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, false)
if err != nil {
u.LogErrorAndExit(err)
}

u.LogInfo(cliConfig, "component validated successfully\n")
},
}

func init() {
validateComponentCmd.DisableFlagParsing = false

validateComponentCmd.PersistentFlags().StringP("stack", "s", "", "atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type <jsonschema|opa|cue>")
validateComponentCmd.PersistentFlags().String("schema-path", "", "atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type <jsonschema|opa|cue>")
validateComponentCmd.PersistentFlags().String("schema-type", "", "atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type <jsonschema|opa|cue>")
validateComponentCmd.PersistentFlags().StringP("stack", "s", "", "atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type <jsonschema|opa>")
validateComponentCmd.PersistentFlags().String("schema-path", "", "atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type <jsonschema|opa>")
validateComponentCmd.PersistentFlags().String("schema-type", "", "atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type <jsonschema|opa>")
validateComponentCmd.PersistentFlags().StringSlice("module-paths", nil, "atmos validate component <component> -s <stack> --schema-path <schema_path> --schema-type opa --module-paths catalog")
validateComponentCmd.PersistentFlags().Int("timeout", 0, "Validation timeout in seconds: atmos validate component <component> -s <stack> --timeout 15")

Expand Down
1 change: 1 addition & 0 deletions cmd/validate_stacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var ValidateStacksCmd = &cobra.Command{
Use: "stacks",
Short: "Execute 'validate stacks' command",
Long: `This command validates stack manifest configurations: atmos validate stacks`,
Example: "validate stacks",
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
Run: func(cmd *cobra.Command, args []string) {
err := e.ExecuteValidateStacksCmd(cmd, args)
Expand Down
15 changes: 7 additions & 8 deletions cmd/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import (

// workflowCmd executes a workflow
var workflowCmd = &cobra.Command{
Use: "workflow",
Short: "Execute a workflow",
Long: `This command executes a workflow: atmos workflow <name> -f <file>`,
Use: "workflow",
Short: "Execute a workflow",
Long: `This command executes a workflow: atmos workflow <name> -f <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>",
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
Run: func(cmd *cobra.Command, args []string) {
err := e.ExecuteWorkflowCmd(cmd, args)
Expand All @@ -28,10 +32,5 @@ func init() {
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>")

err := workflowCmd.MarkPersistentFlagRequired("file")
if err != nil {
u.LogErrorAndExit(err)
}

RootCmd.AddCommand(workflowCmd)
}
2 changes: 1 addition & 1 deletion examples/quick-start/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ARG GEODESIC_VERSION=2.8.2
ARG GEODESIC_OS=debian

# atmos: https://github.com/cloudposse/atmos
ARG ATMOS_VERSION=1.54.0
ARG ATMOS_VERSION=1.55.0

# Terraform: https://github.com/hashicorp/terraform/releases
ARG TF_VERSION=1.6.6
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.21

require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/alecthomas/chroma v0.10.0
github.com/bmatcuk/doublestar/v4 v4.6.1
github.com/charmbracelet/bubbles v0.17.1
github.com/charmbracelet/bubbletea v0.25.0
Expand Down Expand Up @@ -66,6 +67,7 @@ require (
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/docker/cli v24.0.0+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v24.0.0+incompatible // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXva
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
Expand Down Expand Up @@ -294,6 +296,8 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/docker/cli v24.0.0+incompatible h1:0+1VshNwBQzQAx9lOl+OYCTCEAD8fKs/qeXMx3O0wqM=
github.com/docker/cli v24.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
Expand Down
9 changes: 5 additions & 4 deletions internal/exec/atmos.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"fmt"
"strings"

"github.com/fatih/color"
"github.com/samber/lo"

tui "github.com/cloudposse/atmos/internal/tui/atmos"
cfg "github.com/cloudposse/atmos/pkg/config"
"github.com/cloudposse/atmos/pkg/schema"
u "github.com/cloudposse/atmos/pkg/utils"
"github.com/fatih/color"
"github.com/samber/lo"
)

// ExecuteAtmosCmd executes `atmos` command
Expand Down Expand Up @@ -123,7 +124,7 @@ func ExecuteAtmosCmd() error {
}

if selectedCommand == "validate component" {
_, err := ExecuteValidateComponent(cliConfig, schema.ConfigAndStacksInfo{}, selectedComponent, selectedStack, "", "", nil, 0)
_, err = ExecuteValidateComponent(cliConfig, schema.ConfigAndStacksInfo{}, selectedComponent, selectedStack, "", "", nil, 0)
if err != nil {
return err
}
Expand All @@ -138,7 +139,7 @@ func ExecuteAtmosCmd() error {
configAndStacksInfo.ComponentFromArg = selectedComponent
configAndStacksInfo.Stack = selectedStack
configAndStacksInfo.SubCommand = subcommand
err := ExecuteTerraform(configAndStacksInfo)
err = ExecuteTerraform(configAndStacksInfo)
if err != nil {
return err
}
Expand Down
66 changes: 66 additions & 0 deletions internal/exec/describe_workflows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package exec

import (
"fmt"
cfg "github.com/cloudposse/atmos/pkg/config"
"github.com/spf13/cobra"
)

// ExecuteDescribeWorkflowsCmd executes `atmos describe workflows` CLI command
func ExecuteDescribeWorkflowsCmd(cmd *cobra.Command, args []string) error {
info, err := processCommandLineArgs("terraform", cmd, args, nil)
if err != nil {
return err
}

cliConfig, err := cfg.InitCliConfig(info, true)
if err != nil {
return err
}

flags := cmd.Flags()

format, err := flags.GetString("format")
if err != nil {
return err
}

if format != "" && format != "yaml" && format != "json" {
return fmt.Errorf("invalid '--format' flag '%s'. Valid values are 'yaml' (default) and 'json'", format)
}

if format == "" {
format = "yaml"
}

outputType, err := flags.GetString("output")
if err != nil {
return err
}

if outputType != "" && outputType != "list" && outputType != "map" && outputType != "all" {
return fmt.Errorf("invalid '--output' flag '%s'. Valid values are 'list' (default), 'map' and 'all'", outputType)
}

if outputType == "" {
outputType = "list"
}

describeWorkflowsList, describeWorkflowsMap, describeWorkflowsAll, err := ExecuteDescribeWorkflows(cliConfig)
if err != nil {
return err
}

if outputType == "list" {
err = printOrWriteToFile(format, "", describeWorkflowsList)
} else if outputType == "map" {
err = printOrWriteToFile(format, "", describeWorkflowsMap)
} else {
err = printOrWriteToFile(format, "", describeWorkflowsAll)
}
if err != nil {
return err
}

return nil
}
10 changes: 9 additions & 1 deletion internal/exec/shell_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,15 @@ func ExecuteShellCommand(
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout

if redirectStdError == "" {
if runtime.GOOS == "windows" && redirectStdError == "/dev/null" {
redirectStdError = "NUL"
}

if redirectStdError == "/dev/stderr" {
cmd.Stderr = os.Stderr
} else if redirectStdError == "/dev/stdout" {
cmd.Stderr = os.Stdout
} else if redirectStdError == "" {
cmd.Stderr = os.Stderr
} else {
f, err := os.OpenFile(redirectStdError, os.O_RDWR|os.O_CREATE, 0644)
Expand Down
Loading

0 comments on commit 8f00ba2

Please sign in to comment.