diff --git a/docs/checks.md b/docs/checks.md index 5c2c16fc0..d83abf187 100644 --- a/docs/checks.md +++ b/docs/checks.md @@ -2642,6 +2642,12 @@ jobs: env: # ERROR: 'env' context is not available here NAME: ${{ env.NAME }} + services: + redis: + image: redis + env: + # ERROR: No context is allowed here + COMMIT_SHA: ${{ github.sha }} steps: - env: # OK: 'env' context is available here @@ -2663,13 +2669,17 @@ test.yaml:18:17: context "env" is not allowed here. available contexts are "gith | 18 | NAME: ${{ env.NAME }} | ^~~~~~~~ -test.yaml:24:33: calling function "success" is not allowed here. "success" is only available in "jobs..if", "jobs..steps.if". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details [expression] +test.yaml:24:27: context "github" is not allowed here. no context is available here. see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details [expression] + | +24 | COMMIT_SHA: ${{ github.sha }} + | ^~~~~~~~~~ +test.yaml:30:33: calling function "success" is not allowed here. "success" is only available in "jobs..if", "jobs..steps.if". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details [expression] | -24 | run: echo 'Success? ${{ success() }}' +30 | run: echo 'Success? ${{ success() }}' | ^~~~~~~~~ ``` -[Playground](https://rhysd.github.io/actionlint/#eNp8jj1OwzAYhnef4h2QCkNyAC+IgREWTpCkXxtDa0ffT0tU+e7ITU2QkOrFev/sJ0WPyWR0juLJO+D95e3Vg8dZts59pl6KqSRabkCUO6X9vCjg2CmH76qAbWAaNPG8WkCDh8sF+6Cj9e058dfukM7I+V+FLUbiVuk41ZgtSlMorbeo1hy6AnONbsTlLNTlCYqntqi6F6VJaq35u7m/u/3tQcOYsPmwYSCR52tXFvH4hJw3v+2w82vyEwAA//9WsV7P) +[Playground](https://rhysd.github.io/actionlint/#eNp0j8FOwzAMhu99Ch+QBof2AXJBE0KCQ+Ew7ihNvSawJpXtdFRT3x1lXdsJNF+i/7f953PwCrrINsvQ9yoDeNuWzwrIDlxn2VeoOJmCLOkFYCEt2AyTAmi1kPuZFUDtCI0EGlYLIIe70wkaJzZWxTHQ9/4QjjCO/0Yoeo9UCLbd3KboOU+UsYpeYn7QCebcuhCnmqhTBPq+SGreZ6TeGeR5krB2vMK5VjeoJncxr4JTPb2X5evH5+5lq64PYauXTwS7JTT/u38b7nKgAjQ2wGYXjUHmx/MsT+L+AcZxs/Lu1dr5DQAA//+iDXkG) Some contexts are only available in some places. For example, `env` context is not available at `jobs..env`, but it is available at `jobs..steps.env`. @@ -2958,7 +2968,7 @@ Note that `steps` in Composite action's metadata is not checked at this point. I [reusable-workflow-outputs]: https://docs.github.com/en/actions/using-workflows/reusing-workflows#using-outputs-from-a-reusable-workflow [inherit-secrets-announce]: https://github.blog/changelog/2022-05-03-github-actions-simplify-using-secrets-with-reusable-workflows/ [specific-paths-doc]: https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#using-filters-to-target-specific-paths-for-pull-request-or-push-events -[availability-doc]: https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability +[availability-doc]: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#context-availability [deprecate-set-output-save-state]: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ [deprecate-set-env-add-path]: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/ [workflow-commands-doc]: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions diff --git a/expr_sema.go b/expr_sema.go index cf2010702..c18477fad 100644 --- a/expr_sema.go +++ b/expr_sema.go @@ -462,10 +462,6 @@ func (sema *ExprSemanticsChecker) SetContextAvailability(avail []string) { } func (sema *ExprSemanticsChecker) checkAvailableContext(n *VariableNode) { - if len(sema.availableContexts) == 0 { - return - } - ctx := strings.ToLower(n.Name) for _, c := range sema.availableContexts { if c == ctx { @@ -473,16 +469,20 @@ func (sema *ExprSemanticsChecker) checkAvailableContext(n *VariableNode) { } } - s := "contexts are" - if len(sema.availableContexts) == 1 { - s = "context is" + var notes string + switch len(sema.availableContexts) { + case 0: + notes = "no context is available here" + case 1: + notes = "available context is " + quotes(sema.availableContexts) + default: + notes = "available contexts are " + quotes(sema.availableContexts) } sema.errorf( n, - "context %q is not allowed here. available %s %s. see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details", + "context %q is not allowed here. %s. see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details", n.Name, - s, - quotes(sema.availableContexts), + notes, ) } diff --git a/expr_sema_test.go b/expr_sema_test.go index 3f1190c55..193684dab 100644 --- a/expr_sema_test.go +++ b/expr_sema_test.go @@ -754,6 +754,7 @@ func TestExprSemanticsCheckOK(t *testing.T) { } c := NewExprSemanticsChecker(false, nil) + c.SetContextAvailability([]string{"github", "job", "jobs", "matrix", "steps", "needs", "env", "inputs", "secrets", "vars", "runner"}) if tc.funcs != nil { c.funcs = tc.funcs } @@ -1210,6 +1211,14 @@ func TestExprSemanticsCheckError(t *testing.T) { }, availCtx: []string{"env", "matrix"}, }, + { + what: "no available context", + input: "github", + expected: []string{ + "context \"github\" is not allowed here. no context is available", + }, + availCtx: []string{}, + }, { what: "no special function allowed", input: "success()", @@ -1301,6 +1310,8 @@ func TestExprSemanticsCheckError(t *testing.T) { } if tc.availCtx != nil { c.SetContextAvailability(tc.availCtx) + } else { + c.SetContextAvailability([]string{"github", "job", "jobs", "matrix", "steps", "needs", "env", "inputs", "secrets", "vars", "runner"}) } if tc.availSP != nil { c.SetSpecialFunctionAvailability(tc.availSP) @@ -1496,6 +1507,16 @@ func TestExprCompareOperandsCheck(t *testing.T) { }, "any": AnyType{}, } + c.SetContextAvailability([]string{ + "any", + "number", + "string", + "bool", + "null", + "object", + "array", + "array_2d", + }) ty, errs := c.Check(e) if ok { diff --git a/testdata/err/context_availability.out b/testdata/err/context_availability.out index 48a114a35..a94fe071a 100644 --- a/testdata/err/context_availability.out +++ b/testdata/err/context_availability.out @@ -1,4 +1,4 @@ -/test\.yaml:3:34: context "env" is not allowed here\. .+ \[expression\]/ +/test\.yaml:3:35: context "env" is not allowed here\. .+ \[expression\]/ /test\.yaml:10:12: context "env" is not allowed here\. .+ \[expression\]/ /test\.yaml:15:32: context "env" is not allowed here\. .+ \[expression\]/ /test\.yaml:25:22: context "env" is not allowed here\. .+ \[expression\]/ @@ -17,6 +17,7 @@ /test\.yaml:106:18: context "runner" is not allowed here\. .+ \[expression\]/ /test\.yaml:111:20: context "env" is not allowed here\. .+ \[expression\]/ /test\.yaml:115:25: context "runner" is not allowed here\. .+ \[expression\]/ +/test\.yaml:121:23: context "runner" is not allowed here\. .+ \[expression\]/ /test\.yaml:127:17: context "env" is not allowed here\. .+ \[expression\]/ /test\.yaml:134:23: context "env" is not allowed here\. .+ \[expression\]/ /test\.yaml:139:23: context "env" is not allowed here\. .+ \[expression\]/ @@ -31,3 +32,4 @@ /test\.yaml:208:19: context "runner" is not allowed here\. .+ \[expression\]/ /test\.yaml:210:18: context "runner" is not allowed here\. .+ \[expression\]/ /test\.yaml:217:34: context "env" is not allowed here\. .+ \[expression\]/ +/test\.yaml:221:17: context "inputs" is not allowed here\. no context is available here\. .+ \[expression\]/ diff --git a/testdata/err/context_availability.yaml b/testdata/err/context_availability.yaml index 7ee657a4a..34f9666ec 100644 --- a/testdata/err/context_availability.yaml +++ b/testdata/err/context_availability.yaml @@ -1,6 +1,6 @@ # run-name # ERROR at env -run-name: ${{ github.actor}} ${{ env.GITHUB_ACTOR }} +run-name: ${{ github.actor }} ${{ env.GITHUB_ACTOR }} # env env: @@ -117,7 +117,7 @@ jobs: password: ${{ env.MY_PASSWORD }} # jobs..services..env. env: - # OK + # ERROR RUNNER: ${{ runner.name }} # jobs..strategy strategy: @@ -217,3 +217,5 @@ jobs: services: ${{ inputs.bool || env.FOO }} steps: - run: echo + # ERROR at env because `id` allow no context + id: ${{ inputs.foo }} diff --git a/testdata/err/env_context_banned.yaml b/testdata/err/env_context_banned.yaml index 39497104d..7720756b1 100644 --- a/testdata/err/env_context_banned.yaml +++ b/testdata/err/env_context_banned.yaml @@ -21,7 +21,7 @@ jobs: - uses: test/my-action@main env: OS: ${{ runner.os }} - id: foo-${{ runner.name }} + NAME: ${{ runner.name }} container-job: runs-on: ubuntu-latest container: diff --git a/testdata/err/reusable_workflow_empty_secrets.out b/testdata/err/reusable_workflow_empty_secrets.out index 5dc015373..76cb14dd7 100644 --- a/testdata/err/reusable_workflow_empty_secrets.out +++ b/testdata/err/reusable_workflow_empty_secrets.out @@ -1 +1 @@ -/test\.yaml:12:24: property "calling_workflow_secret" is not defined in object type {.+} \[expression\]/ +/test\.yaml:12:23: property "calling_workflow_secret" is not defined in object type {.+} \[expression\]/ diff --git a/testdata/err/reusable_workflow_empty_secrets.yaml b/testdata/err/reusable_workflow_empty_secrets.yaml index d1c2f0d52..492e8dd44 100644 --- a/testdata/err/reusable_workflow_empty_secrets.yaml +++ b/testdata/err/reusable_workflow_empty_secrets.yaml @@ -9,4 +9,4 @@ jobs: steps: - name: Use a repo or org secret from the calling workflow. # So referring this secret causes an error - uses: echo ${{ secrets.CALLING_WORKFLOW_SECRET }} + run: echo ${{ secrets.CALLING_WORKFLOW_SECRET }} diff --git a/testdata/ok/dynamic_shell_name.yaml b/testdata/ok/dynamic_shell_name.yaml index 89a3eadcf..bb6ff8ea9 100644 --- a/testdata/ok/dynamic_shell_name.yaml +++ b/testdata/ok/dynamic_shell_name.yaml @@ -2,14 +2,14 @@ on: push defaults: run: - shell: ${{ env.SHELL }} + shell: ${{ 'sh {0}' }} jobs: test: runs-on: ubuntu-latest defaults: run: - shell: ${{ env.SHELL }} + shell: ${{ 'sh {0}' }} steps: - run: echo hi - shell: ${{ env.SHELL }} + shell: ${{ 'sh {0}' }} diff --git a/testdata/ok/issue-101.yaml b/testdata/ok/issue-101.yaml index ee7d37b77..5a8ecda00 100644 --- a/testdata/ok/issue-101.yaml +++ b/testdata/ok/issue-101.yaml @@ -4,4 +4,4 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: echo ${{ runner.arch }} + - run: echo ${{ runner.arch }} diff --git a/testdata/ok/reusable_workflow_inherit_secrets.yaml b/testdata/ok/reusable_workflow_inherit_secrets.yaml index 999bd5748..de56db35c 100644 --- a/testdata/ok/reusable_workflow_inherit_secrets.yaml +++ b/testdata/ok/reusable_workflow_inherit_secrets.yaml @@ -7,4 +7,4 @@ jobs: steps: # The CALLING_WORKFLOW_SECRET secret is passed with `secrets: inherit` - name: Use a repo or org secret from the calling workflow. - uses: echo ${{ secrets.CALLING_WORKFLOW_SECRET }} + run: echo ${{ secrets.CALLING_WORKFLOW_SECRET }} diff --git a/testdata/ok/workflow_call_job.yaml b/testdata/ok/workflow_call_job.yaml index 62a5fcccd..9aadd89fd 100644 --- a/testdata/ok/workflow_call_job.yaml +++ b/testdata/ok/workflow_call_job.yaml @@ -27,4 +27,4 @@ jobs: permissions: read-all call6: # Edge case. Give up checking format. - uses: ${{ runner.name }} + uses: ${{ 'oooops' }}