diff --git a/.golangci.yml b/.golangci.yml index 0fff7e7a4c..481f82c98f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -186,6 +186,7 @@ issues: - funlen - revive - gci + - errcheck output: formats: diff --git a/cmd/about.go b/cmd/about.go index 01f801c24c..d562a0c548 100644 --- a/cmd/about.go +++ b/cmd/about.go @@ -3,8 +3,9 @@ package cmd import ( _ "embed" - "github.com/cloudposse/atmos/pkg/utils" "github.com/spf13/cobra" + + "github.com/cloudposse/atmos/pkg/utils" ) //go:embed markdown/about.md @@ -17,7 +18,7 @@ var aboutCmd = &cobra.Command{ Long: `Display information about Atmos, its features, and benefits.`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - utils.PrintfMarkdown(aboutMarkdown) + utils.PrintfMarkdown("%s", aboutMarkdown) return nil }, } diff --git a/cmd/about_test.go b/cmd/about_test.go new file mode 100644 index 0000000000..3beb21b9a7 --- /dev/null +++ b/cmd/about_test.go @@ -0,0 +1,35 @@ +package cmd + +import ( + "bytes" + "io" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAboutCmd(t *testing.T) { + // Capture stdout since utils.PrintfMarkdown writes directly to os.Stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + // Execute the command + err := aboutCmd.RunE(aboutCmd, []string{}) + assert.NoError(t, err, "'atmos about' command should execute without error") + + // Close the writer and restore stdout + err = w.Close() + assert.NoError(t, err, "'atmos about' command should execute without error") + + os.Stdout = oldStdout + + // Read captured output + var output bytes.Buffer + _, err = io.Copy(&output, r) + assert.NoError(t, err, "'atmos about' command should execute without error") + + // Check if output contains expected markdown content + assert.Contains(t, output.String(), aboutMarkdown, "'atmos about' output should contain information about Atmos") +} diff --git a/cmd/support.go b/cmd/support.go index f5f3348004..c04e671141 100644 --- a/cmd/support.go +++ b/cmd/support.go @@ -3,8 +3,9 @@ package cmd import ( _ "embed" - "github.com/cloudposse/atmos/pkg/utils" "github.com/spf13/cobra" + + "github.com/cloudposse/atmos/pkg/utils" ) //go:embed markdown/support.md @@ -20,7 +21,7 @@ var supportCmd = &cobra.Command{ SilenceUsage: true, SilenceErrors: true, RunE: func(cmd *cobra.Command, args []string) error { - utils.PrintfMarkdown(supportMarkdown) + utils.PrintfMarkdown("%s", supportMarkdown) return nil }, } diff --git a/cmd/support_test.go b/cmd/support_test.go new file mode 100644 index 0000000000..9c3dab7880 --- /dev/null +++ b/cmd/support_test.go @@ -0,0 +1,35 @@ +package cmd + +import ( + "bytes" + "io" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSupportCmd(t *testing.T) { + // Capture stdout since utils.PrintfMarkdown writes directly to os.Stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + // Execute the command + err := supportCmd.RunE(supportCmd, []string{}) + assert.NoError(t, err, "'atmos support' command should execute without error") + + // Close the writer and restore stdout + err = w.Close() + assert.NoError(t, err, "'atmos support' command should execute without error") + + os.Stdout = oldStdout + + // Read captured output + var output bytes.Buffer + _, err = io.Copy(&output, r) + assert.NoError(t, err, "'atmos support' command should execute without error") + + // Check if output contains expected markdown content + assert.Contains(t, output.String(), supportMarkdown, "'atmos support' output should contain information about Cloud Posse Atmos support") +} diff --git a/cmd/workflow_test.go b/cmd/workflow_test.go new file mode 100644 index 0000000000..7be1e39828 --- /dev/null +++ b/cmd/workflow_test.go @@ -0,0 +1,51 @@ +package cmd + +import ( + "bytes" + "io" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWorkflowCmd(t *testing.T) { + stacksPath := "../tests/fixtures/scenarios/atmos-overrides-section" + + err := os.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath) + assert.NoError(t, err, "Setting 'ATMOS_CLI_CONFIG_PATH' environment variable should execute without error") + + err = os.Setenv("ATMOS_BASE_PATH", stacksPath) + assert.NoError(t, err, "Setting 'ATMOS_BASE_PATH' environment variable should execute without error") + + // Capture stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + expectedOutput := `atmos describe component c1 -s prod +atmos describe component c1 -s staging +atmos describe component c1 -s dev +atmos describe component c1 -s sandbox +atmos describe component c1 -s test +` + + // Execute the command + RootCmd.SetArgs([]string{"workflow", "--file", "workflows", "show-all-describe-component-commands"}) + err = RootCmd.Execute() + assert.NoError(t, err, "'atmos workflow' command should execute without error") + + // Close the writer and restore stdout + err = w.Close() + assert.NoError(t, err, "'atmos workflow' command should execute without error") + + os.Stdout = oldStdout + + // Read captured output + var output bytes.Buffer + _, err = io.Copy(&output, r) + assert.NoError(t, err, "'atmos workflow' command should execute without error") + + // Check if output contains expected markdown content + assert.Contains(t, output.String(), expectedOutput, "'atmos workflow' output should contain information about workflows") +} diff --git a/examples/quick-start-advanced/Dockerfile b/examples/quick-start-advanced/Dockerfile index bb98c37d3c..1a9975b227 100644 --- a/examples/quick-start-advanced/Dockerfile +++ b/examples/quick-start-advanced/Dockerfile @@ -6,7 +6,7 @@ ARG GEODESIC_OS=debian # https://atmos.tools/ # https://github.com/cloudposse/atmos # https://github.com/cloudposse/atmos/releases -ARG ATMOS_VERSION=1.164.0 +ARG ATMOS_VERSION=1.165.3 # Terraform: https://github.com/hashicorp/terraform/releases ARG TF_VERSION=1.5.7 diff --git a/go.mod b/go.mod index 7e843f77e7..914357f0a5 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/cloudposse/atmos -go 1.23.5 +go 1.24.0 require ( dario.cat/mergo v1.0.1 @@ -8,12 +8,12 @@ require ( github.com/alecthomas/chroma v0.10.0 github.com/alicebob/miniredis/v2 v2.34.0 github.com/arsham/figurine v1.3.0 - github.com/aws/aws-sdk-go-v2 v1.36.2 - github.com/aws/aws-sdk-go-v2/config v1.29.7 - github.com/aws/aws-sdk-go-v2/service/ssm v1.56.13 + github.com/aws/aws-sdk-go-v2 v1.36.3 + github.com/aws/aws-sdk-go-v2/config v1.29.9 + github.com/aws/aws-sdk-go-v2/service/ssm v1.57.2 github.com/bmatcuk/doublestar/v4 v4.8.1 github.com/charmbracelet/bubbles v0.20.0 - github.com/charmbracelet/bubbletea v1.3.3 + github.com/charmbracelet/bubbletea v1.3.4 github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/huh v0.6.0 github.com/charmbracelet/lipgloss v1.0.0 @@ -22,7 +22,7 @@ require ( github.com/editorconfig-checker/editorconfig-checker/v3 v3.2.0 github.com/elewis787/boa v0.1.2 github.com/fatih/color v1.18.0 - github.com/go-git/go-git/v5 v5.13.2 + github.com/go-git/go-git/v5 v5.14.0 github.com/gofrs/flock v0.12.1 github.com/golang/mock v1.6.0 github.com/google/go-containerregistry v0.20.3 @@ -35,20 +35,20 @@ require ( github.com/hashicorp/terraform-config-inspect v0.0.0-20250203082807-efaa306e97b4 github.com/hashicorp/terraform-exec v0.22.0 github.com/hexops/gotextdiff v1.0.3 - github.com/jfrog/jfrog-client-go v1.50.0 + github.com/jfrog/jfrog-client-go v1.51.0 github.com/json-iterator/go v1.1.12 github.com/jwalton/go-supportscolor v1.2.0 github.com/kubescape/go-git-url v0.0.30 - github.com/lrstanley/bubblezone v0.0.0-20250219025839-4a28266a24d6 + github.com/lrstanley/bubblezone v0.0.0-20250301021021-ab7b445e9861 github.com/mikefarah/yq/v4 v4.45.1 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 v1.1.0 + github.com/muesli/termenv v0.16.0 + github.com/open-policy-agent/opa v1.2.0 github.com/otiai10/copy v1.14.1 github.com/pkg/errors v0.9.1 - github.com/redis/go-redis/v9 v9.7.0 + github.com/redis/go-redis/v9 v9.7.1 github.com/samber/lo v1.49.1 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 @@ -57,13 +57,13 @@ require ( github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 github.com/zclconf/go-cty v1.16.2 - golang.org/x/oauth2 v0.26.0 - golang.org/x/term v0.29.0 - golang.org/x/text v0.22.0 + golang.org/x/oauth2 v0.28.0 + golang.org/x/term v0.30.0 + golang.org/x/text v0.23.0 gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - mvdan.cc/sh/v3 v3.10.0 + mvdan.cc/sh/v3 v3.11.0 ) require ( @@ -76,12 +76,11 @@ require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/ProtonMail/go-crypto v1.1.5 // indirect github.com/Shopify/ejson v1.3.3 // indirect github.com/a8m/envsubst v1.4.2 // indirect github.com/agext/levenshtein v1.2.2 // indirect - github.com/agnivade/levenshtein v1.2.0 // indirect + github.com/agnivade/levenshtein v1.2.1 // indirect github.com/alecthomas/chroma/v2 v2.14.0 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect @@ -94,21 +93,21 @@ require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aws/aws-sdk-go v1.44.206 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.60 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.62 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.14 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.6 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.5 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.26.10 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.16 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.15 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect github.com/aws/smithy-go v1.22.2 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -126,7 +125,7 @@ require ( github.com/charmbracelet/x/term v0.2.1 // indirect github.com/cloudflare/circl v1.6.0 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect - github.com/containerd/containerd v1.7.25 // indirect + github.com/containerd/containerd v1.7.26 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect @@ -164,7 +163,7 @@ require ( github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/wire v0.5.0 // indirect @@ -204,7 +203,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jfrog/archiver/v3 v3.6.1 // indirect - github.com/jfrog/build-info-go v1.10.9 // indirect + github.com/jfrog/build-info-go v1.10.10 // indirect github.com/jfrog/gofrog v1.7.6 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -242,9 +241,9 @@ require ( github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_golang v1.21.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect github.com/rivo/uniseg v0.4.7 // indirect @@ -289,13 +288,13 @@ require ( go4.org/intern v0.0.0-20230205224052-192e9f60865c // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect gocloud.dev v0.25.1-0.20220408200107-09b10f7359f7 // indirect - golang.org/x/crypto v0.32.0 // indirect + golang.org/x/crypto v0.35.0 // indirect golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect golang.org/x/mod v0.23.0 // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/time v0.9.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/time v0.10.0 // indirect golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/api v0.171.0 // indirect diff --git a/go.sum b/go.sum index 5f0aa52caf..4c4c9da871 100644 --- a/go.sum +++ b/go.sum @@ -674,8 +674,6 @@ github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ= github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= -github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4= github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/Shopify/ejson v1.3.3 h1:dPzgmvFhUPTJIzwdF5DaqbwW1dWaoR8ADKRdSTy6Mss= @@ -684,8 +682,8 @@ github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg= github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/agnivade/levenshtein v1.2.0 h1:U9L4IOT0Y3i0TIlUIDJ7rVUziKi/zPbrJGaFrtYH3SY= -github.com/agnivade/levenshtein v1.2.0/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= +github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= +github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -747,33 +745,33 @@ github.com/aws/aws-sdk-go v1.44.206 h1:xC7O40wdnKH4A95KdYt+smXl9hig1vu9b3mFxAxUo github.com/aws/aws-sdk-go v1.44.206/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= github.com/aws/aws-sdk-go-v2 v1.16.4/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= -github.com/aws/aws-sdk-go-v2 v1.36.2 h1:Ub6I4lq/71+tPb/atswvToaLGVMxKZvjYDVOWEExOcU= -github.com/aws/aws-sdk-go-v2 v1.36.2/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= +github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= +github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1 h1:SdK4Ppk5IzLs64ZMvr6MrSficMtjY2oS0WOORXTlxwU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1/go.mod h1:n8Bs1ElDD2wJ9kCRTczA83gYbBmjSwZp3umc6zF4EeM= github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg= github.com/aws/aws-sdk-go-v2/config v1.15.9/go.mod h1:rv/l/TbZo67kp99v/3Kb0qV6Fm1KEtKyruEV2GvVfgs= -github.com/aws/aws-sdk-go-v2/config v1.29.7 h1:71nqi6gUbAUiEQkypHQcNVSFJVUFANpSeUNShiwWX2M= -github.com/aws/aws-sdk-go-v2/config v1.29.7/go.mod h1:yqJQ3nh2HWw/uxd56bicyvmDW4KSc+4wN6lL8pYjynU= +github.com/aws/aws-sdk-go-v2/config v1.29.9 h1:Kg+fAYNaJeGXp1vmjtidss8O2uXIsXwaRqsQJKXVr+0= +github.com/aws/aws-sdk-go-v2/config v1.29.9/go.mod h1:oU3jj2O53kgOU4TXq/yipt6ryiooYjlkqqVaZk7gY/U= github.com/aws/aws-sdk-go-v2/credentials v1.11.2/go.mod h1:j8YsY9TXTm31k4eFhspiQicfXPLZ0gYXA50i4gxPE8g= github.com/aws/aws-sdk-go-v2/credentials v1.12.4/go.mod h1:7g+GGSp7xtR823o1jedxKmqRZGqLdoHQfI4eFasKKxs= -github.com/aws/aws-sdk-go-v2/credentials v1.17.60 h1:1dq+ELaT5ogfmqtV1eocq8SpOK1NRsuUfmhQtD/XAh4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.60/go.mod h1:HDes+fn/xo9VeszXqjBVkxOo/aUy8Mc6QqKvZk32GlE= +github.com/aws/aws-sdk-go-v2/credentials v1.17.62 h1:fvtQY3zFzYJ9CfixuAQ96IxDrBajbBWGqjNTCa79ocU= +github.com/aws/aws-sdk-go-v2/credentials v1.17.62/go.mod h1:ElETBxIQqcxej++Cs8GyPBbgMys5DgQPTwo7cUPDKt8= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnqSqz8O48LBYDSC+k6brng09jcMOk= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.5/go.mod h1:WAPnuhG5IQ/i6DETFl5NmX3kKqCzw7aau9NHAGcm4QE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29 h1:JO8pydejFKmGcUNiiwt75dzLHRWthkwApIvPoyUtXEg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29/go.mod h1:adxZ9i9DRmB8zAT0pO0yGnsmu0geomp5a3uq5XpgOJ8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3/go.mod h1:0dHuD2HZZSiwfJSy1FO5bX1hQ1TxVV1QXXjpn3XUE44= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.14 h1:qpJmFbypCfwPok5PGTSnQy1NKbv4Hn8xGsee9l4xOPE= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.14/go.mod h1:IOYB+xOZik8YgdTlnDSwbvKmCkikA3nVue8/Qnfzs0c= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.11/go.mod h1:tmUB6jakq5DFNcXsXOA/ZQ7/C8VnSKYkx58OI7Fh79g= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 h1:knLyPMw3r3JsU8MFHWctE4/e2qWbPaxDYLlohPvnY8c= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33/go.mod h1:EBp2HQ3f+XCB+5J+IoEbGhoV7CpJbnrsd4asNXmTL0A= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.5/go.mod h1:fV1AaS2gFc1tM0RCb015FJ0pvWVUfJZANzjwoO4YakM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 h1:K0+Ne08zqti8J9jwENxZ5NoUyBnaFDTu3apwQJWrwwA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33/go.mod h1:K97stwwzaWzmqxO8yLGHhClbVW1tC6VT1pDLk1pGrq4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10/go.mod h1:8DcYQcz0+ZJaSxANlHIsbbi6S+zMwjwdDqwW3r9AzaE= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.12/go.mod h1:00c7+ALdPh4YeEUPXJzyU0Yy01nPGOq2+9rUaz05z9g= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= @@ -788,8 +786,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.6 h1:9mvDAsMiN+07wcf github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.6/go.mod h1:Eus+Z2iBIEfhOvhSdMTcscNOMy6n3X9/BJV0Zgax98w= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3/go.mod h1:wlY6SVjuwvh3TVRpTqdy4I1JpBFLX4UGeKZdWntaocw= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.5/go.mod h1:ZbkttHXaVn3bBo/wpJbQGiiIWR90eTBUVBrEHUEQlho= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14 h1:2scbY6//jy/s8+5vGrk7l1+UtHl0h9A4MjOO2k/TM2E= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14/go.mod h1:bRpZPHZpSe5YRHmPfK3h1M7UBFCn2szHzyx0rw04zro= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.3/go.mod h1:Bm/v2IaN6rZ+Op7zX+bOUMdL4fsrYZiD0dsjLhNKwZc= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.5 h1:DyPYkrH4R2zn+Pdu6hM3VTuPsQYAE6x2WB24X85Sgw0= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.5/go.mod h1:XtL92YWo0Yq80iN3AgYRERJqohg4TozrqRlxYhHGJ7g= @@ -801,18 +799,18 @@ github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.4/go.mod h1:PJc8s+lxyU github.com/aws/aws-sdk-go-v2/service/sns v1.17.4/go.mod h1:kElt+uCcXxcqFyc+bQqZPFD9DME/eC6oHBXvFzQ9Bcw= github.com/aws/aws-sdk-go-v2/service/sqs v1.18.3/go.mod h1:skmQo0UPvsjsuYYSYMVmrPc1HWCbHUJyrCEp+ZaLzqM= github.com/aws/aws-sdk-go-v2/service/ssm v1.24.1/go.mod h1:NR/xoKjdbRJ+qx0pMR4mI+N/H1I1ynHwXnO6FowXJc0= -github.com/aws/aws-sdk-go-v2/service/ssm v1.56.13 h1:JfPeW7F6Y+VqBg6p+8zQv4wlgceguYu5ZT0USEGZ89g= -github.com/aws/aws-sdk-go-v2/service/ssm v1.56.13/go.mod h1:EonGQFn66wZkJJrrKXrryrxoS3V30rcHvaWvc6oGHCI= +github.com/aws/aws-sdk-go-v2/service/ssm v1.57.2 h1:3//q1r7gW/kpiWiPfFILw+N81rangyyMJV6vrznFyvw= +github.com/aws/aws-sdk-go-v2/service/ssm v1.57.2/go.mod h1:PUWUl5MDiYNQkUHN9Pyd9kgtA/YhbxnSnHP+yQqzrM8= github.com/aws/aws-sdk-go-v2/service/sso v1.11.3/go.mod h1:7UQ/e69kU7LDPtY40OyoHYgRmgfGM4mgsLYtcObdveU= github.com/aws/aws-sdk-go-v2/service/sso v1.11.7/go.mod h1:TFVe6Rr2joVLsYQ1ABACXgOC6lXip/qpX2x5jWg/A9w= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.16 h1:YV6xIKDJp6U7YB2bxfud9IENO1LRpGhe2Tv/OKtPrOQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.16/go.mod h1:DvbmMKgtpA6OihFJK13gHMZOZrCHttz8wPHGKXqU+3o= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15 h1:kMyK3aKotq1aTBsj1eS8ERJLjqYRRRcsmP33ozlCvlk= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15/go.mod h1:5uPZU7vSNzb8Y0dm75xTikinegPYK3uJmIHQZFq5Aqo= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 h1:8JdC7Gr9NROg1Rusk25IcZeTO59zLxsKgE0gkh5O6h0= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.1/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 h1:KwuLovgQPcdjNMfFt9OhUd9a2OwcOKhxfvF4glTzLuA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= github.com/aws/aws-sdk-go-v2/service/sts v1.16.3/go.mod h1:bfBj0iVmsUyUg4weDB4NxktD9rDGeKSVWnjTnwbx9b8= github.com/aws/aws-sdk-go-v2/service/sts v1.16.6/go.mod h1:rP1rEOKAGZoXp4iGDxSXFvODAtXpm34Egf0lL0eshaQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.15 h1:ht1jVmeeo2anR7zDiYJLSnRYnO/9NILXXu42FP3rJg0= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.15/go.mod h1:xWZ5cOiFe3czngChE4LhCBqUxNwgfwndEF7XlYP/yD8= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 h1:PZV5W8yk4OtH1JAuhV2PXwwO9v5G5Aoj+eMCn4T+1Kc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= @@ -863,8 +861,8 @@ github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiw github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o= github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= -github.com/charmbracelet/bubbletea v1.3.3 h1:WpU6fCY0J2vDWM3zfS3vIDi/ULq3SYphZhkAGGvmEUY= -github.com/charmbracelet/bubbletea v1.3.3/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo= +github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI= +github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo= github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= @@ -910,8 +908,8 @@ github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/containerd v1.7.25 h1:khEQOAXOEJalRO228yzVsuASLH42vT7DIo9Ss+9SMFQ= -github.com/containerd/containerd v1.7.25/go.mod h1:tWfHzVI0azhw4CT2vaIjsb2CoV4LJ9PrMPaULAr21Ok= +github.com/containerd/containerd v1.7.26 h1:3cs8K2RHlMQaPifLqgRyI4VBkoldNdEw62cb7qQga7k= +github.com/containerd/containerd v1.7.26/go.mod h1:m4JU0E+h0ebbo9yXD7Hyt+sWnc8tChm7MudCjj4jRvQ= github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII= github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= @@ -975,8 +973,8 @@ github.com/editorconfig-checker/editorconfig-checker/v3 v3.2.0 h1:uH7cZAGj3I8rS5 github.com/editorconfig-checker/editorconfig-checker/v3 v3.2.0/go.mod h1:pyykRV3+SalXDuX1fAN7e5THne4+asZu/FhP5dXiWSo= github.com/editorconfig/editorconfig-core-go/v2 v2.6.2 h1:dKG8sc7n321deIVRcQtwlMNoBEra7j0qQ8RwxO8RN0w= github.com/editorconfig/editorconfig-core-go/v2 v2.6.2/go.mod h1:7dvD3GCm7eBw53xZ/lsiq72LqobdMg3ITbMBxnmJmqY= -github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM= -github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= +github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= +github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= github.com/elewis787/boa v0.1.2 h1:xNKWJ9X2MWbLSLLOA31N4l1Jdec9FZSkbTvXy3C8rw4= github.com/elewis787/boa v0.1.2/go.mod h1:EFDKuz/bYgQAKJQBnfHmB9i+bBzsaZJyyoSmOz6eBZI= github.com/elliotchance/orderedmap v1.7.1 h1:8SR2DB391dw0HVI9572ElrY+KU0Q89OCXYwWZx7aAZc= @@ -1052,8 +1050,8 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0= -github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A= +github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= +github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -1178,8 +1176,9 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-containerregistry v0.20.3 h1:oNx7IdTI936V8CQRveCjaxOiegWwvM7kqkbXTpyiovI= github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lwNWK+cxgCuX1vd3PIBDNI= github.com/google/go-github/v59 v59.0.0 h1:7h6bgpF5as0YQLLkEiVqpgtJqjimMYhBkD4jT5aN3VA= @@ -1423,12 +1422,12 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jfrog/archiver/v3 v3.6.1 h1:LOxnkw9pOn45DzCbZNFV6K0+6dCsQ0L8mR3ZcujO5eI= github.com/jfrog/archiver/v3 v3.6.1/go.mod h1:VgR+3WZS4N+i9FaDwLZbq+jeU4B4zctXL+gL4EMzfLw= -github.com/jfrog/build-info-go v1.10.9 h1:mdJ+wlLw2ReFsqC7rifJVlRYLEqYk38uXDYAOZASuGE= -github.com/jfrog/build-info-go v1.10.9/go.mod h1:JcISnovFXKx3wWf3p1fcMmlPdt6adxScXvoJN4WXqIE= +github.com/jfrog/build-info-go v1.10.10 h1:2nOFjV7SX1uisi2rQK7fb4Evm7YkSOdmssrm6Tf4ipc= +github.com/jfrog/build-info-go v1.10.10/go.mod h1:JcISnovFXKx3wWf3p1fcMmlPdt6adxScXvoJN4WXqIE= github.com/jfrog/gofrog v1.7.6 h1:QmfAiRzVyaI7JYGsB7cxfAJePAZTzFz0gRWZSE27c6s= github.com/jfrog/gofrog v1.7.6/go.mod h1:ntr1txqNOZtHplmaNd7rS4f8jpA5Apx8em70oYEe7+4= -github.com/jfrog/jfrog-client-go v1.50.0 h1:t7v/zpLkPomHR6ZjVbPQ1WPQJd9IFKESK9Tt6phZz3k= -github.com/jfrog/jfrog-client-go v1.50.0/go.mod h1:xHxwKBjPSUBd/FyCWgusfHmSWKUZTkfOZkTmntC2F5Y= +github.com/jfrog/jfrog-client-go v1.51.0 h1:O9sgpgEDBW9t05brGYwNR/NMqJ/e3WZY9G8Wge2xR+Q= +github.com/jfrog/jfrog-client-go v1.51.0/go.mod h1:2tQPwRhGS/F357BOKFfZrQbjd4XbzHPYUQm/OFNwLHg= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= @@ -1500,8 +1499,8 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lrstanley/bubblezone v0.0.0-20250219025839-4a28266a24d6 h1:bOg0ACVRYwP+PxgIrfcRSgTiXseIu3DcNNFleDX+yZc= -github.com/lrstanley/bubblezone v0.0.0-20250219025839-4a28266a24d6/go.mod h1:Nn+Kk4v8HhsNDmWMgOl2zhQdxu7pEdheXuLkD+7rx/0= +github.com/lrstanley/bubblezone v0.0.0-20250301021021-ab7b445e9861 h1:lJZbpnKYI7tijRPRr7uZt7aOi1Mn5smjvM1hTAJC/vA= +github.com/lrstanley/bubblezone v0.0.0-20250301021021-ab7b445e9861/go.mod h1:KobQOIne1AxegBa5hNBtvs4i6kAjBImL+TtQlzP6IZE= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= @@ -1598,8 +1597,8 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg= -github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -1610,8 +1609,8 @@ github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= -github.com/open-policy-agent/opa v1.1.0 h1:HMz2evdEMTyNqtdLjmu3Vyx06BmhNYAx67Yz3Ll9q2s= -github.com/open-policy-agent/opa v1.1.0/go.mod h1:T1pASQ1/vwfTa+e2fYcfpLCvWgYtqtiUv+IuA/dLPQs= +github.com/open-policy-agent/opa v1.2.0 h1:88NDVCM0of1eO6Z4AFeL3utTEtMuwloFmWWU7dRV1z0= +github.com/open-policy-agent/opa v1.2.0/go.mod h1:30euUmOvuBoebRCcJ7DMF42bRBOPznvt0ACUMYDUGVY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -1653,8 +1652,8 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA= +github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1664,8 +1663,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= @@ -1673,8 +1672,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= -github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/redis/go-redis/v9 v9.7.1 h1:4LhKRCIduqXqtvCUlaq9c8bdHOkICjDMrr1+Zb3osAc= +github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -1684,8 +1683,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -1927,8 +1926,9 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2067,8 +2067,9 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2100,8 +2101,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= -golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2122,8 +2123,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2231,8 +2232,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2250,8 +2251,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2272,8 +2273,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2283,8 +2284,8 @@ golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2751,8 +2752,8 @@ modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= -mvdan.cc/sh/v3 v3.10.0 h1:v9z7N1DLZ7owyLM/SXZQkBSXcwr2IGMm2LY2pmhVXj4= -mvdan.cc/sh/v3 v3.10.0/go.mod h1:z/mSSVyLFGZzqb3ZIKojjyqIx/xbmz/UHdCSv9HmqXY= +mvdan.cc/sh/v3 v3.11.0 h1:q5h+XMDRfUGUedCqFFsjoFjrhwf2Mvtt1rkMvVz0blw= +mvdan.cc/sh/v3 v3.11.0/go.mod h1:LRM+1NjoYCzuq/WZ6y44x14YNAI0NK7FLPeQSaFagGg= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= oras.land/oras-go/v2 v2.3.1 h1:lUC6q8RkeRReANEERLfH86iwGn55lbSWP20egdFHVec= oras.land/oras-go/v2 v2.3.1/go.mod h1:5AQXVEu1X/FKp1F9DMOb5ZItZBOa0y5dha0yCm4NR9c= diff --git a/internal/exec/stack_processor_utils.go b/internal/exec/stack_processor_utils.go index e30e4fde13..4a3b437544 100644 --- a/internal/exec/stack_processor_utils.go +++ b/internal/exec/stack_processor_utils.go @@ -73,7 +73,7 @@ func ProcessYAMLConfigFiles( ".yml", ) - deepMergedStackConfig, importsConfig, stackConfig, _, _, err := ProcessYAMLConfigFile( + deepMergedStackConfig, importsConfig, stackConfig, _, _, _, _, err := ProcessYAMLConfigFile( atmosConfig, stackBasePath, p, @@ -85,6 +85,8 @@ func ProcessYAMLConfigFiles( false, map[string]any{}, map[string]any{}, + map[string]any{}, + map[string]any{}, "", ) if err != nil { @@ -162,8 +164,10 @@ func ProcessYAMLConfigFile( skipTemplatesProcessingInImports bool, ignoreMissingTemplateValues bool, skipIfMissing bool, - parentTerraformOverrides map[string]any, - parentHelmfileOverrides map[string]any, + parentTerraformOverridesInline map[string]any, + parentTerraformOverridesImports map[string]any, + parentHelmfileOverridesInline map[string]any, + parentHelmfileOverridesImports map[string]any, atmosManifestJsonSchemaFilePath string, ) ( map[string]any, @@ -171,6 +175,8 @@ func ProcessYAMLConfigFile( map[string]any, map[string]any, map[string]any, + map[string]any, + map[string]any, error, ) { var stackConfigs []map[string]any @@ -196,13 +202,13 @@ func ProcessYAMLConfigFile( // This is useful when generating Atmos manifests using other tools, but the imported files are not present yet at the generation time. if err != nil { if ignoreMissingFiles || skipIfMissing { - return map[string]any{}, map[string]map[string]any{}, map[string]any{}, map[string]any{}, map[string]any{}, nil + return map[string]any{}, map[string]map[string]any{}, map[string]any{}, map[string]any{}, map[string]any{}, map[string]any{}, map[string]any{}, nil } else { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, err } } if stackYamlConfig == "" { - return map[string]any{}, map[string]map[string]any{}, map[string]any{}, map[string]any{}, map[string]any{}, nil + return map[string]any{}, map[string]map[string]any{}, map[string]any{}, map[string]any{}, map[string]any{}, map[string]any{}, map[string]any{}, nil } stackManifestTemplatesProcessed := stackYamlConfig @@ -217,7 +223,7 @@ func ProcessYAMLConfigFile( stackManifestTemplatesErrorMessage = fmt.Sprintf("\n\n%s", stackYamlConfig) } e := fmt.Errorf("invalid stack manifest '%s'\n%v%s", relativeFilePath, err, stackManifestTemplatesErrorMessage) - return nil, nil, nil, nil, nil, e + return nil, nil, nil, nil, nil, nil, nil, e } } @@ -227,7 +233,7 @@ func ProcessYAMLConfigFile( stackManifestTemplatesErrorMessage = fmt.Sprintf("\n\n%s", stackYamlConfig) } e := fmt.Errorf("invalid stack manifest '%s'\n%v%s", relativeFilePath, err, stackManifestTemplatesErrorMessage) - return nil, nil, nil, nil, nil, e + return nil, nil, nil, nil, nil, nil, nil, e } // If the path to the Atmos manifest JSON Schema is provided, validate the stack manifest against it @@ -236,12 +242,12 @@ func ProcessYAMLConfigFile( // jsonschema: invalid jsonType: map[interface {}]interface {} dataJson, err := u.ConvertToJSONFast(stackConfigMap) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, err } dataFromJson, err := u.ConvertFromJSON(dataJson) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, err } compiler := jsonschema.NewCompiler() @@ -250,18 +256,18 @@ func ProcessYAMLConfigFile( atmosManifestJsonSchemaFileReader, err := os.Open(atmosManifestJsonSchemaFilePath) if err != nil { - return nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err) + return nil, nil, nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err) } if err := compiler.AddResource(atmosManifestJsonSchemaFilePath, atmosManifestJsonSchemaFileReader); err != nil { - return nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err) + return nil, nil, nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err) } compiler.Draft = jsonschema.Draft2020 compiledSchema, err := compiler.Compile(atmosManifestJsonSchemaFilePath) if err != nil { - return nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err) + return nil, nil, nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err) } if err = compiledSchema.Validate(dataFromJson); err != nil { @@ -269,11 +275,11 @@ func ProcessYAMLConfigFile( case *jsonschema.ValidationError: b, err2 := json.MarshalIndent(e.BasicOutput(), "", " ") if err2 != nil { - return nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err2) + return nil, nil, nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err2) } - return nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, string(b)) + return nil, nil, nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, string(b)) default: - return nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err) + return nil, nil, nil, nil, nil, nil, nil, errors.Errorf(atmosManifestJsonSchemaValidationErrorFormat, relativeFilePath, err) } } } @@ -283,19 +289,19 @@ func ProcessYAMLConfigFile( // Global overrides in this stack manifest if i, ok := stackConfigMap[cfg.OverridesSectionName]; ok { if globalOverrides, ok = i.(map[string]any); !ok { - return nil, nil, nil, nil, nil, fmt.Errorf("invalid 'overrides' section in the stack manifest '%s'", relativeFilePath) + return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("invalid 'overrides' section in the stack manifest '%s'", relativeFilePath) } } // Terraform overrides in this stack manifest if o, ok := stackConfigMap[cfg.TerraformSectionName]; ok { if globalTerraformSection, ok = o.(map[string]any); !ok { - return nil, nil, nil, nil, nil, fmt.Errorf("invalid 'terraform' section in the stack manifest '%s'", relativeFilePath) + return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("invalid 'terraform' section in the stack manifest '%s'", relativeFilePath) } if i, ok := globalTerraformSection[cfg.OverridesSectionName]; ok { if terraformOverrides, ok = i.(map[string]any); !ok { - return nil, nil, nil, nil, nil, fmt.Errorf("invalid 'terraform.overrides' section in the stack manifest '%s'", relativeFilePath) + return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("invalid 'terraform.overrides' section in the stack manifest '%s'", relativeFilePath) } } } @@ -303,45 +309,43 @@ func ProcessYAMLConfigFile( // Helmfile overrides in this stack manifest if o, ok := stackConfigMap[cfg.HelmfileSectionName]; ok { if globalHelmfileSection, ok = o.(map[string]any); !ok { - return nil, nil, nil, nil, nil, fmt.Errorf("invalid 'helmfile' section in the stack manifest '%s'", relativeFilePath) + return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("invalid 'helmfile' section in the stack manifest '%s'", relativeFilePath) } if i, ok := globalHelmfileSection[cfg.OverridesSectionName]; ok { if helmfileOverrides, ok = i.(map[string]any); !ok { - return nil, nil, nil, nil, nil, fmt.Errorf("invalid 'terraform.overrides' section in the stack manifest '%s'", relativeFilePath) + return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("invalid 'terraform.overrides' section in the stack manifest '%s'", relativeFilePath) } } } - // Final Terraform `overrides` - finalTerraformOverrides, err = m.Merge( + parentTerraformOverridesInline, err = m.Merge( atmosConfig, - []map[string]any{globalOverrides, terraformOverrides, parentTerraformOverrides}, + []map[string]any{globalOverrides, terraformOverrides, parentTerraformOverridesInline}, ) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, err } - // Final Helmfile `overrides` - finalHelmfileOverrides, err = m.Merge( + parentHelmfileOverridesInline, err = m.Merge( atmosConfig, - []map[string]any{globalOverrides, helmfileOverrides, parentHelmfileOverrides}, + []map[string]any{globalOverrides, helmfileOverrides, parentHelmfileOverridesInline}, ) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, err } // Find and process all imports importStructs, err := ProcessImportSection(stackConfigMap, relativeFilePath) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, err } for _, importStruct := range importStructs { imp := importStruct.Path if imp == "" { - return nil, nil, nil, nil, nil, fmt.Errorf("invalid empty import in the manifest '%s'", relativeFilePath) + return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("invalid empty import in the manifest '%s'", relativeFilePath) } // If the import file is specified without extension, use `.yaml` as default @@ -383,7 +387,7 @@ func ProcessYAMLConfigFile( errorMessage := fmt.Sprintf("invalid import in the manifest '%s'\nThe file imports itself in '%s'", relativeFilePath, imp) - return nil, nil, nil, nil, nil, errors.New(errorMessage) + return nil, nil, nil, nil, nil, nil, nil, errors.New(errorMessage) } // Find all import matches in the glob @@ -397,7 +401,7 @@ func ProcessYAMLConfigFile( // The import was not found -> check if the import is a Go template; if not, return the error isGolangTemplate, err2 := IsGolangTemplate(imp) if err2 != nil { - return nil, nil, nil, nil, nil, err2 + return nil, nil, nil, nil, nil, nil, nil, err2 } // If the import is not a Go template and SkipIfMissing is false, return the error @@ -408,13 +412,13 @@ func ProcessYAMLConfigFile( relativeFilePath, err, ) - return nil, nil, nil, nil, nil, errors.New(errorMessage) + return nil, nil, nil, nil, nil, nil, nil, errors.New(errorMessage) } else if importMatches == nil { errorMessage := fmt.Sprintf("no matches found for the import '%s' in the file '%s'", imp, relativeFilePath, ) - return nil, nil, nil, nil, nil, errors.New(errorMessage) + return nil, nil, nil, nil, nil, nil, nil, errors.New(errorMessage) } } } @@ -427,12 +431,12 @@ func ProcessYAMLConfigFile( listOfMaps := []map[string]any{importStruct.Context, context} mergedContext, err := m.Merge(atmosConfig, listOfMaps) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, err } // Process the imports in the current manifest for _, importFile := range importMatches { - yamlConfig, _, yamlConfigRaw, importTerraformOverrides, importHelmfileOverrides, err2 := ProcessYAMLConfigFile( + yamlConfig, _, yamlConfigRaw, _, terraformOverridesImports, _, helmfileOverridesImports, err2 := ProcessYAMLConfigFile( atmosConfig, basePath, importFile, @@ -442,34 +446,34 @@ func ProcessYAMLConfigFile( importStruct.SkipTemplatesProcessing, true, // importStruct.IgnoreMissingTemplateValues, importStruct.SkipIfMissing, - finalTerraformOverrides, - finalHelmfileOverrides, + parentTerraformOverridesInline, + parentTerraformOverridesImports, + parentHelmfileOverridesInline, + parentHelmfileOverridesImports, "", ) if err2 != nil { - return nil, nil, nil, nil, nil, err2 + return nil, nil, nil, nil, nil, nil, nil, err2 } - stackConfigs = append(stackConfigs, yamlConfig) - - // Final Terraform `overrides` - finalTerraformOverrides, err = m.Merge( + parentTerraformOverridesImports, err = m.Merge( atmosConfig, - []map[string]any{importTerraformOverrides, finalTerraformOverrides}, + []map[string]any{parentTerraformOverridesImports, terraformOverridesImports}, ) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, err } - // Final Helmfile `overrides` - finalHelmfileOverrides, err = m.Merge( + parentHelmfileOverridesImports, err = m.Merge( atmosConfig, - []map[string]any{importHelmfileOverrides, finalHelmfileOverrides}, + []map[string]any{parentHelmfileOverridesImports, helmfileOverridesImports}, ) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, err } + stackConfigs = append(stackConfigs, yamlConfig) + importRelativePathWithExt := strings.Replace(filepath.ToSlash(importFile), filepath.ToSlash(basePath)+"/", "", 1) ext2 := filepath.Ext(importRelativePathWithExt) if ext2 == "" { @@ -481,6 +485,24 @@ func ProcessYAMLConfigFile( } } + // Terraform `overrides` + finalTerraformOverrides, err = m.Merge( + atmosConfig, + []map[string]any{parentTerraformOverridesImports, parentTerraformOverridesInline}, + ) + if err != nil { + return nil, nil, nil, nil, nil, nil, nil, err + } + + // Helmfile `overrides` + finalHelmfileOverrides, err = m.Merge( + atmosConfig, + []map[string]any{parentHelmfileOverridesImports, parentHelmfileOverridesInline}, + ) + if err != nil { + return nil, nil, nil, nil, nil, nil, nil, err + } + // Add the `overrides` section to all components in this stack manifest if len(finalTerraformOverrides) > 0 || len(finalHelmfileOverrides) > 0 { if componentsSection, ok := stackConfigMap[cfg.ComponentsSectionName].(map[string]any); ok { @@ -516,14 +538,16 @@ func ProcessYAMLConfigFile( stackConfigsDeepMerged, err := m.Merge(atmosConfig, stackConfigs) if err != nil { err2 := fmt.Errorf("ProcessYAMLConfigFile: Merge: Deep-merge the stack manifest and all the imports: Error: %v", err) - return nil, nil, nil, nil, nil, err2 + return nil, nil, nil, nil, nil, nil, nil, err2 } - return stackConfigsDeepMerged, importsConfig, stackConfigMap, finalTerraformOverrides, finalHelmfileOverrides, nil + return stackConfigsDeepMerged, importsConfig, stackConfigMap, + parentTerraformOverridesInline, parentTerraformOverridesImports, + parentHelmfileOverridesInline, parentHelmfileOverridesImports, + nil } -// ProcessStackConfig takes a stack manifest, deep-merges all variables, settings, environments and backends, -// and returns the final stack configuration for all Terraform and helmfile components +// ProcessStackConfig takes a stack manifest, deep-merges all variables, settings, environments and backends, and returns the final stack configuration for all Terraform and helmfile components. func ProcessStackConfig( atmosConfig schema.AtmosConfiguration, stacksBasePath string, @@ -1900,7 +1924,7 @@ func CreateComponentStackMap( isYaml := u.IsYaml(p) if !isDirectory && isYaml { - config, _, _, _, _, err := ProcessYAMLConfigFile( + config, _, _, _, _, _, _, err := ProcessYAMLConfigFile( atmosConfig, stacksBasePath, p, @@ -1912,6 +1936,8 @@ func CreateComponentStackMap( false, map[string]any{}, map[string]any{}, + map[string]any{}, + map[string]any{}, "", ) if err != nil { diff --git a/internal/exec/stack_processor_utils_test.go b/internal/exec/stack_processor_utils_test.go new file mode 100644 index 0000000000..0723ee356a --- /dev/null +++ b/internal/exec/stack_processor_utils_test.go @@ -0,0 +1,443 @@ +package exec + +import ( + "sort" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/cloudposse/atmos/pkg/schema" + u "github.com/cloudposse/atmos/pkg/utils" +) + +func TestProcessYAMLConfigFile(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/relative-paths/stacks" + filePath := "../../tests/fixtures/scenarios/relative-paths/stacks/orgs/acme/platform/dev.yaml" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, stackConfigMap, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Nil(t, err) + assert.Equal(t, 3, len(stackConfigMap)) + + mapResultKeys := u.StringKeysFromMap(stackConfigMap) + // sorting so that the output is deterministic + sort.Strings(mapResultKeys) + + assert.Equal(t, "components", mapResultKeys[0]) + assert.Equal(t, "import", mapResultKeys[1]) + assert.Equal(t, "vars", mapResultKeys[2]) +} + +func TestProcessYAMLConfigFileIgnoreMissingFiles(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/not-present.yaml" + ignoreMissingFiles := true + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, stackConfigMap, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + ignoreMissingFiles, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Nil(t, err) + assert.Equal(t, 0, len(stackConfigMap)) +} + +func TestProcessYAMLConfigFileMissingFilesReturnError(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/not-present.yaml" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, _, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Error(t, err) +} + +func TestProcessYAMLConfigFileEmptyManifest(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/empty.yaml" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, stackConfigMap, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Nil(t, err) + assert.Equal(t, 0, len(stackConfigMap)) +} + +func TestProcessYAMLConfigFileInvalidManifest(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid.yaml" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, _, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Error(t, err) +} + +func TestProcessYAMLConfigFileInvalidImportTemplate(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-import-template.yaml" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, _, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Error(t, err) +} + +func TestProcessYAMLConfigFileInvalidValidationSchemaPath(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/dev.yaml" + atmosManifestJsonSchemaFilePath := "does-not-exist" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, _, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + atmosManifestJsonSchemaFilePath, + ) + + assert.Error(t, err) +} + +func TestProcessYAMLConfigFileInvalidManifestSchema(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-manifest-schema.yaml" + atmosManifestJsonSchemaFilePath := "../../tests/fixtures/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, _, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + atmosManifestJsonSchemaFilePath, + ) + + assert.Error(t, err) +} + +func TestProcessYAMLConfigFileInvalidGlobalOverridesSection(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-global-overrides.yaml" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, _, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Error(t, err) +} + +func TestProcessYAMLConfigFileInvalidTerraformOverridesSection(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-terraform-overrides.yaml" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, _, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Error(t, err) +} + +func TestProcessYAMLConfigFileInvalidHelmfileOverridesSection(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks" + filePath := "../../tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-helmfile-overrides.yaml" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, _, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Error(t, err) +} diff --git a/internal/exec/validate_stacks.go b/internal/exec/validate_stacks.go index e1f40e6f61..83db4de64d 100644 --- a/internal/exec/validate_stacks.go +++ b/internal/exec/validate_stacks.go @@ -152,7 +152,7 @@ func ValidateStacks(atmosConfig schema.AtmosConfiguration) error { filepath.Join(atmosConfig.BasePath, atmosConfig.Stacks.BasePath))) for _, filePath := range stackConfigFilesAbsolutePaths { - stackConfig, importsConfig, _, _, _, err := ProcessYAMLConfigFile( + stackConfig, importsConfig, _, _, _, _, _, err := ProcessYAMLConfigFile( atmosConfig, atmosConfig.StacksBaseAbsolutePath, filePath, @@ -164,6 +164,8 @@ func ValidateStacks(atmosConfig schema.AtmosConfiguration) error { false, map[string]any{}, map[string]any{}, + map[string]any{}, + map[string]any{}, atmosManifestJsonSchemaFilePath, ) if err != nil { diff --git a/internal/exec/validate_stacks_test.go b/internal/exec/validate_stacks_test.go new file mode 100644 index 0000000000..de0c3783f7 --- /dev/null +++ b/internal/exec/validate_stacks_test.go @@ -0,0 +1,48 @@ +package exec + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/cloudposse/atmos/pkg/schema" +) + +func TestValidateStacks(t *testing.T) { + basePath := "../../tests/fixtures/scenarios/atmos-overrides-section/stacks" + + basePathAbs, err := filepath.Abs(basePath) + assert.Nil(t, err) + + stackConfigFilesAbsolutePaths := []string{ + filepath.Join(basePathAbs, "deploy", "dev.yaml"), + filepath.Join(basePathAbs, "deploy", "prod.yaml"), + filepath.Join(basePathAbs, "deploy", "sandbox.yaml"), + filepath.Join(basePathAbs, "deploy", "staging.yaml"), + filepath.Join(basePathAbs, "deploy", "test.yaml"), + } + + atmosConfig := schema.AtmosConfiguration{ + BasePath: basePath, + StacksBaseAbsolutePath: basePathAbs, + StackConfigFilesAbsolutePaths: stackConfigFilesAbsolutePaths, + Stacks: schema.Stacks{ + NamePattern: "{stage}", + }, + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + err = ValidateStacks(atmosConfig) + assert.Nil(t, err) +} diff --git a/internal/exec/vendor_utils.go b/internal/exec/vendor_utils.go index 63abbc59c5..35dec5adb8 100644 --- a/internal/exec/vendor_utils.go +++ b/internal/exec/vendor_utils.go @@ -133,12 +133,11 @@ func ExecuteVendorPullCommand(cmd *cobra.Command, args []string) error { q = fmt.Sprintf("Did you mean 'atmos vendor pull -c %s'?", args[0]) } - return fmt.Errorf("to vendor a component, the '--component' (shorthand '-c') flag needs to be specified.\n" + - "Example: atmos vendor pull -c \n" + - q) + return fmt.Errorf("to vendor a component, the '--component' (shorthand '-c') flag needs to be specified.\n"+ + "Example: atmos vendor pull -c \n%s", q) } -// ReadAndProcessVendorConfigFile reads and processes the Atmos vendoring config file `vendor.yaml` +// ReadAndProcessVendorConfigFile reads and processes the Atmos vendoring config file `vendor.yaml`. func ReadAndProcessVendorConfigFile( atmosConfig schema.AtmosConfiguration, vendorConfigFile string, diff --git a/internal/exec/vendor_utils_test.go b/internal/exec/vendor_utils_test.go new file mode 100644 index 0000000000..050a9f957a --- /dev/null +++ b/internal/exec/vendor_utils_test.go @@ -0,0 +1,60 @@ +package exec + +import ( + "os" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + + "github.com/cloudposse/atmos/pkg/schema" +) + +func TestExecuteVendorPullCommand(t *testing.T) { + stacksPath := "../../tests/fixtures/scenarios/vendor2" + + err := os.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath) + assert.NoError(t, err, "Setting 'ATMOS_CLI_CONFIG_PATH' environment variable should execute without error") + + err = os.Setenv("ATMOS_BASE_PATH", stacksPath) + assert.NoError(t, err, "Setting 'ATMOS_BASE_PATH' environment variable should execute without error") + + cmd := &cobra.Command{ + Use: "pull", + Short: "Pull the latest vendor configurations or dependencies", + Long: "Pull and update vendor-specific configurations or dependencies to ensure the project has the latest required resources.", + FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false}, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + err := ExecuteVendorPullCmd(cmd, args) + if err != nil { + return err + } + return nil + }, + } + + cmd.DisableFlagParsing = false + cmd.PersistentFlags().StringP("component", "c", "", "Only vendor the specified component") + cmd.PersistentFlags().StringP("stack", "s", "", "Only vendor the specified stack") + cmd.PersistentFlags().StringP("type", "t", "terraform", "The type of the vendor (terraform or helmfile).") + cmd.PersistentFlags().Bool("dry-run", false, "Simulate pulling the latest version of the specified component from the remote repository without making any changes.") + cmd.PersistentFlags().String("tags", "", "Only vendor the components that have the specified tags") + cmd.PersistentFlags().Bool("everything", false, "Vendor all components") + + // Execute the command + err = cmd.RunE(cmd, []string{}) + assert.NoError(t, err, "'atmos vendor pull' command should execute without error") +} + +func TestReadAndProcessVendorConfigFile(t *testing.T) { + basePath := "../../tests/fixtures/scenarios/vendor2" + vendorConfigFile := "vendor.yaml" + + atmosConfig := schema.AtmosConfiguration{ + BasePath: basePath, + } + + _, _, _, err := ReadAndProcessVendorConfigFile(atmosConfig, vendorConfigFile, false) + assert.NoError(t, err, "'TestReadAndProcessVendorConfigFile' should execute without error") +} diff --git a/internal/exec/workflow.go b/internal/exec/workflow.go index 23e4d16655..b91554a849 100644 --- a/internal/exec/workflow.go +++ b/internal/exec/workflow.go @@ -123,9 +123,9 @@ func ExecuteWorkflowCmd(cmd *cobra.Command, args []string) error { validWorkflows = append(validWorkflows, fmt.Sprintf("\n- %s", w)) } // sorting so that the output is deterministic - sort.Sort(sort.StringSlice(validWorkflows)) + sort.Strings(validWorkflows) errorMarkdown += strings.Join(validWorkflows, "") - return fmt.Errorf(errorMarkdown) + return fmt.Errorf("%s", errorMarkdown) } else { workflowDefinition = i } diff --git a/internal/exec/workflow_test.go b/internal/exec/workflow_test.go new file mode 100644 index 0000000000..6089af05c7 --- /dev/null +++ b/internal/exec/workflow_test.go @@ -0,0 +1,145 @@ +package exec + +import ( + "bytes" + "io" + "os" + "testing" + + u "github.com/cloudposse/atmos/pkg/utils" + "github.com/spf13/cobra" + + "github.com/stretchr/testify/assert" + + cfg "github.com/cloudposse/atmos/pkg/config" + "github.com/cloudposse/atmos/pkg/schema" +) + +func TestExecuteWorkflowCmd(t *testing.T) { + stacksPath := "../../tests/fixtures/scenarios/atmos-overrides-section" + + err := os.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath) + assert.NoError(t, err, "Setting 'ATMOS_CLI_CONFIG_PATH' environment variable should execute without error") + + err = os.Setenv("ATMOS_BASE_PATH", stacksPath) + assert.NoError(t, err, "Setting 'ATMOS_BASE_PATH' environment variable should execute without error") + + // Capture stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + expectedOutput := `atmos describe component c1 -s prod +atmos describe component c1 -s staging +atmos describe component c1 -s dev +atmos describe component c1 -s sandbox +atmos describe component c1 -s test +` + + cmd := &cobra.Command{ + Use: "workflow", + Short: "Run predefined tasks using workflows", + Long: `Run predefined workflows as an alternative to traditional task runners. Workflows enable you to automate and manage infrastructure and operational tasks specified in configuration files.`, + + FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false}, + Run: func(cmd *cobra.Command, args []string) { + err := ExecuteWorkflowCmd(cmd, args) + if err != nil { + u.PrintErrorMarkdownAndExit("", err, "") + } + }, + } + + cmd.DisableFlagParsing = false + cmd.PersistentFlags().StringP("file", "f", "", "Specify the workflow file to run") + cmd.PersistentFlags().Bool("dry-run", false, "Simulate the workflow without making any changes") + cmd.PersistentFlags().String("from-step", "", "Resume the workflow from the specified step") + cmd.PersistentFlags().String("stack", "", "Execute the workflow for the specified stack") + + // Execute the command + cmd.SetArgs([]string{"--file", "workflows", "show-all-describe-component-commands"}) + err = cmd.Execute() + assert.NoError(t, err, "'atmos workflow' command should execute without error") + + // Close the writer and restore stdout + err = w.Close() + assert.NoError(t, err, "'atmos workflow' command should execute without error") + + os.Stdout = oldStdout + + // Read captured output + var output bytes.Buffer + _, err = io.Copy(&output, r) + assert.NoError(t, err, "'atmos workflow' command should execute without error") + + // Check if output contains expected markdown content + assert.Contains(t, output.String(), expectedOutput, "'atmos workflow' output should contain information about workflows") +} + +func TestExecuteWorkflow(t *testing.T) { + stacksPath := "../tests/fixtures/scenarios/atmos-overrides-section" + workflowPath := "../tests/fixtures/scenarios/atmos-overrides-section/stacks/workflows/workflows.yaml" + + err := os.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath) + assert.NoError(t, err, "Setting 'ATMOS_CLI_CONFIG_PATH' environment variable should execute without error") + + err = os.Setenv("ATMOS_BASE_PATH", stacksPath) + assert.NoError(t, err, "Setting 'ATMOS_BASE_PATH' environment variable should execute without error") + + // Capture stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + expectedOutput := `atmos describe component c1 -s prod +atmos describe component c1 -s staging +atmos describe component c1 -s dev +atmos describe component c1 -s sandbox +atmos describe component c1 -s test +` + + atmosConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, false) + assert.NoError(t, err, "'InitCliConfig' should execute without error") + + workflowDefinition := schema.WorkflowDefinition{ + Steps: []schema.WorkflowStep{ + { + Type: "shell", + Command: "echo atmos describe component c1 -s prod", + }, + { + Type: "shell", + Command: "echo atmos describe component c1 -s staging", + }, + { + Type: "shell", + Command: "echo atmos describe component c1 -s dev", + }, + { + Type: "shell", + Command: "echo atmos describe component c1 -s sandbox", + }, + { + Type: "shell", + Command: "echo atmos describe component c1 -s test", + }, + }, + } + + err = ExecuteWorkflow(atmosConfig, "show-all-describe-component-commands", workflowPath, &workflowDefinition, false, "", "") + assert.NoError(t, err, "'ExecuteWorkflow' should execute without error") + + // Close the writer and restore stdout + err = w.Close() + assert.NoError(t, err, "'ExecuteWorkflow' command should execute without error") + + os.Stdout = oldStdout + + // Read captured output + var output bytes.Buffer + _, err = io.Copy(&output, r) + assert.NoError(t, err, "'ExecuteWorkflow' should execute without error") + + // Check if output contains expected markdown content + assert.Contains(t, output.String(), expectedOutput, "'ExecuteWorkflow' output should contain information workflows") +} diff --git a/pkg/stack/stack_processor.go b/pkg/stack/stack_processor.go index fb836beb75..80bf2db4bd 100644 --- a/pkg/stack/stack_processor.go +++ b/pkg/stack/stack_processor.go @@ -44,8 +44,10 @@ func ProcessYAMLConfigFile( skipTemplatesProcessingInImports bool, ignoreMissingTemplateValues bool, skipIfMissing bool, - parentTerraformOverrides map[string]any, - parentHelmfileOverrides map[string]any, + parentTerraformOverridesInline map[string]any, + parentTerraformOverridesImports map[string]any, + parentHelmfileOverridesInline map[string]any, + parentHelmfileOverridesImports map[string]any, atmosManifestJsonSchemaFilePath string, ) ( map[string]any, @@ -53,6 +55,8 @@ func ProcessYAMLConfigFile( map[string]any, map[string]any, map[string]any, + map[string]any, + map[string]any, error, ) { return exec.ProcessYAMLConfigFile( @@ -65,8 +69,10 @@ func ProcessYAMLConfigFile( skipTemplatesProcessingInImports, ignoreMissingTemplateValues, skipIfMissing, - parentTerraformOverrides, - parentHelmfileOverrides, + parentTerraformOverridesInline, + parentTerraformOverridesImports, + parentHelmfileOverridesInline, + parentHelmfileOverridesImports, atmosManifestJsonSchemaFilePath, ) } diff --git a/pkg/stack/stack_processor_test.go b/pkg/stack/stack_processor_test.go index 672c1c1b07..9eb7d29fe3 100644 --- a/pkg/stack/stack_processor_test.go +++ b/pkg/stack/stack_processor_test.go @@ -1,6 +1,7 @@ package stack import ( + "sort" "testing" "github.com/stretchr/testify/assert" @@ -245,3 +246,50 @@ func TestStackProcessorRelativePaths(t *testing.T) { myappComponent := terraformComponents["myapp"].(map[string]any) assert.NotNil(t, myappComponent) } + +func TestProcessYAMLConfigFile(t *testing.T) { + stacksBasePath := "../../tests/fixtures/scenarios/relative-paths/stacks" + filePath := "../../tests/fixtures/scenarios/relative-paths/stacks/orgs/acme/platform/dev.yaml" + + atmosConfig := schema.AtmosConfiguration{ + Templates: schema.Templates{ + Settings: schema.TemplatesSettings{ + Enabled: true, + Sprig: schema.TemplatesSettingsSprig{ + Enabled: true, + }, + Gomplate: schema.TemplatesSettingsGomplate{ + Enabled: true, + }, + }, + }, + } + + _, _, stackConfigMap, _, _, _, _, err := ProcessYAMLConfigFile( + atmosConfig, + stacksBasePath, + filePath, + map[string]map[string]any{}, + nil, + false, + false, + true, + false, + nil, + nil, + nil, + nil, + "", + ) + + assert.Nil(t, err) + assert.Equal(t, 3, len(stackConfigMap)) + + mapResultKeys := u.StringKeysFromMap(stackConfigMap) + // sorting so that the output is deterministic + sort.Strings(mapResultKeys) + + assert.Equal(t, "components", mapResultKeys[0]) + assert.Equal(t, "import", mapResultKeys[1]) + assert.Equal(t, "vars", mapResultKeys[2]) +} diff --git a/pkg/utils/markdown_utils.go b/pkg/utils/markdown_utils.go index ee0ecae1e5..0e371a9dd3 100644 --- a/pkg/utils/markdown_utils.go +++ b/pkg/utils/markdown_utils.go @@ -9,17 +9,18 @@ import ( "os/exec" "runtime/debug" - "github.com/cloudposse/atmos/pkg/schema" - "github.com/cloudposse/atmos/pkg/ui/markdown" + log "github.com/charmbracelet/log" "golang.org/x/text/cases" "golang.org/x/text/language" - l "github.com/charmbracelet/log" + "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/markdown" ) -// render is the global markdown renderer instance initialized via InitializeMarkdown +// render is the global markdown renderer instance initialized via InitializeMarkdown. var render *markdown.Renderer +// PrintErrorMarkdown prints an error message in Markdown format. func PrintErrorMarkdown(title string, err error, suggestion string) { if err == nil { return @@ -43,12 +44,12 @@ func PrintErrorMarkdown(title string, err error, suggestion string) { LogError(err) } // Print stack trace - if l.GetLevel() == l.DebugLevel { + if log.GetLevel() == log.DebugLevel { debug.PrintStack() } } -// PrintfErrorMarkdown prints a formatted error message in markdown format +// PrintfErrorMarkdown prints a formatted error message in Markdown format. func PrintfErrorMarkdown(format string, a ...interface{}) { if render == nil { LogError(fmt.Errorf(format, a...)) @@ -66,6 +67,7 @@ func PrintfErrorMarkdown(format string, a ...interface{}) { LogError(err) } +// PrintErrorMarkdownAndExit prints an error message in Markdown format and exist with the exit code 1. func PrintErrorMarkdownAndExit(title string, err error, suggestion string) { PrintErrorMarkdown(title, err, suggestion) @@ -75,13 +77,18 @@ func PrintErrorMarkdownAndExit(title string, err error, suggestion string) { os.Exit(exitError.ExitCode()) } + // TODO: Refactor so that we only call `os.Exit` in `main()` or `init()` functions. + // Exiting here makes it difficult to test. + // revive:disable-next-line:deep-exit os.Exit(1) } +// PrintInvalidUsageErrorAndExit prints a message about the incorrect command usage and exist with the exit code 1. func PrintInvalidUsageErrorAndExit(err error, suggestion string) { PrintErrorMarkdownAndExit("Incorrect Usage", err, suggestion) } +// PrintfMarkdown prints a message in Markdown format. func PrintfMarkdown(format string, a ...interface{}) { if render == nil { _, err := os.Stdout.WriteString(fmt.Sprintf(format, a...)) @@ -99,6 +106,7 @@ func PrintfMarkdown(format string, a ...interface{}) { LogError(err) } +// InitializeMarkdown initializes a new Markdown renderer. func InitializeMarkdown(atmosConfig schema.AtmosConfiguration) { var err error render, err = markdown.NewTerminalMarkdownRenderer(atmosConfig) diff --git a/pkg/utils/markdown_utils_test.go b/pkg/utils/markdown_utils_test.go new file mode 100644 index 0000000000..6c7204e2af --- /dev/null +++ b/pkg/utils/markdown_utils_test.go @@ -0,0 +1,135 @@ +package utils + +import ( + "bytes" + "errors" + "io" + "os" + "os/exec" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/markdown" +) + +func TestPrintErrorMarkdown(t *testing.T) { + render, _ = markdown.NewTerminalMarkdownRenderer(schema.AtmosConfiguration{}) + title := "Test Error" + err := errors.New("this is a test error") + suggestion := "Try checking your configuration." + + // Redirect stderr + oldStderr := os.Stderr + r, w, _ := os.Pipe() + os.Stderr = w + + PrintErrorMarkdown(title, err, suggestion) + + // Restore stderr + err = w.Close() + assert.Nil(t, err) + + os.Stderr = oldStderr + + var output bytes.Buffer + _, err = io.Copy(&output, r) + assert.NoError(t, err, "'TestPrintErrorMarkdown' should execute without error") + + // Check if output contains the expected content + expectedOutput := "Test Error" + assert.Contains(t, output.String(), expectedOutput, "'TestPrintErrorMarkdown' output should contain information about the error") +} + +func TestPrintfErrorMarkdown(t *testing.T) { + render, _ = markdown.NewTerminalMarkdownRenderer(schema.AtmosConfiguration{}) + + // Redirect stderr + oldStderr := os.Stderr + r, w, _ := os.Pipe() + os.Stderr = w + + PrintfErrorMarkdown("An error occurred: %s", "something went wrong") + + // Restore stderr + err := w.Close() + assert.Nil(t, err) + + os.Stderr = oldStderr + + // Read captured output + var output bytes.Buffer + _, err = io.Copy(&output, r) + assert.NoError(t, err, "'TestPrintfErrorMarkdown' should execute without error") + + // Check if output contains the expected content + expectedOutput := "An error occurred" + assert.Contains(t, output.String(), expectedOutput, "'TestPrintfErrorMarkdown' output should contain information about the error") +} + +func TestPrintErrorMarkdownAndExit(t *testing.T) { + if os.Getenv("TEST_EXIT") == "1" { + PrintErrorMarkdownAndExit("Fatal Error", errors.New("critical failure"), "Check logs.") + return + } + execPath, err := exec.LookPath(os.Args[0]) + assert.Nil(t, err) + cmd := exec.Command(execPath, "-test.run=TestPrintErrorMarkdownAndExit") + cmd.Env = append(os.Environ(), "TEST_EXIT=1") + err = cmd.Run() + var exitError *exec.ExitError + if errors.As(err, &exitError) { + assert.Equal(t, 1, exitError.ExitCode()) + } else { + assert.Fail(t, "Expected an exit error with code 1") + } +} + +func TestPrintInvalidUsageErrorAndExit(t *testing.T) { + if os.Getenv("TEST_EXIT") == "1" { + PrintInvalidUsageErrorAndExit(errors.New("invalid command"), "Use --help for usage information.") + return + } + execPath, err := exec.LookPath(os.Args[0]) + assert.Nil(t, err) + cmd := exec.Command(execPath, "-test.run=TestPrintErrorMarkdownAndExit") + cmd.Env = append(os.Environ(), "TEST_EXIT=1") + err = cmd.Run() + var exitError *exec.ExitError + if errors.As(err, &exitError) { + assert.Equal(t, 1, exitError.ExitCode()) + } else { + assert.Fail(t, "Expected an exit error with code 1") + } +} + +func TestPrintfMarkdown(t *testing.T) { + render, _ = markdown.NewTerminalMarkdownRenderer(schema.AtmosConfiguration{}) + + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + PrintfMarkdown("Atmos: %s", "Manage Environments Easily in Terraform") + + err := w.Close() + assert.Nil(t, err) + + os.Stdout = oldStdout + + // Read captured output + var output bytes.Buffer + _, err = io.Copy(&output, r) + assert.NoError(t, err, "'TestPrintfMarkdown' should execute without error") + + // Check if output contains the expected content + expectedOutput := "Atmos: Manage Environments Easily in Terraform" + assert.Contains(t, output.String(), expectedOutput, "'TestPrintfMarkdown' output should contain information about Atmos") +} + +func TestInitializeMarkdown(t *testing.T) { + atmosConfig := schema.AtmosConfiguration{} + InitializeMarkdown(atmosConfig) + assert.NotNil(t, render) +} diff --git a/tests/fixtures/scenarios/atmos-overrides-section/atmos.yaml b/tests/fixtures/scenarios/atmos-overrides-section/atmos.yaml new file mode 100644 index 0000000000..2081d8fee3 --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/atmos.yaml @@ -0,0 +1,24 @@ +base_path: "./" + +components: + terraform: + base_path: "../../components/terraform" + apply_auto_approve: false + deploy_run_init: true + init_run_reconfigure: true + auto_generate_backend_file: false + +stacks: + base_path: "stacks" + included_paths: + - "deploy/**/*" + excluded_paths: + - "**/_defaults.yaml" + name_pattern: "{stage}" + +logs: + file: "/dev/stderr" + level: Info + +workflows: + base_path: "stacks/workflows" diff --git a/tests/fixtures/scenarios/atmos-overrides-section/stacks/catalog/c1.yaml b/tests/fixtures/scenarios/atmos-overrides-section/stacks/catalog/c1.yaml new file mode 100644 index 0000000000..d71ce5d1be --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/stacks/catalog/c1.yaml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +components: + terraform: + c1: + vars: + test: + a: a + b: b + c: c + d: d diff --git a/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/dev.yaml b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/dev.yaml new file mode 100644 index 0000000000..7e8d4f27d2 --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/dev.yaml @@ -0,0 +1,14 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: dev + +import: + - teams/team1 + - teams/team2 + +terraform: + overrides: + vars: + test: + a: a-dev diff --git a/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/prod.yaml b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/prod.yaml new file mode 100644 index 0000000000..1c54d2ccbc --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/prod.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: prod + +import: + - teams/team1 + - teams/team2 + +overrides: {} + +terraform: + overrides: + vars: + test: + a: a-prod + b: b-prod + c: c-prod diff --git a/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/sandbox.yaml b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/sandbox.yaml new file mode 100644 index 0000000000..b827a7a46d --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/sandbox.yaml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: sandbox + +import: + - teams/team1 + - teams/team2 diff --git a/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/staging.yaml b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/staging.yaml new file mode 100644 index 0000000000..58f1b6c984 --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/staging.yaml @@ -0,0 +1,16 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: staging + +import: + - teams/team1 + - teams/team2 + +overrides: {} + +terraform: + overrides: + vars: + test: + a: a-staging diff --git a/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/test.yaml b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/test.yaml new file mode 100644 index 0000000000..ab2cb54c02 --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/stacks/deploy/test.yaml @@ -0,0 +1,19 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: test + +import: + - teams/team1 + +overrides: + vars: + test: + a: a-test + b: b-test + +terraform: + overrides: + vars: + test: + a: a-test-2 diff --git a/tests/fixtures/scenarios/atmos-overrides-section/stacks/teams/team1.yaml b/tests/fixtures/scenarios/atmos-overrides-section/stacks/teams/team1.yaml new file mode 100644 index 0000000000..4978e18efa --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/stacks/teams/team1.yaml @@ -0,0 +1,12 @@ +import: + - catalog/c1 + +overrides: {} + +terraform: + overrides: + vars: + test: + a: a-team1 + b: b-team1 + c: c-team1 diff --git a/tests/fixtures/scenarios/atmos-overrides-section/stacks/teams/team2.yaml b/tests/fixtures/scenarios/atmos-overrides-section/stacks/teams/team2.yaml new file mode 100644 index 0000000000..ed83cde38e --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/stacks/teams/team2.yaml @@ -0,0 +1,11 @@ +import: + - catalog/c1 + +overrides: {} + +terraform: + overrides: + vars: + test: + a: a-team2 + b: b-team2 diff --git a/tests/fixtures/scenarios/atmos-overrides-section/stacks/workflows/workflows.yaml b/tests/fixtures/scenarios/atmos-overrides-section/stacks/workflows/workflows.yaml new file mode 100644 index 0000000000..e75f69a293 --- /dev/null +++ b/tests/fixtures/scenarios/atmos-overrides-section/stacks/workflows/workflows.yaml @@ -0,0 +1,32 @@ +workflows: + describe-all: + description: Test 'atmos describe component' in a workflow + steps: + - command: describe component c1 -s prod + - command: describe component c1 -s staging + - command: describe component c1 -s dev + - command: describe component c1 -s sandbox + - command: describe component c1 -s test + + plan-all: + description: Test 'atmos terraform plan' in a workflow + steps: + - command: terraform plan c1 -s prod + - command: terraform plan c1 -s staging + - command: terraform plan c1 -s dev + - command: terraform plan c1 -s sandbox + - command: terraform plan c1 -s test + + show-all-describe-component-commands: + description: Show all `atmos describe component' commands in a workflow + steps: + - command: echo atmos describe component c1 -s prod + type: shell + - command: echo atmos describe component c1 -s staging + type: shell + - command: echo atmos describe component c1 -s dev + type: shell + - command: echo atmos describe component c1 -s sandbox + type: shell + - command: echo atmos describe component c1 -s test + type: shell diff --git a/tests/fixtures/scenarios/invalid-stacks/atmos.yaml b/tests/fixtures/scenarios/invalid-stacks/atmos.yaml new file mode 100644 index 0000000000..c846a63997 --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/atmos.yaml @@ -0,0 +1,21 @@ +base_path: "./" + +components: + terraform: + base_path: "components/terraform" + apply_auto_approve: false + deploy_run_init: true + init_run_reconfigure: true + auto_generate_backend_file: false + +stacks: + base_path: "stacks" + included_paths: + - "orgs/**/*" + excluded_paths: + - "**/_defaults.yaml" + name_pattern: "{namespace}-{tenant}-{stage}" + +logs: + file: "/dev/stderr" + level: Info diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/catalog/invalid-template.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/catalog/invalid-template.yaml new file mode 100644 index 0000000000..a85ca5aaed --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/stacks/catalog/invalid-template.yaml @@ -0,0 +1,5 @@ +components: + terraform: + myapp: + vars: + location: {{ .not-exist }} diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/_defaults.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/_defaults.yaml new file mode 100644 index 0000000000..ac81b4b36e --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/_defaults.yaml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + namespace: acme diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/dev.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/dev.yaml new file mode 100644 index 0000000000..a3cfe19970 --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/dev.yaml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: dev diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/empty.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/empty.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-global-overrides.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-global-overrides.yaml new file mode 100644 index 0000000000..08fc2a4ac4 --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-global-overrides.yaml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: invalid-global-overrides + +overrides: [] diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-helmfile-overrides.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-helmfile-overrides.yaml new file mode 100644 index 0000000000..2c3fd606c0 --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-helmfile-overrides.yaml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: invalid-helmfile-overrides + +helmfile: + overrides: [] diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-import-template.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-import-template.yaml new file mode 100644 index 0000000000..c4d123f7ec --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-import-template.yaml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: invalid-import-template + +import: + - path: catalog/invalid-template + context: + a: 1 diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-manifest-schema.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-manifest-schema.yaml new file mode 100644 index 0000000000..32a804315f --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-manifest-schema.yaml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: invalid-manifest-schema + +components: [] diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-terraform-overrides.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-terraform-overrides.yaml new file mode 100644 index 0000000000..a26bd34e04 --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid-terraform-overrides.yaml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: invalid-terraform-overrides + +terraform: + overrides: [] diff --git a/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid.yaml b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid.yaml new file mode 100644 index 0000000000..62617febc5 --- /dev/null +++ b/tests/fixtures/scenarios/invalid-stacks/stacks/orgs/acme/platform/invalid.yaml @@ -0,0 +1,4 @@ +vars: + stage: invalid + + {} diff --git a/tests/fixtures/scenarios/relative-paths/atmos.yaml b/tests/fixtures/scenarios/relative-paths/atmos.yaml index 5d6807473c..c846a63997 100644 --- a/tests/fixtures/scenarios/relative-paths/atmos.yaml +++ b/tests/fixtures/scenarios/relative-paths/atmos.yaml @@ -7,7 +7,7 @@ components: deploy_run_init: true init_run_reconfigure: true auto_generate_backend_file: false - + stacks: base_path: "stacks" included_paths: diff --git a/tests/fixtures/scenarios/vendor2/.gitignore b/tests/fixtures/scenarios/vendor2/.gitignore new file mode 100644 index 0000000000..68ffb32406 --- /dev/null +++ b/tests/fixtures/scenarios/vendor2/.gitignore @@ -0,0 +1 @@ +components/ diff --git a/tests/fixtures/scenarios/vendor2/atmos.yaml b/tests/fixtures/scenarios/vendor2/atmos.yaml new file mode 100644 index 0000000000..2081d8fee3 --- /dev/null +++ b/tests/fixtures/scenarios/vendor2/atmos.yaml @@ -0,0 +1,24 @@ +base_path: "./" + +components: + terraform: + base_path: "../../components/terraform" + apply_auto_approve: false + deploy_run_init: true + init_run_reconfigure: true + auto_generate_backend_file: false + +stacks: + base_path: "stacks" + included_paths: + - "deploy/**/*" + excluded_paths: + - "**/_defaults.yaml" + name_pattern: "{stage}" + +logs: + file: "/dev/stderr" + level: Info + +workflows: + base_path: "stacks/workflows" diff --git a/tests/fixtures/scenarios/vendor2/vendor.yaml b/tests/fixtures/scenarios/vendor2/vendor.yaml new file mode 100644 index 0000000000..f672ff5f84 --- /dev/null +++ b/tests/fixtures/scenarios/vendor2/vendor.yaml @@ -0,0 +1,21 @@ +apiVersion: atmos/v1 +kind: AtmosVendorConfig +metadata: + name: demo-vendoring + description: Atmos vendoring manifest for Atmos demo component library +spec: + # Import other vendor manifests, if necessary + imports: [] + + sources: + - component: "github/stargazers" + source: "github.com/cloudposse/atmos.git//examples/demo-library/{{ .Component }}?ref={{.Version}}" + version: "main" + targets: + - "components/terraform/{{ .Component }}/{{.Version}}" + included_paths: + - "**/*.tf" + - "**/*.tfvars" + - "**/*.md" + tags: + - demo diff --git a/tests/test-cases/atmos-overrides-section.yaml b/tests/test-cases/atmos-overrides-section.yaml new file mode 100644 index 0000000000..20ff150754 --- /dev/null +++ b/tests/test-cases/atmos-overrides-section.yaml @@ -0,0 +1,120 @@ +tests: + - name: "Atmos 'overrides' section test for 'prod' stack" + enabled: true + tty: false + snapshot: false + clean: true + description: "Ensure the 'overrides' section works inline and in imports" + workdir: "fixtures/scenarios/atmos-overrides-section/" + command: "atmos" + args: + - "describe" + - "component" + - "c1" + - "-s" + - "prod" + expect: + exit_code: 0 + stdout: + - "a: a-prod" + - "b: b-prod" + - "c: c-prod" + - "d: d" + stderr: + - "^$" + + - name: "Atmos 'overrides' section test for 'staging' stack" + enabled: true + tty: false + snapshot: false + clean: true + description: "Ensure the 'overrides' section works inline and in imports" + workdir: "fixtures/scenarios/atmos-overrides-section/" + command: "atmos" + args: + - "describe" + - "component" + - "c1" + - "-s" + - "staging" + expect: + exit_code: 0 + stdout: + - "a: a-staging" + - "b: b-team2" + - "c: c-team1" + - "d: d" + stderr: + - "^$" + + - name: "Atmos 'overrides' section test for 'dev' stack" + enabled: true + tty: false + snapshot: false + clean: true + description: "Ensure the 'overrides' section works inline and in imports" + workdir: "fixtures/scenarios/atmos-overrides-section/" + command: "atmos" + args: + - "describe" + - "component" + - "c1" + - "-s" + - "dev" + expect: + exit_code: 0 + stdout: + - "a: a-dev" + - "b: b-team2" + - "c: c-team1" + - "d: d" + stderr: + - "^$" + + - name: "Atmos 'overrides' section test for 'sandbox' stack" + enabled: true + tty: false + snapshot: false + clean: true + description: "Ensure the 'overrides' section works inline and in imports" + workdir: "fixtures/scenarios/atmos-overrides-section/" + command: "atmos" + args: + - "describe" + - "component" + - "c1" + - "-s" + - "sandbox" + expect: + exit_code: 0 + stdout: + - "a: a-team2" + - "b: b-team2" + - "c: c-team1" + - "d: d" + stderr: + - "^$" + + - name: "Atmos 'overrides' section test for 'test' stack" + enabled: true + tty: false + snapshot: false + clean: true + description: "Ensure the 'overrides' section works inline and in imports" + workdir: "fixtures/scenarios/atmos-overrides-section/" + command: "atmos" + args: + - "describe" + - "component" + - "c1" + - "-s" + - "test" + expect: + exit_code: 0 + stdout: + - "a: a-test-2" + - "b: b-test" + - "c: c-team1" + - "d: d" + stderr: + - "^$" diff --git a/website/docs/core-concepts/share-data/remote-state.mdx b/website/docs/core-concepts/share-data/remote-state.mdx index fa41ff132e..40f4037898 100644 --- a/website/docs/core-concepts/share-data/remote-state.mdx +++ b/website/docs/core-concepts/share-data/remote-state.mdx @@ -353,13 +353,13 @@ For this to work for both the `atmos` CLI and the Terraform provider, we recomme Atmos supports alternative ways to read the outputs (remote state) of components directly in Atmos stack manifests by -using the [`atmos.Component`](/core-concepts/stacks/templates/functions/atmos.Component) Go template function and -the [`!terraform.output`](/core-concepts/stacks/yaml-functions/terraform.output) Atmos YAML function instead of using +using the [`!terraform.output`](/core-concepts/stacks/yaml-functions/terraform.output) Atmos YAML function +and the [`atmos.Component`](/core-concepts/stacks/templates/functions/atmos.Component) Go template function instead of using the [`remote-state`](https://github.com/cloudposse/terraform-yaml-stack-config/tree/main/modules/remote-state) module and configuring Terraform/OpenTofu components to use the module. -Learn how to use 'atmos.Component' template function - Learn how to use '!terraform.output' YAML function +Learn how to use 'atmos.Component' template function + diff --git a/website/docs/core-concepts/share-data/share-data.mdx b/website/docs/core-concepts/share-data/share-data.mdx index cabf6edfbf..a71cbf253d 100644 --- a/website/docs/core-concepts/share-data/share-data.mdx +++ b/website/docs/core-concepts/share-data/share-data.mdx @@ -60,10 +60,41 @@ components: ``` -For more advanced examples, check out the `!store` yaml function documentation. +For more advanced examples, check out the `!store` YAML function documentation. Learn More +### Function: `!terraform.output` + +The `!terraform.output` YAML function allows reading the outputs ([remote state](/core-concepts/share-data/remote-state)) +of components directly in Atmos stack manifests. + +For example, we can read the `vpc_id` output of the `vpc` component in the current stack: + +```yaml +components: + terraform: + cluster: + vars: + vpc_id: !terraform.output vpc vpc_id +``` + +To access the configuration of a component in a different stack, you can specify the stack name as the second argument. +For example, here we're reading the `vpc_id` output of the `vpc` component in the `prod` stack: + +```yaml +components: + terraform: + cluster: + vars: + vpc_id: !terraform.output vpc prod vpc_id +``` + + +For more advanced examples, check out the `!terraform.output` YAML function documentation. +Learn More + + ## Using Template Functions ### Function: `atmos.Component` diff --git a/website/docs/integrations/atlantis.mdx b/website/docs/integrations/atlantis.mdx index 7e63335eff..953e7bf45f 100644 --- a/website/docs/integrations/atlantis.mdx +++ b/website/docs/integrations/atlantis.mdx @@ -673,7 +673,7 @@ on: branches: [ main ] env: - ATMOS_VERSION: 1.164.0 + ATMOS_VERSION: 1.165.3 ATMOS_CLI_CONFIG_PATH: ./ jobs: