From 85403727decb9e3628a18a63e26e51477641ea8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20B=C3=A9trancourt?= Date: Fri, 23 Dec 2022 11:49:17 +0100 Subject: [PATCH] feat: allow to set a expression_timeout in variables (#399) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Bétrancourt --- engine/values/values.go | 19 ++++++++++++++----- hack/template-schema.json | 4 ++++ models/tasktemplate/fromdir_test.go | 16 ++++++++++++++++ models/tasktemplate/template.go | 10 ++++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/engine/values/values.go b/engine/values/values.go index 51b0d168..9c3824cf 100644 --- a/engine/values/values.go +++ b/engine/values/values.go @@ -44,10 +44,11 @@ type Values struct { // Variable holds a named variable, with either a JS expression to be evalued // or a concrete value type Variable struct { - Name string `json:"name"` - Expression string `json:"expression"` - Value interface{} `json:"value"` - evalCachedResult interface{} + Name string `json:"name"` + Expression string `json:"expression"` + ExpressionTimeout string `json:"expression_timeout"` + Value interface{} `json:"value"` + evalCachedResult interface{} } // NewValues instantiates a new Values holder, @@ -430,7 +431,15 @@ func (v *Values) varEval(varName string) (interface{}, error) { return nil, err } - res, err := evalUnsafe(exp, time.Second*10) + var timeout = time.Second * 10 + if i.ExpressionTimeout != "" { + timeout, err = time.ParseDuration(i.ExpressionTimeout) + if err != nil { + return nil, err + } + } + + res, err := evalUnsafe(exp, timeout) if err != nil { return nil, err } diff --git a/hack/template-schema.json b/hack/template-schema.json index 84e347f2..62e98c33 100644 --- a/hack/template-schema.json +++ b/hack/template-schema.json @@ -976,6 +976,10 @@ "expression": { "type": "string", "description": "Javascript expression that will be evaluated (can be templated)" + }, + "expression_timeout": { + "type": "string", + "description": "A valid golang duration which can be parsed by time.ParseDuration()" } } }, diff --git a/models/tasktemplate/fromdir_test.go b/models/tasktemplate/fromdir_test.go index fa261fe1..f0dfb106 100644 --- a/models/tasktemplate/fromdir_test.go +++ b/models/tasktemplate/fromdir_test.go @@ -138,6 +138,22 @@ func TestInvalidVariablesTemplates(t *testing.T) { tt.Normalize() err = tt.Valid() assert.Contains(t, fmt.Sprint(err), "expression and value can't be empty at the same time") + + tt.Variables[0].Name = "toto" + tt.Variables[0].Expression = "" + tt.Variables[0].Value = "foo" + tt.Variables[0].ExpressionTimeout = "30s" + tt.Normalize() + err = tt.Valid() + assert.Contains(t, fmt.Sprint(err), "expression timeout cannot be defined when value is defined") + + tt.Variables[0].Name = "toto" + tt.Variables[0].Expression = "1+1" + tt.Variables[0].Value = nil + tt.Variables[0].ExpressionTimeout = "foo" + tt.Normalize() + err = tt.Valid() + assert.Contains(t, fmt.Sprint(err), "invalid duration \"foo\"") } func TestDependenciesValidation(t *testing.T) { diff --git a/models/tasktemplate/template.go b/models/tasktemplate/template.go index e9b83917..32a5682d 100644 --- a/models/tasktemplate/template.go +++ b/models/tasktemplate/template.go @@ -3,6 +3,7 @@ package tasktemplate import ( "encoding/json" "fmt" + "time" "github.com/Masterminds/squirrel" "github.com/juju/errors" @@ -451,6 +452,15 @@ func validateVariables(variables []values.Variable) error { if variable.Value == nil && variable.Expression == "" { return errors.BadRequestf("variable %q expression and value can't be empty at the same time", variable.Name) } + if variable.Value != nil && variable.ExpressionTimeout != "" { + return errors.BadRequestf("variable %q expression timeout cannot be defined when value is defined", variable.Name) + } + if variable.ExpressionTimeout != "" { + _, err := time.ParseDuration(variable.ExpressionTimeout) + if err != nil { + return errors.BadRequestf("variable %q %s", variable.Name, err) + } + } } return nil