@@ -21,49 +21,45 @@ func init() {
2121 }
2222}
2323
24- func anyVarNotInEnv (expression string , variables []string , env map [string ]interface {}) bool {
25- for _ , variable := range variables {
24+ var variablesToCheck = []string {
25+ "item" ,
26+ "retries" ,
27+ "lastRetry.exitCode" ,
28+ "lastRetry.status" ,
29+ "lastRetry.duration" ,
30+ "lastRetry.message" ,
31+ "workflow.status" ,
32+ "workflow.failures" ,
33+ }
34+
35+ func anyVarNotInEnv (expression string , env map [string ]interface {}) * string {
36+ for _ , variable := range variablesToCheck {
2637 if hasVariableInExpression (expression , variable ) && ! hasVarInEnv (env , variable ) {
27- return true
38+ return & variable
2839 }
2940 }
30- return false
41+ return nil
3142}
3243
3344func expressionReplace (w io.Writer , expression string , env map [string ]interface {}, allowUnresolved bool ) (int , error ) {
3445 // The template is JSON-marshaled. This JSON-unmarshals the expression to undo any character escapes.
3546 var unmarshalledExpression string
3647 err := json .Unmarshal ([]byte (fmt .Sprintf (`"%s"` , expression )), & unmarshalledExpression )
3748 if err != nil && allowUnresolved {
38- log .WithError (err ).Debug ("unresolved is allowed " )
49+ log .WithError (err ).Debug ("unresolved is allowed" )
3950 return fmt .Fprintf (w , "{{%s%s}}" , kindExpression , expression )
4051 }
4152 if err != nil {
4253 return 0 , fmt .Errorf ("failed to unmarshall JSON expression: %w" , err )
4354 }
4455
45- if anyVarNotInEnv (unmarshalledExpression , []string {"retries" }, env ) && allowUnresolved {
46- // this is to make sure expressions like `sprig.int(retries)` don't get resolved to 0 when `retries` don't exist in the env
47- // See https://github.com/argoproj/argo-workflows/issues/5388
48- log .WithError (err ).Debug ("Retries are present and unresolved is allowed" )
49- return fmt .Fprintf (w , "{{%s%s}}" , kindExpression , expression )
50- }
51-
52- lastRetryVariables := []string {"lastRetry.exitCode" , "lastRetry.status" , "lastRetry.duration" , "lastRetry.message" }
53- if anyVarNotInEnv (unmarshalledExpression , lastRetryVariables , env ) && allowUnresolved {
54- // This is to make sure expressions which contains `lastRetry.*` don't get resolved to nil
55- // when they don't exist in the env.
56- log .WithError (err ).Debug ("LastRetry variables are present and unresolved is allowed" )
57- return fmt .Fprintf (w , "{{%s%s}}" , kindExpression , expression )
58- }
59-
60- // This is to make sure expressions which contains `workflow.status` and `work.failures` don't get resolved to nil
61- // when `workflow.status` and `workflow.failures` don't exist in the env.
62- // See https://github.com/argoproj/argo-workflows/issues/10393, https://github.com/expr-lang/expr/issues/330
63- // This issue doesn't happen to other template parameters since `workflow.status` and `workflow.failures` only exist in the env
64- // when the exit handlers complete.
65- if anyVarNotInEnv (unmarshalledExpression , []string {"workflow.status" , "workflow.failures" }, env ) && allowUnresolved {
66- log .WithError (err ).Debug ("workflow.status or workflow.failures are present and unresolved is allowed" )
56+ varNameNotInEnv := anyVarNotInEnv (unmarshalledExpression , env )
57+ if varNameNotInEnv != nil && allowUnresolved {
58+ // this is to make sure expressions don't get resolved to nil or an empty string when certain variables
59+ // don't exist in the env during the "global" replacement.
60+ // See https://github.com/argoproj/argo-workflows/issues/5388, https://github.com/argoproj/argo-workflows/issues/15008,
61+ // https://github.com/argoproj/argo-workflows/issues/10393, https://github.com/expr-lang/expr/issues/330
62+ log .WithField ("variable" , * varNameNotInEnv ).Debug ("variable not in env but unresolved is allowed" )
6763 return fmt .Fprintf (w , "{{%s%s}}" , kindExpression , expression )
6864 }
6965
@@ -116,11 +112,6 @@ func EnvMap(replaceMap map[string]string) map[string]interface{} {
116112 return envMap
117113}
118114
119- // hasRetries checks if the variable `retries` exists in the expression template
120- func hasRetries (expression string ) bool {
121- return hasVariableInExpression (expression , "retries" )
122- }
123-
124115func searchTokens (haystack []lexer.Token , needle []lexer.Token ) bool {
125116 if len (needle ) > len (haystack ) {
126117 return false
0 commit comments