From 47ea93410c499a528eb47942e7f606c28fd1c4db Mon Sep 17 00:00:00 2001 From: Tiago Natel Date: Mon, 12 Feb 2024 13:22:07 +0000 Subject: [PATCH] fix!: incorrect filesystem implicit order due to reloading of objects. Signed-off-by: Tiago Natel --- CHANGELOG.md | 2 + cmd/terramate/e2etests/core/run_test.go | 51 +++++++++++++++++++++++++ config/config.go | 14 +++++++ config/stack.go | 17 ++++----- run/order.go | 4 +- 5 files changed, 76 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07912d328..9df41323a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ Given a version number `MAJOR.MINOR.PATCH`, we increment the: ### Fixed - Fix language server panic when root directory contain errors. +- (**BREAKING CHANGE**) Fix the execution order when using `tag:` filter in `after/before` in conjunction with implicit filesystem order. Please check the `terramate list --run-order` after +upgrading. ## 0.4.5 diff --git a/cmd/terramate/e2etests/core/run_test.go b/cmd/terramate/e2etests/core/run_test.go index 1e2217782..660868415 100644 --- a/cmd/terramate/e2etests/core/run_test.go +++ b/cmd/terramate/e2etests/core/run_test.go @@ -540,6 +540,57 @@ func TestCLIRunOrder(t *testing.T) { ), }, }, + { + name: "implicit order with tags - Zied case", + layout: []string{ + `s:project:tags=["project"];before=["tag:identity"]`, + `s:iac/cloud-storage/bucket:tags=["bucket"];after=["tag:project", "tag:service-account"]`, + `s:iac/service-accounts:tags=["identity"];before=["/iac/service-accounts/sa-name"]`, + `s:iac/service-accounts/sa-name:tags=["service-account"]`, + }, + want: RunExpected{ + Stdout: nljoin( + "/project", + "/iac/service-accounts", + "/iac/service-accounts/sa-name", + "/iac/cloud-storage/bucket", + ), + }, + }, + { + name: "before clause pulling a branch of fs ordered stacks", + layout: []string{ + `s:project:tags=["project"];before=["tag:parent"]`, + `s:dir/parent:tags=["parent"]`, + `s:dir/parent/child:tags=["child"]`, + `s:dir/other:tags=["other"];after=["tag:project", "tag:child"]`, + }, + want: RunExpected{ + Stdout: nljoin( + `/project`, + `/dir/parent`, + `/dir/parent/child`, + `/dir/other`, + ), + }, + }, + { + name: "stack pulled to the middle of fs ordering chain", + layout: []string{ + `s:parent`, + `s:parent/child:before=["tag:other"]`, + `s:parent/child/grand-child`, + `s:other:tags=["other"]`, + }, + want: RunExpected{ + Stdout: nljoin( + `/parent`, + `/parent/child`, + `/other`, + `/parent/child/grand-child`, + ), + }, + }, { name: "grand parent before parent before child (implicit)", layout: []string{ diff --git a/config/config.go b/config/config.go index eab590ff3..d12d6bff0 100644 --- a/config/config.go +++ b/config/config.go @@ -56,6 +56,8 @@ type Tree struct { // Parent is the parent node or nil if none. Parent *Tree + stack *Stack + dir string } @@ -308,6 +310,18 @@ func (tree *Tree) IsStack() bool { return tree.Node.Stack != nil } +// Stack returns the stack object. +func (tree *Tree) Stack() (*Stack, error) { + if tree.stack == nil { + s, err := LoadStack(tree.Root(), tree.Dir()) + if err != nil { + return nil, err + } + tree.stack = s + } + return tree.stack, nil +} + // Stacks returns the stack nodes from the tree. // The search algorithm is a Deep-First-Search (DFS). func (tree *Tree) Stacks() List[*Tree] { diff --git a/config/stack.go b/config/stack.go index 8cb70d09b..cd28e070c 100644 --- a/config/stack.go +++ b/config/stack.go @@ -279,12 +279,12 @@ func validateWatchPaths(rootdir string, stackpath string, paths []string) (proje } // StacksFromTrees converts a List[*Tree] into a List[*Stack]. -func StacksFromTrees(root string, trees List[*Tree]) (List[*SortableStack], error) { +func StacksFromTrees(trees List[*Tree]) (List[*SortableStack], error) { var stacks List[*SortableStack] for _, tree := range trees { - s, err := NewStackFromHCL(root, tree.Node) + s, err := tree.Stack() if err != nil { - return List[*SortableStack]{}, err + return nil, err } stacks = append(stacks, &SortableStack{s}) } @@ -302,9 +302,9 @@ func LoadAllStacks(cfg *Tree) (List[*SortableStack], error) { stacksIDs := map[string]*Stack{} for _, stackNode := range cfg.Stacks() { - stack, err := NewStackFromHCL(cfg.RootDir(), stackNode.Node) + stack, err := stackNode.Stack() if err != nil { - return List[*SortableStack]{}, err + return nil, err } logger := logger.With(). @@ -354,11 +354,8 @@ func TryLoadStack(root *Root, cfgdir project.Path) (stack *Stack, found bool, er return nil, false, nil } - s, err := NewStackFromHCL(root.HostDir(), tree.Node) - if err != nil { - return nil, true, err - } - return s, true, nil + s, err := tree.Stack() + return s, true, err } // ReverseStacks reverses the given stacks slice. diff --git a/run/order.go b/run/order.go index e06c8ba1c..2030119bc 100644 --- a/run/order.go +++ b/run/order.go @@ -195,12 +195,12 @@ func BuildDAG( return err } - ancestorStacks, err := config.StacksFromTrees(root.HostDir(), root.StacksByPaths(s.Dir, ancestorPaths...)) + ancestorStacks, err := config.StacksFromTrees(root.StacksByPaths(s.Dir, ancestorPaths...)) if err != nil { return errors.E(err, "stack %q: failed to load the \"%s\" stacks", s, ancestorsName) } - descendantStacks, err := config.StacksFromTrees(root.HostDir(), root.StacksByPaths(s.Dir, descendantPaths...)) + descendantStacks, err := config.StacksFromTrees(root.StacksByPaths(s.Dir, descendantPaths...)) if err != nil { return errors.E(err, "stack %q: failed to load the \"%s\" stacks", s, descendantsName)