Skip to content

Commit

Permalink
cherry pick (ish) refactoring and fixes from master 🍒
Browse files Browse the repository at this point in the history
In order to cherry pick in the fixes from #2393 and #2471, we first need
to apply the refactoring/changes these were built on in
a8946d4#diff-e2b4c96e5145aa139a97f864d9f9f2a1
but unfortunately this both refactored/changed the code, AND added
pipeline results. Since we don't want to add a new feature in a patch
release, this commit extracts the refactoring (and fix?) from that
commit.
  • Loading branch information
bobcatfish committed Apr 23, 2020
1 parent 33e0847 commit b399116
Show file tree
Hide file tree
Showing 9 changed files with 564 additions and 484 deletions.
9 changes: 6 additions & 3 deletions pkg/apis/pipeline/v1alpha1/pipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,12 @@ func (pt PipelineTask) Deps() []string {
}
// Add any dependents from task results
for _, param := range pt.Params {
if resultRefs, err := v1beta1.NewResultRefs(param); err == nil {
for _, resultRef := range resultRefs {
deps = append(deps, resultRef.PipelineTask)
expressions, ok := v1beta1.GetVarSubstitutionExpressionsForParam(param)
if ok {
if resultRefs, err := v1beta1.NewResultRefs(expressions); err == nil {
for _, resultRef := range resultRefs {
deps = append(deps, resultRef.PipelineTask)
}
}
}
}
Expand Down
9 changes: 6 additions & 3 deletions pkg/apis/pipeline/v1alpha1/pipeline_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,12 @@ func validateGraph(tasks []PipelineTask) error {
func validateParamResults(tasks []PipelineTask) error {
for _, task := range tasks {
for _, param := range task.Params {
if v1beta1.LooksLikeContainsResultRefs(param) {
if _, err := v1beta1.NewResultRefs(param); err != nil {
return err
expressions, ok := v1beta1.GetVarSubstitutionExpressionsForParam(param)
if ok {
if v1beta1.LooksLikeContainsResultRefs(expressions) {
if _, err := v1beta1.NewResultRefs(expressions); err != nil {
return err
}
}
}
}
Expand Down
107 changes: 0 additions & 107 deletions pkg/apis/pipeline/v1beta1/param_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import (
"context"
"encoding/json"
"fmt"
"regexp"
"strings"

resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1"
)
Expand Down Expand Up @@ -142,108 +140,3 @@ func NewArrayOrString(value string, values ...string) ArrayOrString {
StringVal: value,
}
}

// ResultRef is a type that represents a reference to a task run result
type ResultRef struct {
PipelineTask string
Result string
}

const (
resultExpressionFormat = "tasks.<taskName>.results.<resultName>"
// ResultTaskPart Constant used to define the "tasks" part of a pipeline result reference
ResultTaskPart = "tasks"
// ResultResultPart Constant used to define the "results" part of a pipeline result reference
ResultResultPart = "results"
variableSubstitutionFormat = `\$\([A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\)`
)

var variableSubstitutionRegex = regexp.MustCompile(variableSubstitutionFormat)

// NewResultRefs extracts all ResultReferences from param.
// If the ResultReference can be extracted, they are returned. Otherwise an error is returned
func NewResultRefs(param Param) ([]*ResultRef, error) {
substitutionExpressions, ok := getVarSubstitutionExpressions(param)
if !ok {
return nil, fmt.Errorf("Invalid result reference expression: must contain variable substitution %q", resultExpressionFormat)
}
var resultRefs []*ResultRef
for _, expression := range substitutionExpressions {
pipelineTask, result, err := parseExpression(expression)
if err != nil {
return nil, fmt.Errorf("Invalid result reference expression: %v", err)
}
resultRefs = append(resultRefs, &ResultRef{
PipelineTask: pipelineTask,
Result: result,
})
}
return resultRefs, nil
}

// LooksLikeContainsResultRefs attempts to check if param looks like it contains any
// result references.
// This is useful if we want to make sure the param looks like a ResultReference before
// performing strict validation
func LooksLikeContainsResultRefs(param Param) bool {
extractedExpressions, ok := getVarSubstitutionExpressions(param)
if !ok {
return false
}
for _, expression := range extractedExpressions {
if looksLikeResultRef(expression) {
return true
}
}
return false
}

func looksLikeResultRef(expression string) bool {
return strings.HasPrefix(expression, "task") && strings.Contains(expression, ".result")
}

// getVarSubstitutionExpressions extracts all the value between "$(" and ")""
func getVarSubstitutionExpressions(param Param) ([]string, bool) {
var allExpressions []string
switch param.Value.Type {
case ParamTypeArray:
// array type
for _, value := range param.Value.ArrayVal {
expressions := variableSubstitutionRegex.FindAllString(value, -1)
if expressions == nil {
continue
}
for _, expression := range expressions {
allExpressions = append(allExpressions, stripVarSubExpression(expression))
}
}
if len(allExpressions) == 0 {
return nil, false
}
return allExpressions, true
case ParamTypeString:
// string type
expressions := variableSubstitutionRegex.FindAllString(param.Value.StringVal, -1)
if expressions == nil {
return nil, false
}
for _, expression := range expressions {
allExpressions = append(allExpressions, stripVarSubExpression(expression))
}
return allExpressions, true
default:
return nil, false
}
}

func stripVarSubExpression(expression string) string {
return strings.TrimSuffix(strings.TrimPrefix(expression, "$("), ")")
}

func parseExpression(substitutionExpression string) (string, string, error) {
subExpressions := strings.Split(substitutionExpression, ".")
if len(subExpressions) != 4 || subExpressions[0] != ResultTaskPart || subExpressions[2] != ResultResultPart {
return "", "", fmt.Errorf("Must be of the form %q", resultExpressionFormat)
}
return subExpressions[1], subExpressions[3], nil
}
Loading

0 comments on commit b399116

Please sign in to comment.