diff --git a/actions-languageservice/src/complete.expressions.test.ts b/actions-languageservice/src/complete.expressions.test.ts index 6b5e41b..55f2d60 100644 --- a/actions-languageservice/src/complete.expressions.test.ts +++ b/actions-languageservice/src/complete.expressions.test.ts @@ -674,6 +674,33 @@ jobs: }); }); + describe("job context", () => { + it("job context is suggested within a job", async () => { + const input = ` +on: push + +jobs: + test: + runs-on: ubuntu-latest + container: + image: node:14.16 + steps: + - run: echo \${{ job.| }} +`; + + const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig); + expect(result.map(x => x.label)).toContain("container"); + expect(result.map(x => x.label)).toContain("services"); + expect(result.map(x => x.label)).toContain("status"); + }); + + it("job context is suggested within a job", async () => { + }); + + it("job context is suggested within a job", async () => { + }); + }); + it("context completion items include kind and insert text", async () => { const input = ` on: push diff --git a/actions-languageservice/src/context-providers/job.ts b/actions-languageservice/src/context-providers/job.ts index 1cc9ccd..245e922 100644 --- a/actions-languageservice/src/context-providers/job.ts +++ b/actions-languageservice/src/context-providers/job.ts @@ -14,7 +14,7 @@ export function getJobContext(workflowContext: WorkflowContext): data.Dictionary // Container const jobContainer = job.container; if (jobContainer && isMapping(jobContainer)) { - let containerContext = createContainerContext(jobContainer, false); + const containerContext = createContainerContext(jobContainer, false); jobContext.add("container", containerContext); } @@ -26,7 +26,7 @@ export function getJobContext(workflowContext: WorkflowContext): data.Dictionary if (!isMapping(service.value)) { continue } - let serviceContext = createContainerContext(service.value, true); + const serviceContext = createContainerContext(service.value, true); servicesContext.add(service.key.toString(), serviceContext); } jobContext.add("services", servicesContext); @@ -59,6 +59,10 @@ function createContainerContext(container: MappingToken, isServices: boolean): d if (isServices && portParts.length === 2) { ports.add(portParts[1], new data.StringData(portParts[0])); } + else { + // If the port isn't a mapping, just use null + ports.add(portParts[0], new data.Null()); + } } containerContext.add(token.key.toString(), ports); } diff --git a/actions-languageservice/src/validate.expressions.test.ts b/actions-languageservice/src/validate.expressions.test.ts index 6cb674e..ace4d85 100644 --- a/actions-languageservice/src/validate.expressions.test.ts +++ b/actions-languageservice/src/validate.expressions.test.ts @@ -283,6 +283,38 @@ jobs: expect(result).toEqual([]); }); + + it("job.services.", async () => { + const input = ` +on: push + +jobs: + test: + runs-on: ubuntu-latest + container: + image: node:14.16 + steps: + - run: echo \${{ job.container.tupperware }} +`; + const result = await validate(createDocument("wf.yaml", input)); + + expect(result).toEqual([ + { + message: "Context access might be invalid: tupperware", + range: { + end: { + character: 49, + line: 9 + }, + start: { + character: 18, + line: 9 + } + }, + severity: DiagnosticSeverity.Warning + } + ]); + }); }); describe("strategy context", () => {