Skip to content

Commit

Permalink
fix: after/before selecting stacks outside cwd/-C (#292)
Browse files Browse the repository at this point in the history
  • Loading branch information
katcipis committed Apr 6, 2022
1 parent a1329d2 commit 91ae5ce
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 33 deletions.
6 changes: 3 additions & 3 deletions cmd/terramate/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ func (c *cli) printRunOrder() {
}

logger.Debug().Msg("Get run order.")
order, reason, err := run.Sort(c.root(), stacks, c.parsedArgs.Changed)
orderedStacks, reason, err := run.Sort(c.root(), stacks)
if err != nil {
if errors.Is(err, dag.ErrCycleDetected) {
log.Fatal().
Expand All @@ -685,7 +685,7 @@ func (c *cli) printRunOrder() {
}
}

for _, s := range order {
for _, s := range orderedStacks {
c.log(s.Name())
}
}
Expand Down Expand Up @@ -828,7 +828,7 @@ func (c *cli) runOnStacks() {

logger.Trace().Msg("Get order of stacks to run command on.")

orderedStacks, reason, err := run.Sort(c.root(), stacks, c.parsedArgs.Changed)
orderedStacks, reason, err := run.Sort(c.root(), stacks)
if err != nil {
if errors.Is(err, dag.ErrCycleDetected) {
logger.Fatal().
Expand Down
72 changes: 65 additions & 7 deletions cmd/terramate/e2etests/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ import (

func TestCLIRunOrder(t *testing.T) {
type testcase struct {
name string
layout []string
want runExpected
name string
layout []string
workingDir string
want runExpected
}

for _, tc := range []testcase{
Expand Down Expand Up @@ -432,6 +433,20 @@ stack-c
stack-a
stack-d
stack-z
`,
},
},
{
name: `run order selects only stacks inside working dir`,
layout: []string{
`s:stacks/stack-a:after=["/stacks/stack-b", "/parent-stack"]`,
`s:stacks/stack-b:before=["/parent-stack"]`,
`s:parent-stack`,
},
workingDir: "stacks",
want: runExpected{
Stdout: `stack-b
stack-a
`,
},
},
Expand All @@ -440,7 +455,12 @@ stack-z
s := sandbox.New(t)
s.BuildTree(tc.layout)

cli := newCLI(t, s.RootDir())
wd := s.RootDir()
if tc.workingDir != "" {
wd = filepath.Join(wd, tc.workingDir)
}

cli := newCLI(t, wd)
assertRunResult(t, cli.stacksRunOrder(), tc.want)
})
}
Expand Down Expand Up @@ -638,7 +658,6 @@ func TestRunOrderNotChangedStackIgnored(t *testing.T) {
// stack must run after stack2 but stack2 didn't change.

stack2 := s.CreateStack("stack2")

stack := s.CreateStack("stack")
stackMainTf := stack.CreateFile(mainTfFileName, "# some code")
stackConfig, err := hcl.NewConfig(stack.Path())
Expand Down Expand Up @@ -671,8 +690,6 @@ func TestRunOrderNotChangedStackIgnored(t *testing.T) {
mainTfFileName,
), runExpected{Stdout: wantRun})

wantRun = mainTfContents

cli = newCLI(t, stack.Path())
assertRunResult(t, cli.run(
"run",
Expand All @@ -690,6 +707,47 @@ func TestRunOrderNotChangedStackIgnored(t *testing.T) {
), runExpected{})
}

func TestRunIgnoresAfterBeforeStackRefsOutsideWorkingDir(t *testing.T) {
const testfile = "testfile"

s := sandbox.New(t)

s.BuildTree([]string{
"s:parent-stack",
`s:stacks/stack-1:before=["/parent-stack"]`,
`s:stacks/stack-2:after=["/parent-stack"]`,
fmt.Sprintf("f:parent-stack/%s:parent-stack\n", testfile),
fmt.Sprintf("f:stacks/stack-1/%s:stack-1\n", testfile),
fmt.Sprintf("f:stacks/stack-2/%s:stack-2\n", testfile),
})

git := s.Git()
git.CommitAll("first commit")

cat := test.LookPath(t, "cat")
assertRun := func(wd string, want string) {
cli := newCLI(t, filepath.Join(s.RootDir(), wd))

assertRunResult(t, cli.run(
"run",
cat,
testfile,
), runExpected{Stdout: want})

assertRunResult(t, cli.run(
"run",
"--changed",
cat,
testfile,
), runExpected{Stdout: want})
}

assertRun(".", "stack-1\nparent-stack\nstack-2\n")
assertRun("stacks", "stack-1\nstack-2\n")
assertRun("stacks/stack-1", "stack-1\n")
assertRun("stacks/stack-2", "stack-2\n")
}

func TestRunOrderAllChangedStacksExecuted(t *testing.T) {
const (
mainTfFileName = "main.tf"
Expand Down
57 changes: 34 additions & 23 deletions run/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,23 @@ type visited map[string]struct{}
// Sort computes the final execution order for the given list of stacks.
// In the case of multiple possible orders, it returns the lexicographic sorted
// path.
func Sort(root string, stacks []stack.S, changed bool) ([]stack.S, string, error) {
logger := log.With().
Str("action", "RunOrder()").
Str("path", root).
Logger()

logger.Debug().
Msg("Create new directed acyclic graph.")
func Sort(root string, stacks []stack.S) ([]stack.S, string, error) {
d := dag.New()

logger.Trace().
Msg("Create new stack loader.")
loader := stack.NewLoader(root)

logger.Trace().
Msg("Add stacks to loader.")
for _, stack := range stacks {
loader.Set(stack.PrjAbsPath(), stack)
}

visited := visited{}

logger.Trace().
Msg("Range over stacks.")
logger := log.With().
Str("action", "run.Sort()").
Str("root", root).
Logger()

logger.Trace().Msg("Sorting stacks.")

for _, stack := range stacks {
if _, ok := visited[stack.PrjAbsPath()]; ok {
continue
Expand All @@ -65,30 +58,48 @@ func Sort(root string, stacks []stack.S, changed bool) ([]stack.S, string, error
}
}

logger.Trace().
Msg("Validate DAG.")
logger.Trace().Msg("Validate DAG.")

reason, err := d.Validate()
if err != nil {
return nil, reason, err
}

logger.Trace().
Msg("Get topologically order DAG.")
logger.Trace().Msg("Get topologically order DAG.")

order := d.Order()

orderedStacks := make([]stack.S, 0, len(order))

logger.Trace().
Msg("Get ordered stacks.")
logger.Trace().Msg("Get ordered stacks.")

isSelectedStack := func(s stack.S) bool {
// Stacks may be added on the DAG from after/before references
// but they should not be on the final order if they are not part
// of the previously selected stacks passed as a parameter.
// This is important for change detection to work on ordering and
// also for filtering by working dir.
for _, stack := range stacks {
if s.PrjAbsPath() == stack.PrjAbsPath() {
return true
}
}
return false
}

for _, id := range order {
val, err := d.Node(id)
if err != nil {
return nil, "", fmt.Errorf("calculating run-order: %w", err)
}
s := val.(stack.S)
if s.IsChanged() == changed {
orderedStacks = append(orderedStacks, s)
if !isSelectedStack(s) {
logger.Trace().
Str("stack", s.PrjAbsPath()).
Msg("ignoring since not part of selected stacks")
continue
}
orderedStacks = append(orderedStacks, s)
}

return orderedStacks, "", nil
Expand Down

0 comments on commit 91ae5ce

Please sign in to comment.