Skip to content

Commit

Permalink
fix pipeline.yaml step dependency validation
Browse files Browse the repository at this point in the history
Signed-off-by: Gerd Oberlechner <[email protected]>
  • Loading branch information
geoberle committed Dec 4, 2024
1 parent f5c62c3 commit 3759a16
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 18 deletions.
37 changes: 23 additions & 14 deletions tooling/templatize/pkg/pipeline/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,29 @@ func (s *Step) description() string {
}

func (p *Pipeline) Validate() error {
// collect all steps from all resourcegroups and fail if there are duplicates
stepMap := make(map[string]*Step)
for _, rg := range p.ResourceGroups {
for _, step := range rg.Steps {
if _, ok := stepMap[step.Name]; ok {
return fmt.Errorf("duplicate step name %q", step.Name)
}
stepMap[step.Name] = step
}
}

// validate dependsOn for a step exists
for _, step := range stepMap {
for _, dep := range step.DependsOn {
if _, ok := stepMap[dep]; !ok {
return fmt.Errorf("invalid dependency on step %s: dependency %s does not exist", step.Name, dep)
}
}
}

// todo check for circular dependencies

// validate resource groups
for _, rg := range p.ResourceGroups {
err := rg.Validate()
if err != nil {
Expand All @@ -178,19 +201,5 @@ func (rg *ResourceGroup) Validate() error {
if rg.Subscription == "" {
return fmt.Errorf("subscription is required")
}

// validate step dependencies
// todo - check for circular dependencies
stepMap := make(map[string]bool)
for _, step := range rg.Steps {
stepMap[step.Name] = true
}
for _, step := range rg.Steps {
for _, dep := range step.DependsOn {
if !stepMap[dep] {
return fmt.Errorf("invalid dependency from step %s to %s", step.Name, dep)
}
}
}
return nil
}
91 changes: 87 additions & 4 deletions tooling/templatize/pkg/pipeline/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,94 @@ func TestRGValidate(t *testing.T) {
}

func TestPipelineValidate(t *testing.T) {
p := &Pipeline{
ResourceGroups: []*ResourceGroup{{}},
testCases := []struct {
name string
pipeline *Pipeline
err string
}{
{
name: "missing name",
pipeline: &Pipeline{
ResourceGroups: []*ResourceGroup{{}},
},
err: "resource group name is required",
},
{
name: "missing subscription",
pipeline: &Pipeline{
ResourceGroups: []*ResourceGroup{
{
Name: "rg",
},
},
},
err: "subscription is required",
},
{
name: "missing step dependency",
pipeline: &Pipeline{
ResourceGroups: []*ResourceGroup{
{
Name: "rg1",
Subscription: "sub1",
Steps: []*Step{
{
Name: "step1",
},
},
},
{
Name: "rg2",
Subscription: "sub1",
Steps: []*Step{
{
Name: "step2",
DependsOn: []string{"step3"},
},
},
},
},
},
err: "invalid dependency on step step2: dependency step3 does not exist",
},
{
name: "valid step dependencies",
pipeline: &Pipeline{
ResourceGroups: []*ResourceGroup{
{
Name: "rg1",
Subscription: "sub1",
Steps: []*Step{
{
Name: "step1",
},
},
},
{
Name: "rg2",
Subscription: "sub1",
Steps: []*Step{
{
Name: "step2",
DependsOn: []string{"step1"},
},
},
},
},
},
err: "",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := tc.pipeline.Validate()
if tc.err == "" {
assert.NilError(t, err)
} else {
assert.Error(t, err, tc.err)
}
})
}
err := p.Validate()
assert.Error(t, err, "resource group name is required")
}

func TestResourceGroupRun(t *testing.T) {
Expand Down

0 comments on commit 3759a16

Please sign in to comment.