in workflow.go [78:117]
func (w *Workflow) addStep(step Steper, config *StepConfig) {
if step == nil {
return
}
w.BuildStep(step)
if !HasStep(w, step) {
// the step is new, it becomes a new root.
// add the new root to the Workflow.
// if the step embeds a previous root step,
// we need to replace them with the new root.
// workflow will only orchestrate the root Steps,
// and leave the nested Steps being managed by the root Steps.
var oldRoots Set[Steper]
Traverse(step, func(s Steper, walked []Steper) TraverseDecision {
if r := w.RootOf(s); r != nil {
if r != s { // s has another root
panic(fmt.Errorf("add step %p(%s) failed, another step %p(%s) already has %p(%s)",
step, step, r, r, s, s))
}
oldRoots.Add(r)
return TraverseEndBranch
}
return TraverseContinue
})
state := new(State)
for old := range oldRoots {
state.MergeConfig(w.steps[old].Config)
delete(w.steps, old)
}
w.steps[step] = state
}
if config != nil {
for up := range config.Upstreams {
w.setUpstream(step, up)
}
config.Upstreams = nil
// merge config to the state in the lowest workflow
w.StateOf(step).MergeConfig(config)
}
}