Merge pull request #55 from github/elbrenn/github-event
Add inputs and cron to github context event
This commit is contained in:
@@ -321,22 +321,19 @@ on:
|
|||||||
default: some value
|
default: some value
|
||||||
another-name:
|
another-name:
|
||||||
type: string
|
type: string
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
third-name:
|
||||||
|
type: boolean
|
||||||
jobs:
|
jobs:
|
||||||
a:
|
a:
|
||||||
outputs:
|
|
||||||
build_id: my-build-id
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- run: echo hello a
|
|
||||||
b:
|
|
||||||
needs: [a]
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: echo "hello \${{ inputs.|
|
- run: echo "hello \${{ inputs.|
|
||||||
`;
|
`;
|
||||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||||
|
|
||||||
expect(result.map(x => x.label)).toEqual(["another-name", "name"]);
|
expect(result.map(x => x.label)).toEqual(["another-name", "name", "third-name"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("no inputs", async () => {
|
it("no inputs", async () => {
|
||||||
@@ -345,13 +342,6 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
jobs:
|
jobs:
|
||||||
a:
|
a:
|
||||||
outputs:
|
|
||||||
build_id: my-build-id
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- run: echo hello a
|
|
||||||
b:
|
|
||||||
needs: [a]
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: echo "hello \${{ inputs.|
|
- run: echo "hello \${{ inputs.|
|
||||||
@@ -361,11 +351,12 @@ jobs:
|
|||||||
expect(result).toEqual([]);
|
expect(result).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("github context includes expected keys", async () => {
|
describe("github context", () => {
|
||||||
|
it("includes expected keys", async () => {
|
||||||
const input = `
|
const input = `
|
||||||
on: push
|
on: push
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -378,6 +369,69 @@ jobs:
|
|||||||
expect(result.map(x => x.label)).toContain("actor");
|
expect(result.map(x => x.label)).toContain("actor");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("includes event inputs", async () => {
|
||||||
|
const input = `
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
default: some value
|
||||||
|
another-name:
|
||||||
|
type: string
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
third-name:
|
||||||
|
type: boolean
|
||||||
|
jobs:
|
||||||
|
a:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo "hello \${{ github.event.inputs.|
|
||||||
|
`;
|
||||||
|
const result = await complete(...getPositionFromCursor(input), undefined, undefined);
|
||||||
|
|
||||||
|
expect(result.map(x => x.label)).toEqual(["another-name", "name", "third-name"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("excludes event inputs and cron when no relevant events", async () => {
|
||||||
|
const input = `
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: echo \${{ github.event.| }}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await complete(...getPositionFromCursor(input), undefined, undefined);
|
||||||
|
|
||||||
|
expect(result.map(x => x.label)).not.toContain("inputs");
|
||||||
|
expect(result.map(x => x.label)).not.toContain("cron");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes cron schedules", async () => {
|
||||||
|
const input = `
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: echo \${{ github.event.| }}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await complete(...getPositionFromCursor(input), undefined, undefined);
|
||||||
|
|
||||||
|
expect(result.map(x => x.label)).toContain("cron");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("steps context", () => {
|
describe("steps context", () => {
|
||||||
it("includes defined step IDs", async () => {
|
it("includes defined step IDs", async () => {
|
||||||
const input = `
|
const input = `
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export async function getContext(
|
|||||||
function getDefaultContext(name: string, workflowContext: WorkflowContext, mode: Mode): ContextValue | undefined {
|
function getDefaultContext(name: string, workflowContext: WorkflowContext, mode: Mode): ContextValue | undefined {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "github":
|
case "github":
|
||||||
return getGithubContext();
|
return getGithubContext(workflowContext);
|
||||||
|
|
||||||
case "inputs":
|
case "inputs":
|
||||||
return getInputsContext(workflowContext);
|
return getInputsContext(workflowContext);
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import {data} from "@github/actions-expressions";
|
import {data} from "@github/actions-expressions";
|
||||||
|
import {ExpressionData} from "@github/actions-expressions/data/expressiondata";
|
||||||
|
import {WorkflowContext} from "../context/workflow-context";
|
||||||
|
import {getInputsContext} from "./inputs";
|
||||||
|
|
||||||
export function getGithubContext(): data.Dictionary {
|
export function getGithubContext(workflowContext: WorkflowContext): data.Dictionary {
|
||||||
// https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
|
// https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
|
||||||
const keys = [
|
const keys = [
|
||||||
"action",
|
"action",
|
||||||
@@ -41,7 +44,34 @@ export function getGithubContext(): data.Dictionary {
|
|||||||
|
|
||||||
return new data.Dictionary(
|
return new data.Dictionary(
|
||||||
...keys.map(key => {
|
...keys.map(key => {
|
||||||
|
if (key == "event") {
|
||||||
|
return {key, value: getEventContext(workflowContext)};
|
||||||
|
}
|
||||||
|
|
||||||
return {key, value: new data.Null()};
|
return {key, value: new data.Null()};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getEventContext(workflowContext: WorkflowContext): ExpressionData {
|
||||||
|
const d = new data.Dictionary();
|
||||||
|
const events = workflowContext?.template?.events;
|
||||||
|
|
||||||
|
if (!events) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputs = getInputsContext(workflowContext);
|
||||||
|
if (inputs.values().length > 0) {
|
||||||
|
d.add("inputs", inputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
const schedule = events["schedule"];
|
||||||
|
if (schedule && schedule.length > 0) {
|
||||||
|
const default_cron = schedule[0].cron;
|
||||||
|
// For now, default to the first cron expression only
|
||||||
|
d.add("cron", new data.StringData(default_cron));
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,21 +1,29 @@
|
|||||||
import {data} from "@github/actions-expressions";
|
import {data} from "@github/actions-expressions";
|
||||||
|
import {InputConfig} from "@github/actions-workflow-parser/model/workflow-template";
|
||||||
import {WorkflowContext} from "../context/workflow-context";
|
import {WorkflowContext} from "../context/workflow-context";
|
||||||
|
|
||||||
export function getInputsContext(workflowContext: WorkflowContext): data.Dictionary {
|
export function getInputsContext(workflowContext: WorkflowContext): data.Dictionary {
|
||||||
const d = new data.Dictionary();
|
const d = new data.Dictionary();
|
||||||
if (!workflowContext?.template?.events) {
|
|
||||||
|
const events = workflowContext?.template?.events;
|
||||||
|
if (!events) {
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = workflowContext.template.events["workflow_dispatch"];
|
const dispatch = events["workflow_dispatch"];
|
||||||
if (!event) {
|
if (dispatch?.inputs) {
|
||||||
return d;
|
addInputs(d, dispatch.inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputs = event.inputs;
|
const call = events["workflow_call"];
|
||||||
if (!inputs) {
|
if (call?.inputs) {
|
||||||
return d;
|
addInputs(d, call.inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addInputs(d: data.Dictionary, inputs: {[inputName: string]: InputConfig}) {
|
||||||
for (const inputName of Object.keys(inputs)) {
|
for (const inputName of Object.keys(inputs)) {
|
||||||
const input = inputs[inputName];
|
const input = inputs[inputName];
|
||||||
switch (input.type) {
|
switch (input.type) {
|
||||||
@@ -49,6 +57,4 @@ export function getInputsContext(workflowContext: WorkflowContext): data.Diction
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -988,4 +988,79 @@ jobs:
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("github context", () => {
|
||||||
|
it("includes only expected keys", async () => {
|
||||||
|
const input = `
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo \${{ github.action }}
|
||||||
|
- run: echo \${{ github.steps }}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await validate(createDocument("wf.yaml", input));
|
||||||
|
|
||||||
|
expect(result).toEqual([
|
||||||
|
{
|
||||||
|
message: "Context access might be invalid: steps",
|
||||||
|
range: {
|
||||||
|
end: {
|
||||||
|
character: 37,
|
||||||
|
line: 8
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
character: 18,
|
||||||
|
line: 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
severity: DiagnosticSeverity.Warning
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it("validates event inputs", async () => {
|
||||||
|
const input = `
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
default: some value
|
||||||
|
another-name:
|
||||||
|
type: string
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
third-name:
|
||||||
|
type: boolean
|
||||||
|
jobs:
|
||||||
|
a:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo "hello \${{ github.event.inputs.name }}"
|
||||||
|
- run: echo "hello \${{ github.event.inputs.third-name }}"
|
||||||
|
- run: echo "hello \${{ github.event.inputs.random }}"
|
||||||
|
`;
|
||||||
|
const result = await validate(createDocument("wf.yaml", input));
|
||||||
|
|
||||||
|
expect(result).toEqual([
|
||||||
|
{
|
||||||
|
message: "Context access might be invalid: random",
|
||||||
|
range: {
|
||||||
|
end: {
|
||||||
|
character: 56,
|
||||||
|
line: 19
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
character: 23,
|
||||||
|
line: 19
|
||||||
|
}
|
||||||
|
},
|
||||||
|
severity: DiagnosticSeverity.Warning
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user