Skip to content

Commit

Permalink
Merge branch 'main' into DEV-2859
Browse files Browse the repository at this point in the history
  • Loading branch information
haitham911 committed Jan 4, 2025
2 parents f4a81b3 + 52a3442 commit 8d1292b
Show file tree
Hide file tree
Showing 47 changed files with 5,122 additions and 2,411 deletions.
29 changes: 29 additions & 0 deletions atmos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,37 @@ settings:
# deep-merged with all items in the source list.
list_merge_strategy: replace

# Terminal settings for displaying content
terminal:
max_width: 120 # Maximum width for terminal output
pager: true # Use pager for long output
timestamps: false # Show timestamps in logs
colors: true # Enable colored output
unicode: true # Use unicode characters

# Markdown element styling
markdown:
document:
color: "${colors.text}"
heading:
color: "${colors.primary}"
bold: true
code_block:
color: "${colors.secondary}"
margin: 1
link:
color: "${colors.primary}"
underline: true
strong:
color: "${colors.secondary}"
bold: true
emph:
color: "${colors.muted}"
italic: true

version:
check:
enabled: true
timeout: 1000 # ms
frequency: 1h

84 changes: 71 additions & 13 deletions cmd/cmd_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"time"
Expand Down Expand Up @@ -169,29 +168,80 @@ func preCustomCommand(
commandConfig *schema.Command,
) {
var sb strings.Builder
if len(args) != len(commandConfig.Arguments) {
if len(commandConfig.Arguments) == 0 {
u.LogError(schema.AtmosConfiguration{}, errors.New("invalid command"))

//checking for zero arguments in config
if len(commandConfig.Arguments) == 0 {
if len(commandConfig.Steps) > 0 {
// do nothing here; let the code proceed
} else if len(commandConfig.Commands) > 0 {
// show sub-commands
sb.WriteString("Available command(s):\n")
for i, c := range commandConfig.Commands {
sb.WriteString(fmt.Sprintf("%d. %s %s %s\n", i+1, parentCommand.Use, commandConfig.Name, c.Name))
sb.WriteString(
fmt.Sprintf("%d. %s %s %s\n", i+1, parentCommand.Use, commandConfig.Name, c.Name),
)
}
u.LogInfo(schema.AtmosConfiguration{}, sb.String())
os.Exit(1)
} else {
// truly invalid, nothing to do
u.LogError(schema.AtmosConfiguration{}, errors.New(
"invalid command: no args, no steps, no sub-commands",
))
os.Exit(1)
}
}

//Check on many arguments required and have no default value
requiredNoDefaultCount := 0
for _, arg := range commandConfig.Arguments {
if arg.Required && arg.Default == "" {
requiredNoDefaultCount++
}
sb.WriteString(fmt.Sprintf("Command requires %d argument(s):\n", len(commandConfig.Arguments)))
for i, arg := range commandConfig.Arguments {
if arg.Name == "" {
u.LogErrorAndExit(schema.AtmosConfiguration{}, errors.New("invalid argument configuration: empty argument name"))
}

// Check if the number of arguments provided is less than the required number of arguments
if len(args) < requiredNoDefaultCount {
sb.WriteString(
fmt.Sprintf("Command requires at least %d argument(s) (no defaults provided for them):\n",
requiredNoDefaultCount))

// List out which arguments are missing
missingIndex := 1
for _, arg := range commandConfig.Arguments {
if arg.Required && arg.Default == "" {
sb.WriteString(fmt.Sprintf(" %d. %s\n", missingIndex, arg.Name))
missingIndex++
}
sb.WriteString(fmt.Sprintf(" %d. %s\n", i+1, arg.Name))
}
if len(args) > 0 {
sb.WriteString(fmt.Sprintf("\nReceived %d argument(s): %s", len(args), strings.Join(args, ", ")))
sb.WriteString(fmt.Sprintf("\nReceived %d argument(s): %s\n", len(args), strings.Join(args, ", ")))
}
u.LogErrorAndExit(schema.AtmosConfiguration{}, errors.New(sb.String()))
}

// Merge user-supplied arguments with defaults
finalArgs := make([]string, len(commandConfig.Arguments))

for i, arg := range commandConfig.Arguments {
if i < len(args) {
finalArgs[i] = args[i]
} else {
if arg.Default != "" {
finalArgs[i] = fmt.Sprintf("%v", arg.Default)
} else {
// This theoretically shouldn't happen:
sb.WriteString(fmt.Sprintf("Missing required argument '%s' with no default!\n", arg.Name))
u.LogErrorAndExit(schema.AtmosConfiguration{}, errors.New(sb.String()))
}
}
}
// Set the resolved arguments as annotations on the command
if cmd.Annotations == nil {
cmd.Annotations = make(map[string]string)
}
cmd.Annotations["resolvedArgs"] = strings.Join(finalArgs, ",")

// no "steps" means a sub command should be specified
if len(commandConfig.Steps) == 0 {
_ = cmd.Help()
Expand Down Expand Up @@ -224,12 +274,19 @@ func executeCustomCommand(
atmosConfig.Logs.Level = u.LogLevelTrace
}

mergedArgsStr := cmd.Annotations["resolvedArgs"]
finalArgs := strings.Split(mergedArgsStr, ",")
if mergedArgsStr == "" {
// If for some reason no annotation was set, just fallback
finalArgs = args
}

// Execute custom command's steps
for i, step := range commandConfig.Steps {
// Prepare template data for arguments
argumentsData := map[string]string{}
for ix, arg := range commandConfig.Arguments {
argumentsData[arg.Name] = args[ix]
argumentsData[arg.Name] = finalArgs[ix]
}

// Prepare template data for flags
Expand Down Expand Up @@ -405,7 +462,8 @@ func printMessageForMissingAtmosConfig(atmosConfig schema.AtmosConfiguration) {
u.PrintMessageInColor("atmos.yaml", c1)
fmt.Println(" CLI config file was not found.")
fmt.Print("\nThe default Atmos stacks directory is set to ")
u.PrintMessageInColor(path.Join(atmosConfig.BasePath, atmosConfig.Stacks.BasePath), c1)

u.PrintMessageInColor(filepath.Join(atmosConfig.BasePath, atmosConfig.Stacks.BasePath), c1)
fmt.Println(",\nbut the directory does not exist in the current path.")
} else {
// If Atmos found an `atmos.yaml` config file, but it defines invalid paths to Atmos stacks and components
Expand Down
20 changes: 15 additions & 5 deletions cmd/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"

"github.com/charmbracelet/glamour"
Expand Down Expand Up @@ -41,7 +41,11 @@ var docsCmd = &cobra.Command{

// Detect terminal width if not specified in `atmos.yaml`
// The default screen width is 120 characters, but uses maxWidth if set and greater than zero
maxWidth := atmosConfig.Settings.Docs.MaxWidth
maxWidth := atmosConfig.Settings.Terminal.MaxWidth
if maxWidth == 0 && atmosConfig.Settings.Docs.MaxWidth > 0 {
maxWidth = atmosConfig.Settings.Docs.MaxWidth
u.LogWarning(atmosConfig, "'settings.docs.max-width' is deprecated and will be removed in a future version. Please use 'settings.terminal.max_width' instead")
}
defaultWidth := 120
screenWidth := defaultWidth

Expand All @@ -59,7 +63,7 @@ var docsCmd = &cobra.Command{
}

// Construct the full path to the Terraform component by combining the Atmos base path, Terraform base path, and component name
componentPath := path.Join(atmosConfig.BasePath, atmosConfig.Components.Terraform.BasePath, info.Component)
componentPath := filepath.Join(atmosConfig.BasePath, atmosConfig.Components.Terraform.BasePath, info.Component)
componentPathExists, err := u.IsDirectory(componentPath)
if err != nil {
u.LogErrorAndExit(schema.AtmosConfiguration{}, err)
Expand All @@ -68,7 +72,7 @@ var docsCmd = &cobra.Command{
u.LogErrorAndExit(schema.AtmosConfiguration{}, fmt.Errorf("Component '%s' not found in path: '%s'", info.Component, componentPath))
}

readmePath := path.Join(componentPath, "README.md")
readmePath := filepath.Join(componentPath, "README.md")
if _, err := os.Stat(readmePath); err != nil {
if os.IsNotExist(err) {
u.LogErrorAndExit(schema.AtmosConfiguration{}, fmt.Errorf("No README found for component: %s", info.Component))
Expand Down Expand Up @@ -97,7 +101,13 @@ var docsCmd = &cobra.Command{
u.LogErrorAndExit(schema.AtmosConfiguration{}, err)
}

if err := u.DisplayDocs(componentDocs, atmosConfig.Settings.Docs.Pagination); err != nil {
usePager := atmosConfig.Settings.Terminal.Pager
if !usePager && atmosConfig.Settings.Docs.Pagination {
usePager = atmosConfig.Settings.Docs.Pagination
u.LogWarning(atmosConfig, "'settings.docs.pagination' is deprecated and will be removed in a future version. Please use 'settings.terminal.pager' instead")
}

if err := u.DisplayDocs(componentDocs, usePager); err != nil {
u.LogErrorAndExit(schema.AtmosConfiguration{}, fmt.Errorf("failed to display documentation: %w", err))
}

Expand Down
20 changes: 20 additions & 0 deletions cmd/markdown/workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Examples:

– Use interactive UI

$ atmos workflow

– Execute a workflow

$ atmos workflow <workflow-name> --file <file>

– Execute with stack override

$ atmos workflow <workflow-name> --file <file> --stack <stack>

– Resume from specific step

$ atmos workflow <workflow-name> --file <file> --from-step <step>

For more information, refer to the **docs**:
https://atmos.tools/cli/commands/workflow/
Loading

0 comments on commit 8d1292b

Please sign in to comment.