diff --git a/pkg/coordinator/tasks/run_shell/task.go b/pkg/coordinator/tasks/run_shell/task.go index b847c83..b3e7f43 100644 --- a/pkg/coordinator/tasks/run_shell/task.go +++ b/pkg/coordinator/tasks/run_shell/task.go @@ -120,12 +120,23 @@ func (t *Task) Execute(ctx context.Context) error { // add env vars for envName, varName := range t.config.EnvVars { - varValue, varFound := t.ctx.Vars.LookupVar(varName) + varValue, varFound, err2 := t.ctx.Vars.ResolveQuery(varName) + if err2 != nil { + cmdLogger.Errorf("failed parsing var query for env variable %v: %v", envName, err2) + return err2 + } + if !varFound { continue } - command.Env = append(command.Env, fmt.Sprintf("%v=%v", envName, varValue)) + varJSON, err3 := json.Marshal(varValue) + if err3 != nil { + cmdLogger.Errorf("failed encoding env variable %v: %v", envName, err3) + return err3 + } + + command.Env = append(command.Env, fmt.Sprintf("%v=%v", envName, string(varJSON))) } // start shell @@ -197,9 +208,16 @@ func (t *Task) readOutputStream(pipe io.ReadCloser) chan string { } var outputVarPattern = regexp.MustCompile(`^::set-var +([^ ]+) +(.*)$`) +var outputJSONPattern = regexp.MustCompile(`^::set-json +([^ ]+) +(.*)$`) func (t *Task) parseOutputVars(line string) { match := outputVarPattern.FindStringSubmatch(line) + if match != nil { + t.ctx.Vars.SetVar(match[1], match[2]) + t.logger.Infof("set variable %v: (string) %v", match[1], match[2]) + } + + match = outputJSONPattern.FindStringSubmatch(line) if match != nil { var varValue interface{} @@ -208,7 +226,7 @@ func (t *Task) parseOutputVars(line string) { t.logger.Warnf("error parsing ::set-var expression: %v", err.Error()) } else { t.ctx.Vars.SetVar(match[1], varValue) - t.logger.Infof("set variable %v: %v", match[1], varValue) + t.logger.Infof("set variable %v: (json) %v", match[1], varValue) } } } diff --git a/pkg/coordinator/types/vars.go b/pkg/coordinator/types/vars.go index b10594f..5f89891 100644 --- a/pkg/coordinator/types/vars.go +++ b/pkg/coordinator/types/vars.go @@ -3,6 +3,7 @@ package types type Variables interface { GetVar(name string) interface{} LookupVar(name string) (interface{}, bool) + ResolveQuery(query string) (interface{}, bool, error) SetVar(name string, value interface{}) NewScope() Variables GetVarsMap() map[string]any diff --git a/pkg/coordinator/vars/variables.go b/pkg/coordinator/vars/variables.go index c390a41..ef18320 100644 --- a/pkg/coordinator/vars/variables.go +++ b/pkg/coordinator/vars/variables.go @@ -101,6 +101,29 @@ func (v *Variables) GetVarsMap() map[string]any { return varsMap } +func (v *Variables) ResolveQuery(queryStr string) (interface{}, bool, error) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + varsMap := v.GetVarsMap() + queryStr = fmt.Sprintf(".%v", queryStr) + + query, err := gojq.Parse(queryStr) + if err != nil { + return nil, false, fmt.Errorf("could not parse variable query '%v': %v", queryStr, err) + } + + iter := query.RunWithContext(ctx, varsMap) + + val, ok := iter.Next() + if !ok { + // no query result, skip variable assignment + return nil, false, nil + } + + return val, true, nil +} + func (v *Variables) ConsumeVars(config interface{}, consumeMap map[string]string) error { applyMap := map[string]interface{}{}