ensure invalid dependecy fails linter with helpful error
This commit is contained in:
@@ -19,15 +19,6 @@ import (
|
||||
// have the same name.
|
||||
var ErrDuplicateStepName = errors.New("linter: duplicate step names")
|
||||
|
||||
// ErrMissingDependency is returned when a Pipeline step
|
||||
// defines dependencies that are invlid or unknown.
|
||||
var ErrMissingDependency = errors.New("linter: invalid or unknown step dependency")
|
||||
|
||||
// ErrCyclicalDependency is returned when a Pipeline step
|
||||
// defines a cyclical dependency, which would result in an
|
||||
// infinite execution loop.
|
||||
var ErrCyclicalDependency = errors.New("linter: cyclical step dependency detected")
|
||||
|
||||
// Opts provides linting options.
|
||||
type Opts struct {
|
||||
Trusted bool
|
||||
@@ -80,13 +71,28 @@ func checkPipeline(pipeline *resource.Pipeline, trusted bool) error {
|
||||
|
||||
func checkSteps(pipeline *resource.Pipeline, trusted bool) error {
|
||||
steps := append(pipeline.Services, pipeline.Steps...)
|
||||
names := map[string]struct{}{}
|
||||
if !pipeline.Clone.Disable {
|
||||
names["clone"] = struct{}{}
|
||||
}
|
||||
for _, step := range steps {
|
||||
if step == nil {
|
||||
return errors.New("linter: nil step")
|
||||
}
|
||||
|
||||
// unique list of names
|
||||
_, ok := names[step.Name]
|
||||
if ok {
|
||||
return ErrDuplicateStepName
|
||||
}
|
||||
names[step.Name] = struct{}{}
|
||||
|
||||
if err := checkStep(step, trusted); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkDeps(step, names); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -171,3 +177,16 @@ func checkEmptyDirVolume(volume *resource.VolumeEmptyDir, trusted bool) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkDeps(step *resource.Step, deps map[string]struct{}) error {
|
||||
for _, dep := range step.DependsOn {
|
||||
_, ok := deps[dep]
|
||||
if !ok {
|
||||
return fmt.Errorf("linter: unknown step dependency detected: %s references %s", step.Name, dep)
|
||||
}
|
||||
if step.Name == dep {
|
||||
return fmt.Errorf("linter: cyclical step dependency detected: %s", dep)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -197,6 +197,12 @@ func TestLint(t *testing.T) {
|
||||
// invalid: true,
|
||||
// message: "linter: invalid or missing name",
|
||||
// },
|
||||
|
||||
{
|
||||
path: "testdata/missing_dep.yml",
|
||||
invalid: true,
|
||||
message: "linter: unknown step dependency detected: test references foo",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
name := path.Base(test.path)
|
||||
|
||||
29
engine/linter/testdata/missing_dep.yml
vendored
29
engine/linter/testdata/missing_dep.yml
vendored
@@ -1,35 +1,18 @@
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: amd64
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: golang
|
||||
commands:
|
||||
- go build
|
||||
|
||||
- name: test
|
||||
image: golang
|
||||
commands:
|
||||
- go build
|
||||
- go test
|
||||
|
||||
services:
|
||||
- name: database
|
||||
image: redis
|
||||
ports:
|
||||
- 6379
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: arm
|
||||
|
||||
platform:
|
||||
arch: arm
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: golang
|
||||
commands:
|
||||
- go build
|
||||
- go test
|
||||
|
||||
depends_on:
|
||||
- foo
|
||||
...
|
||||
Reference in New Issue
Block a user