From 986ce1bfe45a27a2f9e622a6d2bb7052fa5c576d Mon Sep 17 00:00:00 2001 From: Josh Gross Date: Fri, 3 Feb 2023 17:52:48 -0500 Subject: [PATCH] Separate reusable jobs in the workflow context --- .../src/context-providers/secrets.ts | 13 +++++-------- .../src/context-providers/steps.ts | 7 +++---- .../src/context-providers/variables.ts | 13 +++++-------- .../src/test-utils/workflow-context.ts | 5 ++--- .../src/context-providers/env.ts | 6 ++---- .../src/context-providers/job.ts | 3 +-- .../src/context-providers/needs.ts | 5 +++-- .../src/context-providers/steps.ts | 3 +-- .../src/context/workflow-context.ts | 19 +++++++++++++++---- 9 files changed, 37 insertions(+), 37 deletions(-) diff --git a/actions-languageserver/src/context-providers/secrets.ts b/actions-languageserver/src/context-providers/secrets.ts index 85ad93d..61c6ca0 100644 --- a/actions-languageserver/src/context-providers/secrets.ts +++ b/actions-languageserver/src/context-providers/secrets.ts @@ -2,7 +2,6 @@ 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 {isJob} from "@github/actions-workflow-parser/model/type-guards"; import {Octokit} from "@octokit/rest"; import {RepositoryContext} from "../initializationOptions"; import {TTLCache} from "../utils/cache"; @@ -15,13 +14,11 @@ export async function getSecrets( defaultContext: DescriptionDictionary | undefined ): Promise { let environmentName: string | undefined; - const job = workflowContext?.job; - const environment = job && isJob(job) && job.environment; - if (environment) { - if (isString(environment)) { - environmentName = environment.value; - } else if (isMapping(environment)) { - for (const x of environment) { + 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; diff --git a/actions-languageserver/src/context-providers/steps.ts b/actions-languageserver/src/context-providers/steps.ts index a3bed5e..eea315b 100644 --- a/actions-languageserver/src/context-providers/steps.ts +++ b/actions-languageserver/src/context-providers/steps.ts @@ -1,7 +1,7 @@ import {data, DescriptionDictionary, isDescriptionDictionary} from "@github/actions-expressions"; import {parseActionReference} from "@github/actions-languageservice/action"; import {WorkflowContext} from "@github/actions-languageservice/context/workflow-context"; -import {isActionStep, isReusableWorkflowJob} from "@github/actions-workflow-parser/model/type-guards"; +import {isActionStep} from "@github/actions-workflow-parser/model/type-guards"; import {Octokit} from "@octokit/rest"; import {TTLCache} from "../utils/cache"; import {getActionOutputs} from "./action-outputs"; @@ -12,8 +12,7 @@ export async function getStepsContext( defaultContext: DescriptionDictionary | undefined, workflowContext: WorkflowContext ): Promise { - const job = workflowContext.job; - if (!defaultContext || !job || isReusableWorkflowJob(job)) { + if (!defaultContext || !workflowContext.job) { return defaultContext; } @@ -27,7 +26,7 @@ export async function getStepsContext( // Copy the default context for each step // If the step is an action, add the action outputs to the context const stepsContext = new DescriptionDictionary(); - for (const step of job.steps) { + for (const step of workflowContext.job.steps) { if (!contextSteps.has(step.id)) { continue; } diff --git a/actions-languageserver/src/context-providers/variables.ts b/actions-languageserver/src/context-providers/variables.ts index d14b20b..52babbd 100644 --- a/actions-languageserver/src/context-providers/variables.ts +++ b/actions-languageserver/src/context-providers/variables.ts @@ -6,7 +6,6 @@ import {Pair} from "@github/actions-expressions/data/expressiondata"; import {RepositoryContext} from "../initializationOptions"; import {StringData} from "@github/actions-expressions/data/index"; import {TTLCache} from "../utils/cache"; -import {isJob} from "@github/actions-workflow-parser/model/type-guards"; export async function getVariables( workflowContext: WorkflowContext, @@ -16,13 +15,11 @@ export async function getVariables( defaultContext: DescriptionDictionary | undefined ): Promise { let environmentName: string | undefined; - const job = workflowContext?.job; - const environment = job && isJob(job) && job.environment; - if (environment) { - if (isString(environment)) { - environmentName = environment.value; - } else if (isMapping(environment)) { - for (const x of environment) { + 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; diff --git a/actions-languageserver/src/test-utils/workflow-context.ts b/actions-languageserver/src/test-utils/workflow-context.ts index 44b3654..aef5cfe 100644 --- a/actions-languageserver/src/test-utils/workflow-context.ts +++ b/actions-languageserver/src/test-utils/workflow-context.ts @@ -1,6 +1,5 @@ import {WorkflowContext} from "@github/actions-languageservice/context/workflow-context"; import {convertWorkflowTemplate, parseWorkflow, TraceWriter} from "@github/actions-workflow-parser"; -import {isJob} from "@github/actions-workflow-parser/model/type-guards"; const nullTrace: TraceWriter = { info: x => {}, @@ -20,8 +19,8 @@ export function createWorkflowContext(workflow: string, job?: string, stepIndex? context.job = template.jobs.find(j => j.id.value === job); } - if (stepIndex !== undefined && context.job && isJob(context.job)) { - context.step = context.job.steps[stepIndex]; + if (stepIndex !== undefined) { + context.step = context.job?.steps[stepIndex]; } return context; diff --git a/actions-languageservice/src/context-providers/env.ts b/actions-languageservice/src/context-providers/env.ts index 8aaeaf4..5aa22cb 100644 --- a/actions-languageservice/src/context-providers/env.ts +++ b/actions-languageservice/src/context-providers/env.ts @@ -1,6 +1,5 @@ import {data, DescriptionDictionary} from "@github/actions-expressions"; import {isScalar, isString} from "@github/actions-workflow-parser"; -import {isJob} from "@github/actions-workflow-parser/model/type-guards"; import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/mapping-token"; import {WorkflowContext} from "../context/workflow-context"; @@ -13,9 +12,8 @@ export function getEnvContext(workflowContext: WorkflowContext): DescriptionDict } //job env - const job = workflowContext.job; - if (job && isJob(job) && job.env) { - envContext(job.env, d); + if (workflowContext.job && workflowContext.job.env) { + envContext(workflowContext.job.env, d); } //workflow env diff --git a/actions-languageservice/src/context-providers/job.ts b/actions-languageservice/src/context-providers/job.ts index 5adf7e4..6c37ab6 100644 --- a/actions-languageservice/src/context-providers/job.ts +++ b/actions-languageservice/src/context-providers/job.ts @@ -1,6 +1,5 @@ import {data, DescriptionDictionary} from "@github/actions-expressions"; import {isMapping, isSequence} from "@github/actions-workflow-parser"; -import {isReusableWorkflowJob} from "@github/actions-workflow-parser/model/type-guards"; import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/mapping-token"; import {WorkflowContext} from "../context/workflow-context"; @@ -8,7 +7,7 @@ export function getJobContext(workflowContext: WorkflowContext): DescriptionDict // https://docs.github.com/en/actions/learn-github-actions/contexts#job-context const jobContext = new DescriptionDictionary(); const job = workflowContext.job; - if (!job || isReusableWorkflowJob(job)) { + if (!job) { return jobContext; } diff --git a/actions-languageservice/src/context-providers/needs.ts b/actions-languageservice/src/context-providers/needs.ts index 455bfd5..e261b0d 100644 --- a/actions-languageservice/src/context-providers/needs.ts +++ b/actions-languageservice/src/context-providers/needs.ts @@ -25,14 +25,15 @@ function needsJobContext(job?: WorkflowJob): DescriptionDictionary { if (job && isJob(job)) { d.add("outputs", jobOutputs(job)); } + // Can be "success", "failure", "cancelled", or "skipped" d.add("result", new data.Null()); return d; } -function jobOutputs(job: Job): DescriptionDictionary { +function jobOutputs(job?: Job): DescriptionDictionary { const d = new DescriptionDictionary(); - if (!job.outputs) { + if (!job?.outputs) { return d; } diff --git a/actions-languageservice/src/context-providers/steps.ts b/actions-languageservice/src/context-providers/steps.ts index fb2d76d..b07b18e 100644 --- a/actions-languageservice/src/context-providers/steps.ts +++ b/actions-languageservice/src/context-providers/steps.ts @@ -1,12 +1,11 @@ import {data, DescriptionDictionary} from "@github/actions-expressions"; -import {isReusableWorkflowJob} from "@github/actions-workflow-parser/model/type-guards"; import {Step} from "@github/actions-workflow-parser/model/workflow-template"; import {WorkflowContext} from "../context/workflow-context"; import {getDescription} from "./descriptions"; export function getStepsContext(workflowContext: WorkflowContext): DescriptionDictionary { const d = new DescriptionDictionary(); - if (!workflowContext.job || isReusableWorkflowJob(workflowContext.job)) { + if (!workflowContext.job?.steps) { return d; } diff --git a/actions-languageservice/src/context/workflow-context.ts b/actions-languageservice/src/context/workflow-context.ts index 2b77a24..c4c20af 100644 --- a/actions-languageservice/src/context/workflow-context.ts +++ b/actions-languageservice/src/context/workflow-context.ts @@ -1,6 +1,6 @@ import {isMapping, isSequence, WorkflowTemplate} from "@github/actions-workflow-parser"; import {isJob, isReusableWorkflowJob} from "@github/actions-workflow-parser/model/type-guards"; -import {Step, WorkflowJob} from "@github/actions-workflow-parser/model/workflow-template"; +import {Step, Job, ReusableWorkflowJob} from "@github/actions-workflow-parser/model/workflow-template"; import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/mapping-token"; import {SequenceToken} from "@github/actions-workflow-parser/templates/tokens/sequence-token"; import {StringToken} from "@github/actions-workflow-parser/templates/tokens/string-token"; @@ -11,8 +11,11 @@ export interface WorkflowContext { template: WorkflowTemplate | undefined; - /** If the context is for a position within a job, this will be the job */ - job?: WorkflowJob; + /** If the context is for a position within a regular job, this will be the job */ + job?: Job; + + /** If the context is for a position within a reusable workflow job, this will be the reusable workflow job */ + reusableWorkflowJob?: ReusableWorkflowJob; /** If the context is for a position within a step, this will be the step */ step?: Step; @@ -36,7 +39,15 @@ export function getWorkflowContext( switch (token.definition?.key) { case "job": { const jobID = (token as StringToken).value; - context.job = template.jobs.find(job => job.id.value === jobID); + const job = template.jobs.find(job => job.id.value === jobID); + if (!job) { + break; + } + if (isJob(job)) { + context.job = job; + } else if (isReusableWorkflowJob(job)) { + context.reusableWorkflowJob = job; + } break; } case "steps": {