diff --git a/actions-languageserver/src/on-completion.ts b/actions-languageserver/src/on-completion.ts index 892646a..dcb98a4 100644 --- a/actions-languageserver/src/on-completion.ts +++ b/actions-languageserver/src/on-completion.ts @@ -7,7 +7,10 @@ import { Octokit } from "@octokit/rest"; import { CompletionItem, DocumentUri, Position } from "vscode-languageserver"; import { TextDocument } from "vscode-languageserver-textdocument"; import { RepositoryContext } from "./initializationOptions"; +import { getJobNames } from "./value-providers/needs"; import { getRunnerLabels } from "./value-providers/runs-on"; +import { WorkflowTemplate } from "@github/actions-workflow-parser"; + export async function onCompletion( position: Position, @@ -17,8 +20,8 @@ export async function onCompletion( repoWorkflowMap: Map ): Promise { const config: ValueProviderConfig = { - getCustomValues: async (key: string, context: WorkflowContext) => - getCustomValues(key, context, sessionToken, repoWorkflowMap), + getCustomValues: async (key: string, context: WorkflowContext, template: WorkflowTemplate | undefined) => + getCustomValues(key, context, sessionToken, repoWorkflowMap, template), }; return await complete(document, position, config); } @@ -27,7 +30,8 @@ async function getCustomValues( key: string, context: WorkflowContext, sessionToken: string | undefined, - repoWorkspaceMap: Map + repoWorkspaceMap: Map, + template: WorkflowTemplate | undefined ) { if (!sessionToken) { return; @@ -44,4 +48,7 @@ async function getCustomValues( }); return await getRunnerLabels(octokit, repo.owner, repo.name); } + if (key === "needs" && template) { + return await getJobNames(template); + } } diff --git a/actions-languageserver/src/value-providers/needs.ts b/actions-languageserver/src/value-providers/needs.ts new file mode 100644 index 0000000..f1a91ea --- /dev/null +++ b/actions-languageserver/src/value-providers/needs.ts @@ -0,0 +1,19 @@ +import { Value } from "@github/actions-languageservice/value-providers/config"; +import { WorkflowTemplate } from "@github/actions-workflow-parser/model/workflow-template"; + +export async function getJobNames( + template: WorkflowTemplate +): Promise { + const labels = new Set([ + // "dummy-job", + ]); + + const jobsValues = template.jobs.jobNames; + if (jobsValues) { + for (const job of jobsValues?.values() || []) { + labels.add(job); + } + } + + return Array.from(labels).map((label) => ({ label })); +} diff --git a/actions-languageservice/src/complete.ts b/actions-languageservice/src/complete.ts index ff4333c..6c9a3d8 100644 --- a/actions-languageservice/src/complete.ts +++ b/actions-languageservice/src/complete.ts @@ -1,4 +1,4 @@ -import { parseWorkflow } from "@github/actions-workflow-parser"; +import { convertWorkflowTemplate, parseWorkflow, WorkflowTemplate } from "@github/actions-workflow-parser"; import { SEQUENCE_TYPE, STRING_TYPE, @@ -31,16 +31,24 @@ export async function complete( content: newDoc.getText(), }; const result = parseWorkflow(file.name, [file], nullTrace); - const [innerToken, parent] = findInnerTokenAndParent(newPos, result.value); + let template: WorkflowTemplate | undefined = undefined; + const valueToRemove = parent?.definition?.keyname; + if (result.value) { + template = convertWorkflowTemplate(result.context, result.value); + console.log("template", template); + } + const values = await getValues( innerToken, parent, newPos, textDocument.uri, - valueProviderConfig + valueProviderConfig, + template, ); - return values.map((value) => CompletionItem.create(value.label)); + const valuesFiltered = values.filter((x) => x.label !== valueToRemove); + return valuesFiltered.map((value) => CompletionItem.create(value.label)); } async function getValues( @@ -48,7 +56,8 @@ async function getValues( parent: TemplateToken | null, position: Position, workflowUri: string, - valueProviderConfig: ValueProviderConfig | undefined + valueProviderConfig: ValueProviderConfig | undefined, + template: WorkflowTemplate | undefined, ): Promise { if (!parent) { return []; @@ -62,16 +71,21 @@ async function getValues( } const existingValues = getExistingValues(token, parent); + console.log("Parent", parent); + console.log("Token", token); let customValues: Value[] | undefined = undefined; if (token?.definition?.key) { customValues = await valueProviderConfig?.getCustomValues( token.definition.key, - { uri: workflowUri } + { uri: workflowUri }, + template, ); + // add to custom values? } if (customValues !== undefined) { + console.log("filterAndSortCompletionOptions with customValues") return filterAndSortCompletionOptions(customValues, existingValues); } @@ -87,6 +101,7 @@ async function getValues( } const values = valueProvider(); + console.log("filterAndSortCompletionOptions with values") return filterAndSortCompletionOptions(values, existingValues); } diff --git a/actions-languageservice/src/utils/find-token.ts b/actions-languageservice/src/utils/find-token.ts index 0faefea..6b3ed9c 100644 --- a/actions-languageservice/src/utils/find-token.ts +++ b/actions-languageservice/src/utils/find-token.ts @@ -47,7 +47,10 @@ export function findInnerTokenAndParent( if (nullNodeOnLine(pos, key, value)) { return [value, key]; } - + //value.definition?.keyname = key.value; + if (value.definition){ + value.definition.keyname = key.toString(); + } s.push(value); } continue; @@ -74,8 +77,8 @@ function posInToken(pos: Position, token: TemplateToken): boolean { const r = token.range; // TokenRange is one-based, Position is zero-based - const tokenLine = pos.line + 1; - const tokenChar = pos.character + 1; + const tokenLine = pos.line //+ 1; + const tokenChar = pos.character //+ 1; // Check lines if (r.start[0] > tokenLine || tokenLine > r.end[0]) { diff --git a/actions-languageservice/src/value-providers/config.ts b/actions-languageservice/src/value-providers/config.ts index 7ef28b7..baecf7a 100644 --- a/actions-languageservice/src/value-providers/config.ts +++ b/actions-languageservice/src/value-providers/config.ts @@ -1,3 +1,5 @@ +import { WorkflowTemplate } from "@github/actions-workflow-parser/model/workflow-template"; + export interface Value { label: string; description?: string; @@ -11,7 +13,8 @@ export interface WorkflowContext { export interface ValueProviderConfig { getCustomValues: ( key: string, - context: WorkflowContext + context: WorkflowContext, + template: WorkflowTemplate | undefined ) => Promise; getActionInputs?: ( owner: string, diff --git a/actions-languageservice/src/value-providers/needs.ts b/actions-languageservice/src/value-providers/needs.ts new file mode 100644 index 0000000..b26918d --- /dev/null +++ b/actions-languageservice/src/value-providers/needs.ts @@ -0,0 +1,19 @@ +import { Value } from "./config"; +import { WorkflowTemplate } from "@github/actions-workflow-parser/model/workflow-template"; + +export async function getJobNames( + template: WorkflowTemplate +): Promise { + const labels = new Set([ + "dummy-job", + ]); + + const jobsValues = template.jobs.jobNames; + if (jobsValues) { + for (const job of jobsValues?.values() || []) { + labels.add(job); + } + } + + return Array.from(labels).map((label) => ({ label })); +}