2022-11-15 15:59:14 -08:00
|
|
|
import {data} from "@github/actions-expressions";
|
2022-12-14 16:10:31 -05:00
|
|
|
import {CompletionItemKind} from "vscode-languageserver-types";
|
2022-11-15 13:03:44 -08:00
|
|
|
import {complete, getExpressionInput} from "./complete";
|
|
|
|
|
import {ContextProviderConfig} from "./context-providers/config";
|
2022-12-08 10:17:29 -08:00
|
|
|
import {registerLogger} from "./log";
|
2022-11-15 13:03:44 -08:00
|
|
|
import {getPositionFromCursor} from "./test-utils/cursor-position";
|
2022-12-08 10:17:29 -08:00
|
|
|
import {TestLogger} from "./test-utils/logger";
|
2022-11-15 13:03:44 -08:00
|
|
|
|
|
|
|
|
const contextProviderConfig: ContextProviderConfig = {
|
2022-11-29 16:56:20 -05:00
|
|
|
getContext: async (context: string) => {
|
2022-11-15 15:59:14 -08:00
|
|
|
switch (context) {
|
|
|
|
|
case "github":
|
|
|
|
|
return new data.Dictionary({
|
|
|
|
|
key: "event",
|
|
|
|
|
value: new data.StringData("push")
|
|
|
|
|
});
|
2022-11-15 13:03:44 -08:00
|
|
|
}
|
|
|
|
|
|
2022-11-15 15:59:14 -08:00
|
|
|
return undefined;
|
2022-11-15 13:03:44 -08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-08 10:17:29 -08:00
|
|
|
registerLogger(new TestLogger());
|
|
|
|
|
|
2022-11-15 13:03:44 -08:00
|
|
|
describe("expressions", () => {
|
|
|
|
|
it("input extraction", () => {
|
|
|
|
|
const test = (input: string) => {
|
|
|
|
|
const [doc, pos] = getPositionFromCursor(input);
|
|
|
|
|
return getExpressionInput(doc.getText(), pos.character);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
expect(test("${{ gh |")).toBe(" gh ");
|
|
|
|
|
expect(test("${{ gh |}}")).toBe(" gh ");
|
2022-12-15 15:18:59 +01:00
|
|
|
expect(test("${{ vars| == 'test' }}")).toBe(" vars");
|
|
|
|
|
expect(test("${{ fromJso|('test').bar == 'test' }}")).toBe(" fromJso");
|
|
|
|
|
expect(test("${{ github.| == 'test' }}")).toBe(" github.");
|
|
|
|
|
expect(test("test ${{ github.| == 'test' }}")).toBe(" github.");
|
2022-11-15 13:03:44 -08:00
|
|
|
expect(test("${{ vars }} ${{ gh |}}")).toBe(" gh ");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe("top-level auto-complete", () => {
|
|
|
|
|
it("single region", async () => {
|
|
|
|
|
const input = "run-name: ${{ | }}";
|
2022-12-12 19:06:08 -05:00
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, undefined);
|
2022-11-15 13:03:44 -08:00
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual([
|
|
|
|
|
"github",
|
|
|
|
|
"inputs",
|
|
|
|
|
"vars",
|
|
|
|
|
"contains",
|
|
|
|
|
"endsWith",
|
|
|
|
|
"format",
|
|
|
|
|
"fromJson",
|
|
|
|
|
"join",
|
|
|
|
|
"startsWith",
|
|
|
|
|
"toJson"
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("single region with existing input", async () => {
|
|
|
|
|
const input = "run-name: ${{ g| }}";
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual([
|
|
|
|
|
"github",
|
|
|
|
|
"inputs",
|
|
|
|
|
"vars",
|
|
|
|
|
"contains",
|
|
|
|
|
"endsWith",
|
|
|
|
|
"format",
|
|
|
|
|
"fromJson",
|
|
|
|
|
"join",
|
|
|
|
|
"startsWith",
|
|
|
|
|
"toJson"
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
2022-12-15 15:18:59 +01:00
|
|
|
it("single region with existing condition", async () => {
|
|
|
|
|
const input = "run-name: ${{ g| == 'test' }}";
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual([
|
|
|
|
|
"github",
|
|
|
|
|
"inputs",
|
|
|
|
|
"vars",
|
|
|
|
|
"contains",
|
|
|
|
|
"endsWith",
|
|
|
|
|
"format",
|
|
|
|
|
"fromJson",
|
|
|
|
|
"join",
|
|
|
|
|
"startsWith",
|
|
|
|
|
"toJson"
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("multiple regions with partial function", async () => {
|
|
|
|
|
const input = "run-name: Run a ${{ inputs.test }} one-line script ${{ from|('test') == inputs.name }}";
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual([
|
|
|
|
|
"github",
|
|
|
|
|
"inputs",
|
|
|
|
|
"vars",
|
|
|
|
|
"contains",
|
|
|
|
|
"endsWith",
|
|
|
|
|
"format",
|
|
|
|
|
"fromJson",
|
|
|
|
|
"join",
|
|
|
|
|
"startsWith",
|
|
|
|
|
"toJson"
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
2022-11-15 13:03:44 -08:00
|
|
|
it("multiple regions", async () => {
|
|
|
|
|
const input = "run-name: test-${{ github }}-${{ | }}";
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual([
|
|
|
|
|
"github",
|
|
|
|
|
"inputs",
|
|
|
|
|
"vars",
|
|
|
|
|
"contains",
|
|
|
|
|
"endsWith",
|
|
|
|
|
"format",
|
|
|
|
|
"fromJson",
|
|
|
|
|
"join",
|
|
|
|
|
"startsWith",
|
|
|
|
|
"toJson"
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
2022-12-08 16:38:36 -08:00
|
|
|
describe("multi-line strings", () => {
|
|
|
|
|
it("indented |", async () => {
|
|
|
|
|
const input = `on: push
|
|
|
|
|
jobs:
|
|
|
|
|
build:
|
|
|
|
|
steps:
|
|
|
|
|
- run: |
|
|
|
|
|
first line
|
|
|
|
|
test \${{ github.| }}
|
|
|
|
|
test2`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input, 1), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["event"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("indented |+", async () => {
|
|
|
|
|
const input = `on: push
|
|
|
|
|
jobs:
|
|
|
|
|
build:
|
|
|
|
|
steps:
|
|
|
|
|
- run: |+
|
|
|
|
|
first line
|
|
|
|
|
test \${{ github.| }}
|
|
|
|
|
test2`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input, 1), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["event"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("indented >", async () => {
|
|
|
|
|
const input = `on: push
|
|
|
|
|
jobs:
|
|
|
|
|
build:
|
|
|
|
|
steps:
|
|
|
|
|
- run: >
|
|
|
|
|
first line
|
|
|
|
|
test \${{ github.| }}
|
|
|
|
|
test2`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["event"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("indented >+", async () => {
|
|
|
|
|
const input = `on: push
|
|
|
|
|
jobs:
|
|
|
|
|
build:
|
|
|
|
|
steps:
|
|
|
|
|
- run: >+
|
|
|
|
|
first line
|
|
|
|
|
test \${{ github.| }}
|
|
|
|
|
test2`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["event"]);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2022-11-15 13:03:44 -08:00
|
|
|
it("nested auto-complete", async () => {
|
|
|
|
|
const input = "run-name: ${{ github.| }}";
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["event"]);
|
|
|
|
|
});
|
2022-11-15 15:59:14 -08:00
|
|
|
|
|
|
|
|
it("using default context provider", async () => {
|
|
|
|
|
const input =
|
|
|
|
|
"on: push\njobs:\n build:\n runs-on: ubuntu-latest\n environment:\n url: ${{ runner.| }}\n steps:\n - run: echo";
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["arch", "name", "os", "temp", "tool_cache"]);
|
|
|
|
|
});
|
2022-11-16 16:19:48 -08:00
|
|
|
|
|
|
|
|
it("job if", async () => {
|
|
|
|
|
const input = `on: push
|
|
|
|
|
jobs:
|
|
|
|
|
build:
|
|
|
|
|
if: github.|
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["event"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("step if", async () => {
|
|
|
|
|
const input = `on: push
|
|
|
|
|
jobs:
|
|
|
|
|
build:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo
|
|
|
|
|
if: github.|`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["event"]);
|
|
|
|
|
});
|
2022-11-15 13:03:44 -08:00
|
|
|
});
|
2022-11-29 16:56:20 -05:00
|
|
|
|
|
|
|
|
it("context inherited from parent", async () => {
|
|
|
|
|
// The token definition is just a `string` and
|
|
|
|
|
// the parent `step-with` holds the allowed context
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
jobs:
|
|
|
|
|
build:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/deploy@v100
|
|
|
|
|
with:
|
|
|
|
|
deploy-key: \${{ secrets.|
|
|
|
|
|
`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
2022-12-07 18:10:27 -08:00
|
|
|
expect(result.map(x => x.label)).toEqual(["GITHUB_TOKEN"]);
|
2022-11-29 16:56:20 -05:00
|
|
|
});
|
2022-11-30 11:21:32 -05:00
|
|
|
|
|
|
|
|
it("needs context only includes referenced jobs", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
jobs:
|
|
|
|
|
a:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo hello a
|
|
|
|
|
b:
|
|
|
|
|
needs: [a]
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo hello b
|
|
|
|
|
c:
|
|
|
|
|
needs: [b]
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
2022-12-02 11:28:03 -08:00
|
|
|
- run: echo "hello \${{ needs.|
|
2022-11-30 11:21:32 -05:00
|
|
|
`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["b"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("needs.<job_id>", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
jobs:
|
|
|
|
|
a:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo hello a
|
|
|
|
|
b:
|
|
|
|
|
needs: [a]
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
2022-12-02 11:28:03 -08:00
|
|
|
- run: echo "hello \${{ needs.a.|
|
2022-11-30 11:21:32 -05:00
|
|
|
`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["outputs", "result"]);
|
|
|
|
|
});
|
|
|
|
|
|
2022-12-01 14:46:48 -05:00
|
|
|
it("needs.<job_id>.outputs includes outputs", async () => {
|
2022-11-30 11:21:32 -05:00
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
jobs:
|
|
|
|
|
a:
|
|
|
|
|
outputs:
|
|
|
|
|
build_id: my-build-id
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo hello a
|
|
|
|
|
b:
|
|
|
|
|
needs: [a]
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo "hello \${{ needs.a.outputs.|
|
|
|
|
|
`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["build_id"]);
|
|
|
|
|
});
|
2022-12-02 11:28:03 -08:00
|
|
|
|
|
|
|
|
it("inputs", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on:
|
|
|
|
|
workflow_dispatch:
|
|
|
|
|
inputs:
|
|
|
|
|
name:
|
|
|
|
|
type: string
|
|
|
|
|
default: some value
|
|
|
|
|
another-name:
|
|
|
|
|
type: string
|
|
|
|
|
jobs:
|
|
|
|
|
a:
|
|
|
|
|
outputs:
|
|
|
|
|
build_id: my-build-id
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo hello a
|
|
|
|
|
b:
|
|
|
|
|
needs: [a]
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo "hello \${{ inputs.|
|
|
|
|
|
`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["another-name", "name"]);
|
|
|
|
|
});
|
2022-12-05 15:23:28 -05:00
|
|
|
|
|
|
|
|
it("no inputs", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on:
|
|
|
|
|
workflow_dispatch:
|
|
|
|
|
jobs:
|
|
|
|
|
a:
|
|
|
|
|
outputs:
|
|
|
|
|
build_id: my-build-id
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo hello a
|
|
|
|
|
b:
|
|
|
|
|
needs: [a]
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo "hello \${{ inputs.|
|
|
|
|
|
`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result).toEqual([]);
|
|
|
|
|
});
|
2022-12-06 17:46:09 -05:00
|
|
|
|
2022-12-12 19:06:08 -05:00
|
|
|
it("github context includes expected keys", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- run: echo \${{ github.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, undefined);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toContain("actor");
|
|
|
|
|
});
|
|
|
|
|
|
2022-12-05 16:50:39 -05:00
|
|
|
describe("steps context", () => {
|
|
|
|
|
it("includes defined step IDs", async () => {
|
|
|
|
|
const input = `
|
2022-12-05 15:20:13 -08:00
|
|
|
on: push
|
|
|
|
|
jobs:
|
|
|
|
|
one:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- id: a
|
|
|
|
|
run: echo hello a
|
|
|
|
|
- id: b
|
|
|
|
|
run: echo hello b
|
|
|
|
|
- id: c
|
|
|
|
|
run: echo "hello \${{ steps.|
|
|
|
|
|
`;
|
2022-12-05 16:50:39 -05:00
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["a", "b"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("step.<step_id>", async () => {
|
|
|
|
|
const input = `
|
2022-12-05 15:20:13 -08:00
|
|
|
on: push
|
|
|
|
|
jobs:
|
|
|
|
|
one:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- id: a
|
|
|
|
|
run: echo hello a
|
|
|
|
|
- run: echo "hello \${{ steps.a.|
|
2022-12-05 16:50:39 -05:00
|
|
|
`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["conclusion", "outcome", "outputs"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("ignores IDs from later steps", async () => {
|
|
|
|
|
const input = `
|
2022-12-05 15:20:13 -08:00
|
|
|
on: push
|
|
|
|
|
jobs:
|
|
|
|
|
one:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- id: a
|
|
|
|
|
run: echo hello a
|
|
|
|
|
- id: b
|
|
|
|
|
run: echo "hello \${{ steps.|
|
|
|
|
|
- id: c
|
|
|
|
|
run: echo hello c
|
2022-12-05 16:50:39 -05:00
|
|
|
`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["a"]);
|
|
|
|
|
});
|
|
|
|
|
|
2022-12-06 17:46:09 -05:00
|
|
|
it("Ignores generated IDs", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
jobs:
|
|
|
|
|
one:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo hello a
|
|
|
|
|
- id: b
|
|
|
|
|
run: echo hello b
|
|
|
|
|
- run: echo "hello \${{ steps.|
|
|
|
|
|
`;
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
2022-12-05 16:50:39 -05:00
|
|
|
|
2022-12-06 17:46:09 -05:00
|
|
|
expect(result.map(x => x.label)).toEqual(["b"]);
|
|
|
|
|
});
|
2022-12-05 16:50:39 -05:00
|
|
|
});
|
2022-12-06 18:02:54 -05:00
|
|
|
|
|
|
|
|
describe("strategy context", () => {
|
2022-12-07 13:26:34 -05:00
|
|
|
it("strategy is not suggested when outside of a matrix job", async () => {
|
2022-12-06 18:02:54 -05:00
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- run: npm test > test-job-\${{ | }}.txt
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).not.toContain("strategy");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("strategy is suggested within a matrix job", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
strategy:
|
|
|
|
|
matrix:
|
|
|
|
|
test-group: [1, 2]
|
|
|
|
|
node: [14, 16]
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- run: npm test > test-job-\${{ | }}.txt
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toContain("strategy");
|
|
|
|
|
});
|
|
|
|
|
|
2022-12-07 19:08:44 -05:00
|
|
|
it("includes expected keys", async () => {
|
|
|
|
|
const input = `
|
2022-12-06 18:02:54 -05:00
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
2022-12-07 13:26:34 -05:00
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
strategy:
|
|
|
|
|
matrix:
|
|
|
|
|
test-group: [1, 2]
|
|
|
|
|
node: [14, 16]
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- run: npm test > test-job-\${{ strategy.| }}.txt
|
2022-12-07 19:08:44 -05:00
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["fail-fast", "job-index", "job-total", "max-parallel"]);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe("matrix context", () => {
|
|
|
|
|
it("matrix is not suggested when outside of a matrix job", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- run: npm test > test-job-\${{ | }}.txt
|
2022-12-06 18:02:54 -05:00
|
|
|
`;
|
|
|
|
|
|
2022-12-07 19:08:44 -05:00
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
2022-12-06 18:02:54 -05:00
|
|
|
|
2022-12-07 19:08:44 -05:00
|
|
|
expect(result.map(x => x.label)).not.toContain("strategy");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("matrix is suggested within a matrix job", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
strategy:
|
|
|
|
|
matrix:
|
|
|
|
|
test-group: [1, 2]
|
|
|
|
|
node: [14, 16]
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- run: npm test > test-job-\${{ | }}.txt
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toContain("strategy");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("basic matrix job", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: \${{ matrix.os }}
|
|
|
|
|
strategy:
|
|
|
|
|
matrix:
|
|
|
|
|
os: [ubuntu-latest, windows-latest]
|
|
|
|
|
node: [14, 16]
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- uses: actions/setup-node@v3
|
|
|
|
|
with:
|
|
|
|
|
node-version: \${{ matrix.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["node", "os"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("matrix with include", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
strategy:
|
|
|
|
|
matrix:
|
|
|
|
|
fruit: [apple, pear]
|
|
|
|
|
animal: [cat, dog]
|
|
|
|
|
include:
|
|
|
|
|
- color: green
|
|
|
|
|
- color: pink
|
|
|
|
|
animal: cat
|
|
|
|
|
- fruit: apple
|
|
|
|
|
shape: circle
|
|
|
|
|
- fruit: banana
|
|
|
|
|
- fruit: banana
|
|
|
|
|
animal: cat
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- uses: actions/setup-node@v3
|
|
|
|
|
with:
|
|
|
|
|
node-version: \${{ matrix.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["animal", "color", "fruit", "shape"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("matrix from expression", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
strategy:
|
|
|
|
|
matrix: \${{ fromJSON('{"color":["green","blue"]}') }}
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- uses: actions/setup-node@v3
|
|
|
|
|
with:
|
|
|
|
|
node-version: \${{ matrix.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual([]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("matrix with include expression", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: \${{ matrix.os }}
|
|
|
|
|
strategy:
|
|
|
|
|
matrix:
|
|
|
|
|
fruit: [apple, pear]
|
|
|
|
|
animal: [cat, dog]
|
|
|
|
|
include: \${{ fromJSON('{"color":"green"}') }}
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- uses: actions/setup-node@v3
|
|
|
|
|
with:
|
|
|
|
|
node-version: \${{ matrix.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
2022-12-08 14:34:11 -05:00
|
|
|
expect(result.map(x => x.label)).toEqual(["animal", "fruit"]);
|
2022-12-07 19:08:44 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("matrix with expression in property", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
strategy:
|
|
|
|
|
matrix:
|
|
|
|
|
color: \${{ fromJSON('["green","blue"]') }}
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- uses: actions/setup-node@v3
|
|
|
|
|
with:
|
|
|
|
|
node-version: \${{ matrix.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["color"]);
|
|
|
|
|
});
|
2022-12-06 18:02:54 -05:00
|
|
|
});
|
2022-12-14 16:10:31 -05:00
|
|
|
|
2022-12-16 10:58:09 -08:00
|
|
|
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
|
2022-12-16 11:34:06 -08:00
|
|
|
services:
|
|
|
|
|
nginx:
|
|
|
|
|
image: node:14.16
|
2022-12-16 10:58:09 -08:00
|
|
|
steps:
|
|
|
|
|
- run: echo \${{ job.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
2022-12-16 11:34:06 -08:00
|
|
|
expect(result.map(x => x.label)).toEqual(["container", "services", "status"]);
|
2022-12-16 10:58:09 -08:00
|
|
|
});
|
|
|
|
|
|
2022-12-16 11:34:06 -08:00
|
|
|
it("container context is suggested within a job container", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
container:
|
|
|
|
|
image: node:14.16
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo \${{ job.container.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["id", "network"]);
|
2022-12-16 10:58:09 -08:00
|
|
|
});
|
|
|
|
|
|
2022-12-16 11:34:06 -08:00
|
|
|
it("services are suggested within a job services list", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
services:
|
|
|
|
|
nginx:
|
|
|
|
|
image: node:14.16
|
|
|
|
|
redis:
|
|
|
|
|
image: redis
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo \${{ job.services.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["nginx", "redis"]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("services context is suggested within a job service", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
services:
|
|
|
|
|
nginx:
|
|
|
|
|
image: node:14.16
|
|
|
|
|
ports:
|
|
|
|
|
- 80:8080
|
|
|
|
|
- 90
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo \${{ job.services.nginx.| }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
expect(result.map(x => x.label)).toEqual(["id", "network", "ports"]);
|
2022-12-16 10:58:09 -08:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2022-12-14 16:10:31 -05:00
|
|
|
it("context completion items include kind and insert text", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@v3
|
|
|
|
|
- run: echo \${{ | }}.txt
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
// Built-in function
|
|
|
|
|
const toJSON = result.find(x => x.label === "toJson");
|
|
|
|
|
expect(toJSON).toBeDefined();
|
|
|
|
|
expect(toJSON!.kind).toBe(CompletionItemKind.Function);
|
|
|
|
|
expect(toJSON!.insertText).toBe("toJson()");
|
|
|
|
|
|
|
|
|
|
// Function from context
|
|
|
|
|
const hashFiles = result.find(x => x.label === "hashFiles");
|
|
|
|
|
expect(hashFiles).toBeDefined();
|
|
|
|
|
expect(hashFiles!.kind).toBe(CompletionItemKind.Function);
|
|
|
|
|
expect(hashFiles!.insertText).toBe("hashFiles()");
|
|
|
|
|
|
|
|
|
|
// Not a function
|
|
|
|
|
const github = result.find(x => x.label === "github");
|
|
|
|
|
expect(github).toBeDefined();
|
|
|
|
|
expect(github!.kind).toBe(CompletionItemKind.Variable);
|
|
|
|
|
expect(github!.insertText).toBeUndefined();
|
|
|
|
|
});
|
2022-12-15 10:48:28 -05:00
|
|
|
|
|
|
|
|
it("function parentheses are not inserted when parentheses already exist", async () => {
|
|
|
|
|
const input = `
|
|
|
|
|
on: push
|
|
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
test:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
steps:
|
|
|
|
|
- run: echo \${{ toJS|(github.event) }}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
|
|
|
|
|
|
|
|
|
expect(result.find(x => x.label === "toJson")!.insertText).toBe("toJson");
|
|
|
|
|
});
|
2022-11-15 13:03:44 -08:00
|
|
|
});
|