Backport of https://github.com/go-gitea/gitea/pull/38754
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-name: ${{ 1) && (2 }} # panicked, aborting workflow parsing for the push
if: ${{ 1 }} ${{ 0) && (0 }} # silently skipped the job
runs-on: ${{ nosuchcontext.x }} # silently queued the job against the label ""
```
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. A part that fails is an error instead of an empty string.
`expressionCallsFunction` is self-contained here, since this branch has
no `expressionsMatch` to build it on. That makes
`github.com/rhysd/actionlint` a direct dependency, which it already is
on `main`.
Update golangci-lint from v2.11.2 to v2.11.4 and fix new `modernize`
lint warnings:
- Use `strings.Builder` instead of string concatenation in loop
(`evaluator.go`)
- Use `atomic.Int64` instead of `int64` with atomic free functions
(`logchecker.go`, `timer_test.go`, `integration_test.go`)
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
The jobparser sub package in act is only used by Gitea. Move it to Gitea
to make it more easier to maintain.
---------
Co-authored-by: Christopher Homberger <christopher.homberger@web.de>