Skip to content

Commit

Permalink
feat: add terramate.config.order_of_execution.nested attribute.
Browse files Browse the repository at this point in the history
Signed-off-by: i4k <t.nateldemoura@gmail.com>
  • Loading branch information
i4ki committed Dec 2, 2024
1 parent c84179c commit 56fbf84
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 24 deletions.
39 changes: 33 additions & 6 deletions e2etests/core/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ func TestCLIRunOrder(t *testing.T) {
t.Parallel()

type testcase struct {
name string
layout []string
filterTags []string
filterNoTags []string
workingDir string
want RunExpected
name string
layout []string
fsOrderingDisabled bool
filterTags []string
filterNoTags []string
workingDir string
want RunExpected
}

for _, tc := range []testcase{
Expand Down Expand Up @@ -542,6 +543,22 @@ func TestCLIRunOrder(t *testing.T) {
),
},
},
{
name: "stack-b after stack-a after parent (fs ordering disabled)",
layout: []string{
`s:parent/stack-b:after=["/parent/stack-a"]`,
`s:parent/stack-a`,
`s:parent:after=["/parent/stack-b"]`,
},
fsOrderingDisabled: true,
want: RunExpected{
Stdout: nljoin(
"/parent/stack-a",
"/parent/stack-b",
"/parent",
),
},
},
{
name: "implicit order with tags - Zied case",
layout: []string{
Expand Down Expand Up @@ -919,6 +936,16 @@ func TestCLIRunOrder(t *testing.T) {
t.Parallel()
copiedLayout := make([]string, len(tc.layout))
copy(copiedLayout, tc.layout)
if tc.fsOrderingDisabled {
copiedLayout = append(copiedLayout,
fmt.Sprintf("file:disable_fs_ordering:%s", Terramate(
Config(
Block("order_of_execution",
Bool("nested", false),
),
),
).String()))
}
if runtime.GOOS != "windows" {
copiedLayout = append(copiedLayout,

Expand Down
53 changes: 52 additions & 1 deletion hcl/hcl.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ type RunConfig struct {
Env *RunEnv
}

// OrderOfExecutionConfig represents the order_of_execution block.
type OrderOfExecutionConfig struct {
Nested *bool // If filesystem order is enabled.
}

// RunEnv represents Terramate run environment.
type RunEnv struct {
// Attributes is the collection of attribute definitions within the env block.
Expand Down Expand Up @@ -262,6 +267,7 @@ type RootConfig struct {
Generate *GenerateRootConfig
ChangeDetection *ChangeDetectionConfig
Run *RunConfig
OrderOfExecution *OrderOfExecutionConfig
Cloud *CloudConfig
Experiments []string
DisableSafeguards safeguard.Keywords
Expand Down Expand Up @@ -1759,7 +1765,16 @@ func (p *TerramateParser) parseRootConfig(cfg *RootConfig, block *ast.MergedBloc
}
}

errs.AppendWrap(ErrTerramateSchema, block.ValidateSubBlocks("git", "generate", "change_detection", "run", "cloud", "targets", "telemetry"))
errs.AppendWrap(ErrTerramateSchema, block.ValidateSubBlocks(
"git",
"generate",
"change_detection",
"run",
"order_of_execution",
"cloud",
"targets",
"telemetry",
))

gitBlock, ok := block.Blocks[ast.NewEmptyLabelBlockType("git")]
if ok {
Expand All @@ -1771,6 +1786,12 @@ func (p *TerramateParser) parseRootConfig(cfg *RootConfig, block *ast.MergedBloc
errs.Append(parseRunConfig(cfg, runBlock))
}

orderExecBlock, ok := block.Blocks[ast.NewEmptyLabelBlockType("order_of_execution")]
if ok {
cfg.OrderOfExecution = &OrderOfExecutionConfig{}
errs.Append(parseOrderOfExecutionConfig(cfg.OrderOfExecution, orderExecBlock))
}

cloudBlock, ok := block.Blocks[ast.NewEmptyLabelBlockType("cloud")]
if ok {
cfg.Cloud = &CloudConfig{}
Expand Down Expand Up @@ -1850,6 +1871,36 @@ func parseRunConfig(cfg *RootConfig, runBlock *ast.MergedBlock) error {
return errs.AsError()
}

func parseOrderOfExecutionConfig(cfg *OrderOfExecutionConfig, orderExecBlock *ast.MergedBlock) error {
errs := errors.L()
for _, attr := range orderExecBlock.Attributes {
value, err := attr.Expr.Value(nil)
if err != nil {
errs.Append(errors.E(err, "failed to evaluate terramate.config.order_of_execution.%s attribute", attr.Name))
continue
}

switch attr.Name {
case "nested":
if value.Type() != cty.Bool {
errs.Append(attrErr(attr,
"terramate.config.order_of_execution.nested is not a bool but %q",
value.Type().FriendlyName(),
))
continue
}
t := value.True()
cfg.Nested = &t
default:
errs.Append(errors.E(attr.NameRange,
"unrecognized attribute terramate.config.order_of_execution.%s",
attr.Name,
))
}
}
return errs.AsError()
}

func parseGenerateRootConfig(cfg *GenerateRootConfig, generateBlock *ast.MergedBlock) error {
errs := errors.L()

Expand Down
81 changes: 81 additions & 0 deletions hcl/hcl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
errtest "github.com/terramate-io/terramate/test/errors"
. "github.com/terramate-io/terramate/test/hclutils"
"github.com/terramate-io/terramate/test/hclutils/info"
. "github.com/terramate-io/terramate/test/hclwrite/hclutils"
)

type (
Expand All @@ -43,6 +44,8 @@ type (
)

func TestHCLParserTerramateBlock(t *testing.T) {
truth := true
falsy := false
for _, tc := range []testcase{
{
name: "unrecognized blocks",
Expand Down Expand Up @@ -594,6 +597,84 @@ func TestHCLParserTerramateBlock(t *testing.T) {
},
},
},
{
name: "terramate.config.order_of_execution.nested=false",
input: []cfgfile{
{
filename: "cfg.tm",
body: Terramate(
Config(
Block("order_of_execution",
Bool("nested", false),
),
),
).String(),
},
},
want: want{
config: hcl.Config{
Terramate: &hcl.Terramate{
Config: &hcl.RootConfig{
OrderOfExecution: &hcl.OrderOfExecutionConfig{
Nested: &falsy,
},
},
},
},
},
},
{
name: "empty terramate.config.order_of_execution block",
input: []cfgfile{
{
filename: "cfg.tm",
body: `
terramate {
config {
order_of_execution {
}
}
}
`,
},
},
want: want{
config: hcl.Config{
Terramate: &hcl.Terramate{
Config: &hcl.RootConfig{
OrderOfExecution: &hcl.OrderOfExecutionConfig{},
},
},
},
},
},
{
name: "terramate.config.order_of_execution.nested=true",
input: []cfgfile{
{
filename: "cfg.tm",
body: Terramate(
Config(
Block("order_of_execution",
Bool("nested", true),
),
),
).String(),
},
},
want: want{
config: hcl.Config{
Terramate: &hcl.Terramate{
Config: &hcl.RootConfig{
OrderOfExecution: &hcl.OrderOfExecutionConfig{
Nested: &truth,
},
},
},
},
},
},
} {
testParser(t, tc)
}
Expand Down
47 changes: 30 additions & 17 deletions run/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,28 +106,30 @@ func buildValidStackDAG[S ~[]E, E any](
Str("root", root.HostDir()).
Logger()

isParentStack := func(s1, s2 *config.Stack) bool {
return s1.Dir.HasPrefix(s2.Dir.String() + "/")
}
if isFsOrderingEnabled(root) {
isParentStack := func(s1, s2 *config.Stack) bool {
return s1.Dir.HasPrefix(s2.Dir.String() + "/")
}

getStackDir := func(s E) string {
return getStack(s).Dir.String()
}
getStackDir := func(s E) string {
return getStack(s).Dir.String()
}

slices.SortStableFunc(items, func(a, b E) int {
return strings.Compare(getStack(a).Dir.String(), getStack(b).Dir.String())
})
slices.SortStableFunc(items, func(a, b E) int {
return strings.Compare(getStack(a).Dir.String(), getStack(b).Dir.String())
})

for _, a := range items {
for _, b := range items {
if getStack(a).Dir == getStack(b).Dir {
continue
}
for _, a := range items {
for _, b := range items {
if getStack(a).Dir == getStack(b).Dir {
continue
}

if isParentStack(getStack(a), getStack(b)) {
logger.Debug().Msgf("stack %q runs before %q since it is its parent", getStackDir(a), getStackDir(b))
if isParentStack(getStack(a), getStack(b)) {
logger.Debug().Msgf("stack %q runs before %q since it is its parent", getStackDir(a), getStackDir(b))

getStack(b).AppendBefore(getStack(a).Dir.String())
getStack(b).AppendBefore(getStack(a).Dir.String())
}
}
}
}
Expand Down Expand Up @@ -298,3 +300,14 @@ func toids(values config.List[*config.SortableStack]) []dag.ID {
}
return ids
}

func isFsOrderingEnabled(root *config.Root) bool {
cfg := root.Tree().Node
if cfg.Terramate != nil &&
cfg.Terramate.Config != nil &&
cfg.Terramate.Config.OrderOfExecution != nil &&
cfg.Terramate.Config.OrderOfExecution.Nested != nil {
return *cfg.Terramate.Config.OrderOfExecution.Nested
}
return true
}

0 comments on commit 56fbf84

Please sign in to comment.