Skip to content

Commit 76d2632

Browse files
committed
TEP-0075: Extract out the validation of object keys
Prior to this commit, the validation against the required and provided keys for object type was part of the validateObjectUsage function. That makes the purpose of validateObjectUsage confusing. In this commit, a new helper function is created to validate that separately. Also functions are reordered a bit to make the whole file easier to track and read.
1 parent 3c0fb3b commit 76d2632

File tree

2 files changed

+65
-47
lines changed

2 files changed

+65
-47
lines changed

pkg/apis/pipeline/v1beta1/task_validation.go

Lines changed: 64 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ func ValidateParameterVariables(steps []Step, params []ParamSpec) *apis.FieldErr
325325

326326
errs := validateVariables(steps, "params", parameterNames)
327327
errs = errs.Also(validateArrayUsage(steps, "params", arrayParameterNames))
328+
errs = errs.Also(validateObjectDefault(objectParamSpecs))
328329
return errs.Also(validateObjectUsage(steps, objectParamSpecs))
329330
}
330331

@@ -361,52 +362,6 @@ func ValidateResourcesVariables(steps []Step, resources *TaskResources) *apis.Fi
361362
return validateVariables(steps, "resources.(?:inputs|outputs)", resourceNames)
362363
}
363364

364-
// TODO (@chuangw6): Make sure an object param is not used as a whole when providing values for strings.
365-
// https://github.com/tektoncd/community/blob/main/teps/0075-object-param-and-result-types.md#variable-replacement-with-object-params
366-
// "When providing values for strings, Task and Pipeline authors can access
367-
// individual attributes of an object param; they cannot access the object
368-
// as whole (we could add support for this later)."
369-
func validateObjectUsage(steps []Step, params []ParamSpec) (errs *apis.FieldError) {
370-
objectParameterNames := sets.NewString()
371-
for _, p := range params {
372-
// collect all names of object type params
373-
objectParameterNames.Insert(p.Name)
374-
375-
// collect all keys for this object param
376-
objectKeys := sets.NewString()
377-
for key := range p.Properties {
378-
objectKeys.Insert(key)
379-
}
380-
381-
if p.Default != nil && p.Default.ObjectVal != nil {
382-
errs = errs.Also(validateObjectKeysInDefault(p.Default.ObjectVal, objectKeys, p.Name))
383-
}
384-
385-
// check if the object's key names are referenced correctly i.e. param.objectParam.key1
386-
errs = errs.Also(validateVariables(steps, fmt.Sprintf("params\\.%s", p.Name), objectKeys))
387-
}
388-
389-
return errs
390-
}
391-
392-
// validate if object keys defined in properties are all provided in default
393-
func validateObjectKeysInDefault(defaultObject map[string]string, neededObjectKeys sets.String, paramName string) (errs *apis.FieldError) {
394-
neededObjectKeysInSpec := neededObjectKeys.List()
395-
providedObjectKeysInDefault := []string{}
396-
for k := range defaultObject {
397-
providedObjectKeysInDefault = append(providedObjectKeysInDefault, k)
398-
}
399-
400-
missingObjectKeys := list.DiffLeft(neededObjectKeysInSpec, providedObjectKeysInDefault)
401-
if len(missingObjectKeys) != 0 {
402-
return &apis.FieldError{
403-
Message: fmt.Sprintf("Required key(s) %s for the parameter %s are not provided in default.", missingObjectKeys, paramName),
404-
Paths: []string{fmt.Sprintf("%s.properties", paramName), fmt.Sprintf("%s.default", paramName)},
405-
}
406-
}
407-
return nil
408-
}
409-
410365
func validateArrayUsage(steps []Step, prefix string, vars sets.String) (errs *apis.FieldError) {
411366
for idx, step := range steps {
412367
errs = errs.Also(validateStepArrayUsage(step, prefix, vars)).ViaFieldIndex("steps", idx)
@@ -488,6 +443,69 @@ func validateStepVariables(step Step, prefix string, vars sets.String) *apis.Fie
488443
return errs
489444
}
490445

446+
// validateObjectDefault validates the keys of all the object params within a
447+
// slice of ParamSpecs are provided in default iff the default section is provided.
448+
func validateObjectDefault(objectParams []ParamSpec) (errs *apis.FieldError) {
449+
for _, p := range objectParams {
450+
errs = errs.Also(validateObjectKeys(p.Properties, p.Default, p.Name))
451+
}
452+
return errs
453+
}
454+
455+
// validate if object keys defined in properties are all provided in its value provider iff the provider is not nil.
456+
func validateObjectKeys(properties map[string]PropertySpec, propertiesProvider *ArrayOrString, name string) (errs *apis.FieldError) {
457+
if propertiesProvider == nil || propertiesProvider.ObjectVal == nil {
458+
return nil
459+
}
460+
461+
neededKeys := []string{}
462+
providedKeys := []string{}
463+
464+
// collect all needed keys
465+
for key := range properties {
466+
neededKeys = append(neededKeys, key)
467+
}
468+
469+
// collect all provided keys
470+
for key := range propertiesProvider.ObjectVal {
471+
providedKeys = append(providedKeys, key)
472+
}
473+
474+
missings := list.DiffLeft(neededKeys, providedKeys)
475+
if len(missings) != 0 {
476+
return &apis.FieldError{
477+
Message: fmt.Sprintf("Required key(s) %s for the parameter %s are missing in the value provider.", missings, name),
478+
Paths: []string{fmt.Sprintf("%s.properties", name), fmt.Sprintf("%s.default", name)},
479+
}
480+
}
481+
482+
return nil
483+
}
484+
485+
// TODO (@chuangw6): Make sure an object param is not used as a whole when providing values for strings.
486+
// https://github.com/tektoncd/community/blob/main/teps/0075-object-param-and-result-types.md#variable-replacement-with-object-params
487+
// "When providing values for strings, Task and Pipeline authors can access
488+
// individual attributes of an object param; they cannot access the object
489+
// as whole (we could add support for this later)."
490+
func validateObjectUsage(steps []Step, params []ParamSpec) (errs *apis.FieldError) {
491+
objectParameterNames := sets.NewString()
492+
for _, p := range params {
493+
// collect all names of object type params
494+
objectParameterNames.Insert(p.Name)
495+
496+
// collect all keys for this object param
497+
objectKeys := sets.NewString()
498+
for key := range p.Properties {
499+
objectKeys.Insert(key)
500+
}
501+
502+
// check if the object's key names are referenced correctly i.e. param.objectParam.key1
503+
errs = errs.Also(validateVariables(steps, fmt.Sprintf("params\\.%s", p.Name), objectKeys))
504+
}
505+
506+
return errs
507+
}
508+
491509
func validateTaskVariable(value, prefix string, vars sets.String) *apis.FieldError {
492510
return substitution.ValidateVariableP(value, prefix, vars)
493511
}

pkg/apis/pipeline/v1beta1/task_validation_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ func TestTaskSpecValidateError(t *testing.T) {
660660
Steps: validSteps,
661661
},
662662
expectedError: apis.FieldError{
663-
Message: fmt.Sprintf("Required key(s) %s for the parameter %s are not provided in default.", []string{"key2"}, "myobjectParam"),
663+
Message: fmt.Sprintf("Required key(s) %s for the parameter %s are missing in the value provider.", []string{"key2"}, "myobjectParam"),
664664
Paths: []string{"myobjectParam.properties", "myobjectParam.default"},
665665
},
666666
}, {

0 commit comments

Comments
 (0)