diff --git a/actions-languageservice/src/complete.expressions.test.ts b/actions-languageservice/src/complete.expressions.test.ts index e646353..86973b1 100644 --- a/actions-languageservice/src/complete.expressions.test.ts +++ b/actions-languageservice/src/complete.expressions.test.ts @@ -778,6 +778,57 @@ jobs: expect(result.map(x => x.label)).toEqual(["container", "services", "status"]); }); + it("job context is suggested within a job output", async () => { + const input = ` +on: push +jobs: + test: + runs-on: ubuntu-latest + outputs: + environment: \${{ | }} + steps: + - id: a + run: echo hi +`; + + const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig); + expect(result.map(x => x.label)).toEqual([ + "env", + "github", + "inputs", + "job", + "needs", + "runner", + "secrets", + "steps", + "vars", + "contains", + "endsWith", + "format", + "fromJson", + "join", + "startsWith", + "toJson", + ]); + }); + + it("step context is suggested within a job output", async () => { + const input = ` +on: push +jobs: + test: + runs-on: ubuntu-latest + outputs: + environment: \${{ steps.| }} + steps: + - id: foo + run: echo hi +`; + + const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig); + expect(result.map(x => x.label)).toEqual(["foo"]); + }); + it("container context is suggested within a job container", async () => { const input = ` on: push diff --git a/actions-languageservice/src/context/workflow-context.ts b/actions-languageservice/src/context/workflow-context.ts index 1754ffc..6ba3f28 100644 --- a/actions-languageservice/src/context/workflow-context.ts +++ b/actions-languageservice/src/context/workflow-context.ts @@ -33,7 +33,7 @@ export function getWorkflowContext( // Iterate through the token path to find the job and step for (const token of tokenPath) { switch (token.definition?.key) { - case "job-id": { + case "job": { const jobID = (token as StringToken).value; context.job = template.jobs.find(job => job.id.value === jobID); break; diff --git a/actions-languageservice/src/utils/find-token.test.ts b/actions-languageservice/src/utils/find-token.test.ts index d1e5f75..d639fde 100644 --- a/actions-languageservice/src/utils/find-token.test.ts +++ b/actions-languageservice/src/utils/find-token.test.ts @@ -145,7 +145,7 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"], + ["job", TokenType.String, "build"], ["job-factory", TokenType.Mapping], ["runs-on", TokenType.String, "runs-on"], ["runs-on", TokenType.Sequence] @@ -180,7 +180,7 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"], + ["job", TokenType.String, "build"], ["job-factory", TokenType.Mapping], ["runs-on", TokenType.String, "runs-on"] ], @@ -201,7 +201,7 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"], + ["job", TokenType.String, "build"], ["job-factory", TokenType.Mapping] ], parent: ["job-factory", TokenType.Mapping], @@ -221,7 +221,7 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"], + ["job", TokenType.String, "build"], ["job-factory", TokenType.Mapping] ], parent: ["job-factory", TokenType.Mapping], @@ -241,7 +241,7 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"], + ["job", TokenType.String, "build"], ["job-factory", TokenType.Mapping] ], parent: ["job-factory", TokenType.Mapping], @@ -261,10 +261,10 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"] + ["job", TokenType.String, "build"] ], parent: ["jobs", TokenType.Mapping], - key: ["job-id", TokenType.String, "build"], + key: ["job", TokenType.String, "build"], token: [null, TokenType.String, "continue-on-error:foo"] }); }); @@ -280,7 +280,7 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"], + ["job", TokenType.String, "build"], ["job-factory", TokenType.Mapping] ], parent: ["job-factory", TokenType.Mapping], @@ -300,7 +300,7 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"], + ["job", TokenType.String, "build"], ["job-factory", TokenType.Mapping] ], parent: ["job-factory", TokenType.Mapping], @@ -320,10 +320,10 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"] + ["job", TokenType.String, "build"] ], parent: ["jobs", TokenType.Mapping], - key: ["job-id", TokenType.String, "build"], + key: ["job", TokenType.String, "build"], token: [null, TokenType.String, "runs-"] }); }); @@ -340,10 +340,10 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"] + ["job", TokenType.String, "build"] ], parent: ["jobs", TokenType.Mapping], - key: ["job-id", TokenType.String, "build"], + key: ["job", TokenType.String, "build"], token: [null, TokenType.String, "runs-"] }); }); @@ -360,7 +360,7 @@ jobs: ["workflow-root-strict", TokenType.Mapping], ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], - ["job-id", TokenType.String, "build"], + ["job", TokenType.String, "build"], ["job-factory", TokenType.Mapping], ["runs-on", TokenType.String, "runs-on"] ], diff --git a/actions-languageservice/src/validate.expressions.test.ts b/actions-languageservice/src/validate.expressions.test.ts index 7d7c84c..a5b4944 100644 --- a/actions-languageservice/src/validate.expressions.test.ts +++ b/actions-languageservice/src/validate.expressions.test.ts @@ -190,6 +190,39 @@ jobs: ]); }); + it("reference of invalid step in job outputs", async () => { + const input = ` + on: push + jobs: + a: + outputs: + environment: \${{ steps.foo }} + runs-on: ubuntu-latest + steps: + - id: a + run: echo hello a + `; + + const result = await validate(createDocument("wf.yaml", input)); + + expect(result).toEqual([ + { + "message": "Context access might be invalid: foo", + "range": { + "end": { + "character": 41, + "line": 5, + }, + "start": { + "character": 25, + "line": 5, + }, + }, + "severity": 2, + }, + ]); + }); + it("invalid reference of generated step name", async () => { const input = ` on: push diff --git a/package-lock.json b/package-lock.json index 49208c3..4c99a8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -702,9 +702,9 @@ "link": true }, "node_modules/@github/actions-workflow-parser": { - "version": "0.0.38", - "resolved": "https://npm.pkg.github.com/download/@github/actions-workflow-parser/0.0.38/e696d29d18f20c008147bc09c0d2c9b5777ba7ba", - "integrity": "sha512-FfFUS8CJOwodvmw2b/0K7W9sEd2uwuCzmO8cyjp+Ew4uzDRtjX7Q7TkMras7/U4LrpvDhpYZ2TucF3yY+seSkA==", + "version": "0.0.39", + "resolved": "https://npm.pkg.github.com/download/@github/actions-workflow-parser/0.0.39/ba3e9e02e489175e0f284f0aebd9bde92ad4e935", + "integrity": "sha512-Iw8OkCUxdgFvXpJkg6dAIEpGQrS09o3TC1I0looCJ1lHMBDBD7aVXasE8zJzlQUTdgRTGMiptNMgZS2MnGC76Q==", "license": "MIT", "dependencies": { "@github/actions-expressions": "*", @@ -13565,9 +13565,9 @@ } }, "@github/actions-workflow-parser": { - "version": "0.0.38", - "resolved": "https://npm.pkg.github.com/download/@github/actions-workflow-parser/0.0.38/e696d29d18f20c008147bc09c0d2c9b5777ba7ba", - "integrity": "sha512-FfFUS8CJOwodvmw2b/0K7W9sEd2uwuCzmO8cyjp+Ew4uzDRtjX7Q7TkMras7/U4LrpvDhpYZ2TucF3yY+seSkA==", + "version": "0.0.39", + "resolved": "https://npm.pkg.github.com/download/@github/actions-workflow-parser/0.0.39/ba3e9e02e489175e0f284f0aebd9bde92ad4e935", + "integrity": "sha512-Iw8OkCUxdgFvXpJkg6dAIEpGQrS09o3TC1I0looCJ1lHMBDBD7aVXasE8zJzlQUTdgRTGMiptNMgZS2MnGC76Q==", "requires": { "@github/actions-expressions": "*", "yaml": "^2.0.0-8"