diff --git a/actions-languageserver/src/context-providers.ts b/actions-languageserver/src/context-providers.ts index bc45283..c0824ce 100644 --- a/actions-languageserver/src/context-providers.ts +++ b/actions-languageserver/src/context-providers.ts @@ -1,7 +1,6 @@ -import {data, DescriptionDictionary} from "@github/actions-expressions"; +import {DescriptionDictionary} from "@github/actions-expressions"; import {ContextProviderConfig} from "@github/actions-languageservice"; import {WorkflowContext} from "@github/actions-languageservice/context/workflow-context"; -import {isMapping, isString} from "@github/actions-workflow-parser"; import {Octokit} from "@octokit/rest"; import {getSecrets} from "./context-providers/secrets"; import {getStepsContext} from "./context-providers/steps"; @@ -27,43 +26,11 @@ export function contextProviders( workflowContext: WorkflowContext ) => { switch (name) { - case "secrets": { - let environmentName: string | undefined; - if (workflowContext?.job?.environment) { - if (isString(workflowContext.job.environment)) { - environmentName = workflowContext.job.environment.value; - } else if (isMapping(workflowContext.job.environment)) { - for (const x of workflowContext.job.environment) { - if (isString(x.key) && x.key.value === "name") { - if (isString(x.value)) { - environmentName = x.value.value; - } - break; - } - } - } - } + case "secrets": + return await getSecrets(workflowContext, octokit, cache, repo, defaultContext); - const secrets = await getSecrets(octokit, cache, repo, environmentName); - - defaultContext = defaultContext || new DescriptionDictionary(); - secrets.repoSecrets - .sort((a, b) => a.value.localeCompare(b.value)) - .forEach(secret => defaultContext!.add(secret.value, new data.StringData("***"), "Repository secret")); - secrets.environmentSecrets - .sort((a, b) => a.value.localeCompare(b.value)) - .forEach(secret => - defaultContext!.add( - secret.value, - new data.StringData("***"), - `Secret for environment \`${environmentName}\`` - ) - ); - return defaultContext; - } - case "steps": { + case "steps": return await getStepsContext(octokit, cache, defaultContext, workflowContext); - } } }; diff --git a/actions-languageserver/src/context-providers/secrets.ts b/actions-languageserver/src/context-providers/secrets.ts index 25b923f..c8c262a 100644 --- a/actions-languageserver/src/context-providers/secrets.ts +++ b/actions-languageserver/src/context-providers/secrets.ts @@ -1,9 +1,74 @@ +import {data, DescriptionDictionary} from "@github/actions-expressions"; import {StringData} from "@github/actions-expressions/data/string"; +import {WorkflowContext} from "@github/actions-languageservice/context/workflow-context"; +import {isMapping, isString} from "@github/actions-workflow-parser"; import {Octokit} from "@octokit/rest"; import {RepositoryContext} from "../initializationOptions"; import {TTLCache} from "../utils/cache"; export async function getSecrets( + workflowContext: WorkflowContext, + octokit: Octokit, + cache: TTLCache, + repo: RepositoryContext, + defaultContext: DescriptionDictionary | undefined +): Promise { + let environmentName: string | undefined; + if (workflowContext?.job?.environment) { + if (isString(workflowContext.job.environment)) { + environmentName = workflowContext.job.environment.value; + } else if (isMapping(workflowContext.job.environment)) { + for (const x of workflowContext.job.environment) { + if (isString(x.key) && x.key.value === "name") { + if (isString(x.value)) { + environmentName = x.value.value; + } + break; + } + } + } + } + + const secrets = await getRemoteSecrets(octokit, cache, repo, environmentName); + + // Build combined map of secrets + const secretsMap = new Map< + string, + { + key: string; + value: data.StringData; + description?: string; + } + >(); + + secrets.repoSecrets.forEach(secret => + secretsMap.set(secret.value.toLowerCase(), { + key: secret.value, + value: new data.StringData("***"), + description: "Repository secret" + }) + ); + + // Override repo secrets with environment secrets (if defined) + secrets.environmentSecrets.forEach(secret => + secretsMap.set(secret.value.toLowerCase(), { + key: secret.value, + value: new data.StringData("***"), + description: `Secret for environment \`${environmentName}\`` + }) + ); + + const secretsContext = defaultContext || new DescriptionDictionary(); + + // Sort secrets by key and add to context + Array.from(secretsMap.values()) + .sort((a, b) => a.key.localeCompare(b.key)) + .forEach(secret => secretsContext?.add(secret.key, secret.value, secret.description)); + + return secretsContext; +} + +async function getRemoteSecrets( octokit: Octokit, cache: TTLCache, repo: RepositoryContext,