fix: evaluate each ${{ }} part on its own (#1146)

Every `${{ }}` part was spliced as raw text into a synthesized `format('...', <raw>)` call and re-parsed, so unbalanced parentheses restructured the whole expression:

```yaml
run: echo ${{ 1) && (2 }}      # panicked with "did not evaluate to a string"
if: ${{ 1 }} ${{ 0) && (0 }}   # silently skipped the step
```

One scanner shaped like GitHub's template reader now splits every value, and each part is evaluated on its own, so nothing builds an expression out of text.

An empty input to `Evaluate` asked `success()` whatever the caller requested, so a post step running under `always()` asked the wrong question.

Same fix as https://github.com/go-gitea/gitea/pull/38754 on the Gitea side.

Written by Claude Opus 5.

---------

Co-authored-by: bircni <[email protected]>
Reviewed-on: https://gitea.com/gitea/runner/pulls/1146
Reviewed-by: bircni <[email protected]>
Co-authored-by: silverwind <[email protected]>
This commit is contained in:
silverwindandbircni authored and bircni committed 2026-08-06 16:05:39 +00:00
1 parent 09b643bc14
commit 20497aaf4f
4 files changed
+202 -154

No files matched your search

+7
View File
@@ -682,3 +682,10 @@ func TestCoerceToString(t *testing.T) {
})
}
}
func TestEvaluateEmptyInputAsksItsOwnStatusCheck(t *testing.T) {
// always() needs no job or step context, so it shows which function an empty input asks for
output, err := NewInterpeter(&EvaluationEnvironment{}, Config{}).Evaluate("", DefaultStatusCheckAlways)
require.NoError(t, err)
assert.Equal(t, true, output)
}