Add jobs context (#160)
This commit is contained in:
@@ -729,6 +729,107 @@ jobs:
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("jobs context", () => {
|
||||||
|
it("includes defined jobs", async () => {
|
||||||
|
const input = `
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
# Map the workflow outputs to job outputs
|
||||||
|
outputs:
|
||||||
|
result:
|
||||||
|
description: "one or two"
|
||||||
|
value: \${{ jobs.| }}
|
||||||
|
jobs:
|
||||||
|
one:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- id: a
|
||||||
|
run: echo hello a
|
||||||
|
two:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- id: b
|
||||||
|
run: echo hello b
|
||||||
|
`;
|
||||||
|
const result = await complete(...getPositionFromCursor(input), {contextProviderConfig});
|
||||||
|
|
||||||
|
expect(result.map(x => x.label)).toEqual(["one", "two"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("jobs.<job_id>.result only", async () => {
|
||||||
|
const input = `
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
# Map the workflow outputs to job outputs
|
||||||
|
outputs:
|
||||||
|
result:
|
||||||
|
description: "The result"
|
||||||
|
value: \${{ jobs.one.| }}
|
||||||
|
jobs:
|
||||||
|
one:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- id: a
|
||||||
|
run: echo hello a
|
||||||
|
`;
|
||||||
|
const result = await complete(...getPositionFromCursor(input), {contextProviderConfig});
|
||||||
|
|
||||||
|
expect(result.map(x => x.label)).toEqual(["result"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("jobs.<job_id>", async () => {
|
||||||
|
const input = `
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
outputs:
|
||||||
|
output1:
|
||||||
|
description: "A greeting"
|
||||||
|
value: \${{ jobs.example_job.| }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
example_job:
|
||||||
|
name: Generate output
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Map the job outputs to step outputs
|
||||||
|
outputs:
|
||||||
|
output1: "\${{ steps.a.outputs.greeting }}"
|
||||||
|
steps:
|
||||||
|
- id: a
|
||||||
|
run: echo "greeting=hello" >> $GITHUB_OUTPUT
|
||||||
|
`;
|
||||||
|
const result = await complete(...getPositionFromCursor(input), {contextProviderConfig});
|
||||||
|
|
||||||
|
expect(result.map(x => x.label)).toEqual(["outputs", "result"]);
|
||||||
|
});
|
||||||
|
it("jobs.<job_id>.outputs", async () => {
|
||||||
|
const input = `
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
outputs:
|
||||||
|
output1:
|
||||||
|
description: "A greeting"
|
||||||
|
value: \${{ jobs.example_job.outputs.| }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
example_job:
|
||||||
|
name: Generate output
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Map the job outputs to step outputs
|
||||||
|
outputs:
|
||||||
|
output1: "\${{ steps.a.outputs.greeting }}"
|
||||||
|
output2: "\${{ steps.b.outputs.greeting }}"
|
||||||
|
steps:
|
||||||
|
- id: a
|
||||||
|
run: echo "greeting=hello" >> $GITHUB_OUTPUT
|
||||||
|
- id: b
|
||||||
|
run: echo "greeting=hello" >> $GITHUB_OUTPUT
|
||||||
|
`;
|
||||||
|
const result = await complete(...getPositionFromCursor(input), {contextProviderConfig});
|
||||||
|
|
||||||
|
expect(result.map(x => x.label)).toEqual(["output1", "output2"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("strategy context", () => {
|
describe("strategy context", () => {
|
||||||
it("strategy is not suggested when outside of a matrix job", async () => {
|
it("strategy is not suggested when outside of a matrix job", async () => {
|
||||||
const input = `
|
const input = `
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {getEnvContext} from "./env";
|
|||||||
import {getGithubContext} from "./github";
|
import {getGithubContext} from "./github";
|
||||||
import {getInputsContext} from "./inputs";
|
import {getInputsContext} from "./inputs";
|
||||||
import {getJobContext} from "./job";
|
import {getJobContext} from "./job";
|
||||||
|
import {getJobsContext} from "./jobs";
|
||||||
import {getMatrixContext} from "./matrix";
|
import {getMatrixContext} from "./matrix";
|
||||||
import {getNeedsContext} from "./needs";
|
import {getNeedsContext} from "./needs";
|
||||||
import {getStepsContext} from "./steps";
|
import {getStepsContext} from "./steps";
|
||||||
@@ -61,6 +62,9 @@ function getDefaultContext(name: string, workflowContext: WorkflowContext, mode:
|
|||||||
case "job":
|
case "job":
|
||||||
return getJobContext(workflowContext);
|
return getJobContext(workflowContext);
|
||||||
|
|
||||||
|
case "jobs":
|
||||||
|
return getJobsContext(workflowContext);
|
||||||
|
|
||||||
case "matrix":
|
case "matrix":
|
||||||
return getMatrixContext(workflowContext, mode);
|
return getMatrixContext(workflowContext, mode);
|
||||||
|
|
||||||
|
|||||||
@@ -172,6 +172,14 @@
|
|||||||
"description": "`GITHUB_TOKEN` is a secret that is automatically created for every workflow run, and is always included in the secrets context. For more information, see [Automatic token authentication](https://docs.github.com/actions/security-guides/automatic-token-authentication)."
|
"description": "`GITHUB_TOKEN` is a secret that is automatically created for every workflow run, and is always included in the secrets context. For more information, see [Automatic token authentication](https://docs.github.com/actions/security-guides/automatic-token-authentication)."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jobs": {
|
||||||
|
"outputs": {
|
||||||
|
"description": "The set of outputs of a job in a reusable workflow."
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"description": "The result of a job in the reusable workflow. Possible values are `success`, `failure`, `cancelled`, or `skipped`."
|
||||||
|
}
|
||||||
|
},
|
||||||
"steps": {
|
"steps": {
|
||||||
"outputs": {
|
"outputs": {
|
||||||
"description": "The set of outputs defined for the step."
|
"description": "The set of outputs defined for the step."
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import {data, DescriptionDictionary} from "@github/actions-expressions";
|
||||||
|
import {StringData} from "@github/actions-expressions/data/string";
|
||||||
|
import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/mapping-token";
|
||||||
|
import {WorkflowContext} from "../context/workflow-context";
|
||||||
|
import {getDescription} from "./descriptions";
|
||||||
|
|
||||||
|
export function getJobsContext(workflowContext: WorkflowContext): DescriptionDictionary {
|
||||||
|
// https://docs.github.com/en/actions/learn-github-actions/contexts#jobs-context
|
||||||
|
const jobsContext = new DescriptionDictionary();
|
||||||
|
|
||||||
|
const jobs = workflowContext.template?.jobs;
|
||||||
|
if (!jobs) {
|
||||||
|
return jobsContext;
|
||||||
|
}
|
||||||
|
for (const job of jobs) {
|
||||||
|
const jobContext = new DescriptionDictionary();
|
||||||
|
jobContext.add("result", new data.Null(), getDescription("jobs", "result"));
|
||||||
|
|
||||||
|
const outputs = job.outputs || new data.Null();
|
||||||
|
if (outputs instanceof MappingToken) {
|
||||||
|
jobContext.add("outputs", createOutputsContext(outputs as MappingToken), getDescription("jobs", "outputs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
jobsContext.add(job.id.toString(), jobContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobsContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOutputsContext(outputs: MappingToken): DescriptionDictionary {
|
||||||
|
const outputsContext = new DescriptionDictionary();
|
||||||
|
for (const output of outputs) {
|
||||||
|
outputsContext.add(
|
||||||
|
output.key.toString(),
|
||||||
|
new StringData(output.value.toString()),
|
||||||
|
getDescription(output.key.toString(), "output")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return outputsContext;
|
||||||
|
}
|
||||||
@@ -404,6 +404,55 @@ jobs:
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("jobs context", () => {
|
||||||
|
it("jobs.<job_id>.result", async () => {
|
||||||
|
const input = `
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
# Map the workflow outputs to job outputs
|
||||||
|
outputs:
|
||||||
|
successful:
|
||||||
|
description: "Was job successful"
|
||||||
|
value: \${{ jobs.example_job.result }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
example_job:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- id: a
|
||||||
|
run: echo hello world`;
|
||||||
|
|
||||||
|
const result = await validate(createDocument("wf.yaml", input));
|
||||||
|
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("jobs.<job_id>.outputs.<output_name>", async () => {
|
||||||
|
const input = `
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
outputs:
|
||||||
|
output1:
|
||||||
|
description: "A greeting"
|
||||||
|
value: \${{ jobs.example_job.outputs.output1 }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
example_job:
|
||||||
|
name: Generate output
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Map the job outputs to step outputs
|
||||||
|
outputs:
|
||||||
|
output1: "\${{ steps.a.outputs.greeting }}"
|
||||||
|
steps:
|
||||||
|
- id: a
|
||||||
|
run: echo "greeting=hello" >> $GITHUB_OUTPUT`;
|
||||||
|
|
||||||
|
const result = await validate(createDocument("wf.yaml", input));
|
||||||
|
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("env context", () => {
|
describe("env context", () => {
|
||||||
it("references env within scope", async () => {
|
it("references env within scope", async () => {
|
||||||
const input = `
|
const input = `
|
||||||
|
|||||||
Reference in New Issue
Block a user