Skip to content

Commit

Permalink
feat: forward parent lifecycles to child stages defined on the module
Browse files Browse the repository at this point in the history
In scenarios where lifecycles are defined on the module level, there was an issue preventing the same
lifecycle phases from being applied to the child modules. This was very inconvenient when
reusing multiple modules and the caller may have custom lifecycle phases, but the module's
are not owned by the caller to make changes
  • Loading branch information
srevinsaju committed Mar 14, 2024
1 parent aa2632a commit c7c535e
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 10 deletions.
2 changes: 2 additions & 0 deletions internal/behavior/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ type Child struct {
// Parent is the flag to indicate whether the program is running in parent mode
Parent string

ParentLifecycles []string

// ParentParams is the list of parameters to be passed to the parent
ParentParams []string
}
Expand Down
24 changes: 19 additions & 5 deletions internal/ci/module_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,28 @@ func (m *Module) run(conductor *Conductor, source string, evalCtx *hcl.EvalConte
})
}

var parentLifecycles []string
if cfg.Behavior.Child.ParentLifecycles != nil {
parentLifecycles = cfg.Behavior.Child.ParentLifecycles
}
if m.Lifecycle != nil {
conductor.Eval().Mutex().RLock()
lifecyclePhases, d := m.Lifecycle.Phase.Value(evalCtx)
conductor.Eval().Mutex().RUnlock()
diags = diags.Extend(d)
for _, phase := range lifecyclePhases.AsValueSlice() {
parentLifecycles = append(parentLifecycles, phase.AsString())
}
}

b := &behavior.Behavior{
Unattended: conductor.Config.Behavior.Unattended,
Ci: conductor.Config.Behavior.Ci,
Child: behavior.Child{
Enabled: true,
Parent: "",
ParentParams: nil,
Enabled: true,
Parent: "",
ParentParams: nil,
ParentLifecycles: parentLifecycles,
},
DryRun: false,
}
Expand All @@ -194,8 +209,7 @@ func (m *Module) run(conductor *Conductor, source string, evalCtx *hcl.EvalConte
conductorOptions = append(conductorOptions, ConductorWithParser(conductor.Parser))

// populate input variables for the child conductor, which would be passed to the module
attrs, d := m.Body.JustAttributes()
diags = diags.Extend(d)
attrs, _ := m.Body.JustAttributes()
for _, attr := range attrs {
//we need to evaluate the values first within the parent's evaluation context
//before sending it to the child goroutine and child conductor
Expand Down
14 changes: 10 additions & 4 deletions internal/ci/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,16 @@ func BlockCanRun(runnable Block, conductor *Conductor, runnableId string, depGra
ok = false
overridden = false

// if the list is empty, we will assume that the runnable is not overridden
// if the list is empty, we will assume that the runnable is not overridden,
// and we will run all module blocks. This is so that the child processoe
var phases []cty.Value
var phasesDefined bool

// if the parent config has lifecycles defined, we will append it to the child
for _, phase := range conductor.Config.Behavior.Child.ParentLifecycles {
phases = append(phases, cty.StringVal(phase))
}

var phasesDefined bool = len(phases) > 0
stage := runnable.(PhasedBlock)
if stage.LifecycleConfig() != nil {
evalContext := conductor.Eval().Context()
Expand All @@ -126,8 +132,8 @@ func BlockCanRun(runnable Block, conductor *Conductor, runnableId string, depGra
diags = diags.Extend(d)
return false, false, diags
}
phasesDefined = !phaseHcl.IsNull()
phases = phaseHcl.AsValueSlice()
phasesDefined = !phaseHcl.IsNull() || len(phases) > 0
phases = append(phases, phaseHcl.AsValueSlice()...)
}

if runnable.Type() == blocks.ModuleBlock && len(phases) == 0 && !phasesDefined {
Expand Down
32 changes: 31 additions & 1 deletion tests/togomak.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,36 @@ stage "tests" {
}
}

stage "module_phase_test" {
pre_hook {
stage {
script = "echo ${ansi.fg.green}${each.key}${ansi.reset}: full"
}
}

for_each = toset([
"../examples/module-phases-inheritance/togomak.hcl",
])

depends_on = [stage.build, stage.coverage_prepare]
args = [
"./togomak_coverage",
"-C", dirname(each.key),
"--ci", "-v", "-v", "-v",
"add"
]

env {
name = "GOCOVERDIR"
value = local.coverage_data_dir
}
env {
name = "TOGOMAK_VAR_name"
value = "bot"
}

}


stage "tests_dry_run" {
pre_hook {
Expand Down Expand Up @@ -82,7 +112,7 @@ stage "fmt" {
}

stage "cache" {
depends_on = [stage.fmt, stage.tests, stage.tests_dry_run]
depends_on = [stage.fmt, stage.tests, stage.tests_dry_run, stage.module_phase_test]
script = "./togomak_coverage cache clean --recursive"
}

Expand Down

0 comments on commit c7c535e

Please sign in to comment.