diff --git a/actions-languageservice/src/hover.test.ts b/actions-languageservice/src/hover.test.ts index ab2f5b3..e90041c 100644 --- a/actions-languageservice/src/hover.test.ts +++ b/actions-languageservice/src/hover.test.ts @@ -1,17 +1,15 @@ import {TextDocument} from "vscode-languageserver-textdocument"; import {hover} from "./hover"; +import {getPositionFromCursor} from "./test-utils/cursor-position"; describe("validation", () => { it("valid workflow", async () => { - const input = `on: push + const input = `o|n: push jobs: build: - runs-on: [self-hosted, u|]`; + runs-on: [self-hosted]`; const doc = TextDocument.create("test://test/test.yaml", "yaml", 0, input); - const result = await hover(doc, { - line: 0, - character: 0 - }); + const result = await hover(doc, getPositionFromCursor(input)[1]); expect(result).not.toBeUndefined(); expect(result?.contents).toEqual( "The name of the GitHub event that triggers the workflow. You can provide a single event string, array of events, array of event types, or an event configuration map that schedules a workflow or restricts the execution of a workflow to specific files, tags, or branch changes. For a list of available events, see https://help.github.com/en/github/automating-your-workflow-with-github-actions/events-that-trigger-workflows." @@ -19,15 +17,25 @@ jobs: }); it("hover on value", async () => { - const input = `on: push + const input = `on: pu|sh jobs: build: - runs-on: [self-hosted, u|]`; + runs-on: [self-hosted]`; const doc = TextDocument.create("test://test/test.yaml", "yaml", 0, input); - const result = await hover(doc, { - line: 0, - character: 5 - }); - expect(result?.contents).toBeUndefined(); + const result = await hover(doc, getPositionFromCursor(input)[1]); + expect(result).not.toBeUndefined(); + expect(result?.contents).toEqual("Runs your workflow when you push a commit or tag."); + }); + + it("hover on sequence value", async () => { + const input = `on: [pull_request, + pu|sh] +jobs: + build: + runs-on: [self-hosted]`; + const doc = TextDocument.create("test://test/test.yaml", "yaml", 0, input); + const result = await hover(doc, getPositionFromCursor(input)[1]); + expect(result).not.toBeUndefined(); + expect(result?.contents).toEqual("Runs your workflow when you push a commit or tag."); }); }); diff --git a/actions-languageservice/src/utils/find-token.test.ts b/actions-languageservice/src/utils/find-token.test.ts index 0cfe35e..788095d 100644 --- a/actions-languageservice/src/utils/find-token.test.ts +++ b/actions-languageservice/src/utils/find-token.test.ts @@ -53,7 +53,7 @@ describe("find-token", () => { path: [["workflow-root-strict", TokenType.Mapping]], parent: ["workflow-root-strict", TokenType.Mapping], key: null, - token: [null, TokenType.String, "on"] + token: ["on-strict", TokenType.String, "on"] }); }); @@ -61,11 +61,11 @@ describe("find-token", () => { expect(testFindToken(`on: pu|sh`)).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "on"] + ["on-strict", TokenType.String, "on"] ], parent: ["workflow-root-strict", TokenType.Mapping], - key: [null, TokenType.String, "on"], - token: ["on-strict", TokenType.String, "push"] + key: ["on-strict", TokenType.String, "on"], + token: ["push-string", TokenType.String, "push"] }); }); @@ -76,12 +76,12 @@ describe("find-token", () => { ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "on"], + ["on-strict", TokenType.String, "on"], ["on-mapping-strict", TokenType.Mapping] ], parent: ["on-mapping-strict", TokenType.Mapping], key: null, - token: [null, TokenType.String, "push"] + token: ["push", TokenType.String, "push"] }); }); @@ -92,12 +92,12 @@ describe("find-token", () => { ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "on"], - ["on-strict", TokenType.Sequence] + ["on-strict", TokenType.String, "on"], + ["on-sequence-strict", TokenType.Sequence] ], - parent: ["on-strict", TokenType.Sequence], + parent: ["on-sequence-strict", TokenType.Sequence], key: null, - token: ["non-empty-string", TokenType.String, "push"] + token: ["push-string", TokenType.String, "push"] }); }); @@ -108,10 +108,10 @@ describe("find-token", () => { ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "on"], - ["on-strict", TokenType.Sequence] + ["on-strict", TokenType.String, "on"], + ["on-sequence-strict", TokenType.Sequence] ], - parent: ["on-strict", TokenType.Sequence], + parent: ["on-sequence-strict", TokenType.Sequence], key: null, token: null }); @@ -125,12 +125,12 @@ describe("find-token", () => { ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "on"], - ["on-strict", TokenType.Sequence] + ["on-strict", TokenType.String, "on"], + ["on-sequence-strict", TokenType.Sequence] ], - parent: ["on-strict", TokenType.Sequence], + parent: ["on-sequence-strict", TokenType.Sequence], key: null, - token: ["non-empty-string", TokenType.String, "pull_request"] + token: ["pull-request-string", TokenType.String, "pull_request"] }); }); @@ -143,14 +143,14 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"], ["job-factory", TokenType.Mapping], - [null, TokenType.String, "runs-on"], - ["runs-on", TokenType.Sequence] + ["runs-on", TokenType.String, "runs-on"], + ["sequence-of-non-empty-string", TokenType.Sequence] ], - parent: ["runs-on", TokenType.Sequence], + parent: ["sequence-of-non-empty-string", TokenType.Sequence], key: null, token: ["non-empty-string", TokenType.String, "self"] }); @@ -165,7 +165,7 @@ jo|bs: path: [["workflow-root-strict", TokenType.Mapping]], parent: ["workflow-root-strict", TokenType.Mapping], key: null, - token: [null, TokenType.String, "jobs"] + token: ["jobs", TokenType.String, "jobs"] }); }); @@ -178,15 +178,15 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"], ["job-factory", TokenType.Mapping], - [null, TokenType.String, "runs-on"] + ["runs-on", TokenType.String, "runs-on"] ], parent: ["job-factory", TokenType.Mapping], - key: [null, TokenType.String, "runs-on"], - token: ["runs-on", TokenType.String, "ubu"] + key: ["runs-on", TokenType.String, "runs-on"], + token: ["non-empty-string", TokenType.String, "ubu"] }); }); @@ -199,14 +199,14 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"], ["job-factory", TokenType.Mapping] ], parent: ["job-factory", TokenType.Mapping], key: null, - token: [null, TokenType.String, "runs-on"] + token: ["runs-on", TokenType.String, "runs-on"] }); }); @@ -219,14 +219,14 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"], ["job-factory", TokenType.Mapping] ], parent: ["job-factory", TokenType.Mapping], - key: [null, TokenType.String, "continue-on-error"], - token: ["boolean-strategy-context", TokenType.Null, ""] + key: ["boolean-strategy-context", TokenType.String, "continue-on-error"], + token: [null, TokenType.Null, ""] }); }); @@ -239,14 +239,14 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"], ["job-factory", TokenType.Mapping] ], parent: ["job-factory", TokenType.Mapping], - key: [null, TokenType.String, "container"], - token: ["container", TokenType.String, ""] + key: ["container", TokenType.String, "container"], + token: ["string", TokenType.String, ""] }); }); @@ -259,13 +259,13 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"] ], parent: ["jobs", TokenType.Mapping], key: ["job-id", TokenType.String, "build"], - token: ["job", TokenType.String, "continue-on-error:foo"] + token: [null, TokenType.String, "continue-on-error:foo"] }); }); @@ -278,7 +278,7 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"], ["job-factory", TokenType.Mapping] @@ -298,14 +298,14 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"], ["job-factory", TokenType.Mapping] ], parent: ["job-factory", TokenType.Mapping], key: null, - token: [null, TokenType.String, "continue-on-error"] + token: ["boolean-strategy-context", TokenType.String, "continue-on-error"] }); }); @@ -318,13 +318,13 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"] ], parent: ["jobs", TokenType.Mapping], key: ["job-id", TokenType.String, "build"], - token: ["job", TokenType.String, "runs-"] + token: [null, TokenType.String, "runs-"] }); }); @@ -338,13 +338,13 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"] ], parent: ["jobs", TokenType.Mapping], key: ["job-id", TokenType.String, "build"], - token: ["job", TokenType.String, "runs-"] + token: [null, TokenType.String, "runs-"] }); }); @@ -358,15 +358,15 @@ jobs: ).toEqual({ path: [ ["workflow-root-strict", TokenType.Mapping], - [null, TokenType.String, "jobs"], + ["jobs", TokenType.String, "jobs"], ["jobs", TokenType.Mapping], ["job-id", TokenType.String, "build"], ["job-factory", TokenType.Mapping], - [null, TokenType.String, "runs-on"] + ["runs-on", TokenType.String, "runs-on"] ], parent: ["job-factory", TokenType.Mapping], - key: [null, TokenType.String, "runs-on"], - token: ["runs-on", TokenType.String, "ubu"] + key: ["runs-on", TokenType.String, "runs-on"], + token: ["non-empty-string", TokenType.String, "ubu"] }); }); }); diff --git a/actions-languageservice/src/value-providers/definition.ts b/actions-languageservice/src/value-providers/definition.ts index ad3e5d2..4b51d60 100644 --- a/actions-languageservice/src/value-providers/definition.ts +++ b/actions-languageservice/src/value-providers/definition.ts @@ -2,6 +2,7 @@ import {BooleanDefinition} from "@github/actions-workflow-parser/templates/schem import {Definition} from "@github/actions-workflow-parser/templates/schema/definition"; import {MappingDefinition} from "@github/actions-workflow-parser/templates/schema/mapping-definition"; import {OneOfDefinition} from "@github/actions-workflow-parser/templates/schema/one-of-definition"; +import {SequenceDefinition} from "@github/actions-workflow-parser/templates/schema/sequence-definition"; import {StringDefinition} from "@github/actions-workflow-parser/templates/schema/string-definition"; import {getWorkflowSchema} from "@github/actions-workflow-parser/workflows/workflow-schema"; import {Value} from "./config"; @@ -26,6 +27,10 @@ export function definitionValues(def: Definition): Value[] { return stringsToValues([def.constant]); } + if (def instanceof SequenceDefinition && def.itemType && schema.definitions[def.itemType]) { + return definitionValues(schema.definitions[def.itemType]); + } + return []; }