From 73883d1d175613cc6b7d3cc31aab823fae7caca7 Mon Sep 17 00:00:00 2001 From: Jaryt Bustard Date: Mon, 25 Jul 2022 17:46:05 -0400 Subject: [PATCH] feat: Parse pre-steps and post-steps for Workflows --- .../Components/Workflow/exports/Workflow.ts | 10 +++++-- .../Workflow/exports/WorkflowJob.ts | 27 +++++++++++++++++ .../Workflow/exports/WorkflowJobAbstract.ts | 19 ++---------- src/lib/Components/Workflow/parsers/index.ts | 30 +++++++++++++++++-- .../Workflow/types/Workflow.types.ts | 8 +++-- .../Workflow/types/WorkflowJob.types.ts | 6 +--- tests/Workflow.test.ts | 17 +++++++---- 7 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/lib/Components/Workflow/exports/Workflow.ts b/src/lib/Components/Workflow/exports/Workflow.ts index 4522218..8ad0bf2 100644 --- a/src/lib/Components/Workflow/exports/Workflow.ts +++ b/src/lib/Components/Workflow/exports/Workflow.ts @@ -1,5 +1,6 @@ import { Generable } from '../..'; import { GenerableType } from '../../../Config/exports/Mapping'; +import { Command } from '../../Commands/exports/Command'; import { Job } from '../../Job'; import { When } from '../../Logic'; import { Conditional } from '../../Logic/exports/Conditional'; @@ -68,8 +69,13 @@ export class Workflow implements Generable, Conditional { /** * Add a Job to the current Workflow. Chainable */ - addJob(job: Job, parameters?: WorkflowJobParameters): this { - this.jobs.push(new WorkflowJob(job, parameters)); + addJob( + job: Job, + parameters?: WorkflowJobParameters, + pre_steps?: Command[], + post_steps?: Command[], + ): this { + this.jobs.push(new WorkflowJob(job, parameters, pre_steps, post_steps)); return this; } diff --git a/src/lib/Components/Workflow/exports/WorkflowJob.ts b/src/lib/Components/Workflow/exports/WorkflowJob.ts index e5e33c7..7429828 100644 --- a/src/lib/Components/Workflow/exports/WorkflowJob.ts +++ b/src/lib/Components/Workflow/exports/WorkflowJob.ts @@ -1,7 +1,10 @@ import { OrbRef } from '../../../Orb/exports/OrbRef'; +import { AnyCommandShape } from '../../Commands/types/Command.types'; import { Job } from '../../Job'; +import { StepsParameter } from '../../Parameters/types'; import { JobParameterLiteral } from '../../Parameters/types/CustomParameterLiterals.types'; import { + WorkflowJobContentsShape, WorkflowJobParameters, WorkflowJobShape, } from '../types/WorkflowJob.types'; @@ -16,12 +19,19 @@ import { WorkflowJobAbstract } from './WorkflowJobAbstract'; export class WorkflowJob extends WorkflowJobAbstract { job: Job | OrbRef; + pre_steps?: StepsParameter; + post_steps?: StepsParameter; + constructor( job: Job | OrbRef, parameters?: Exclude, + pre_steps?: StepsParameter, + post_steps?: StepsParameter, ) { super(parameters); this.job = job; + this.pre_steps = pre_steps; + this.post_steps = post_steps; } generate(flatten?: boolean): WorkflowJobShape { @@ -29,12 +39,29 @@ export class WorkflowJob extends WorkflowJobAbstract { return this.job.name; } + console.log(this.generateContents(flatten)); + return { [this.job.name]: this.generateContents(flatten), }; } + generateContents(flatten?: boolean): WorkflowJobContentsShape { + return { + ...super.generateContents(flatten), + 'pre-steps': this.generateSteps(this.pre_steps, flatten), + 'post-steps': this.generateSteps(this.post_steps, flatten), + }; + } + get name(): string { return this.job.name; } + + private generateSteps( + steps?: StepsParameter, + flatten?: boolean, + ): AnyCommandShape[] | undefined { + return steps?.map((step) => step.generate(flatten)); + } } diff --git a/src/lib/Components/Workflow/exports/WorkflowJobAbstract.ts b/src/lib/Components/Workflow/exports/WorkflowJobAbstract.ts index 61335ce..1f7418b 100644 --- a/src/lib/Components/Workflow/exports/WorkflowJobAbstract.ts +++ b/src/lib/Components/Workflow/exports/WorkflowJobAbstract.ts @@ -1,7 +1,5 @@ import { GenerableType } from '../../../Config/exports/Mapping'; -import { AnyCommandShape } from '../../Commands/types/Command.types'; import { Generable } from '../../index'; -import { StepsParameter } from '../../Parameters/types'; import { WorkflowJobContentsShape, WorkflowJobParameters, @@ -22,17 +20,13 @@ export abstract class WorkflowJobAbstract implements Generable { this.parameters = parameters; } + // eslint-disable-next-line @typescript-eslint/no-unused-vars generateContents(flatten?: boolean): WorkflowJobContentsShape { let parameters: WorkflowJobParametersShape | undefined; if (this.parameters) { - const { matrix, pre_steps, post_steps, ...jobParameters } = - this.parameters; - parameters = { - ...jobParameters, - 'pre-steps': this.generateSteps(pre_steps, flatten), - 'post-steps': this.generateSteps(post_steps, flatten), - }; + const { matrix, ...jobParameters } = this.parameters; + parameters = jobParameters; if (matrix) { parameters.matrix = { @@ -48,13 +42,6 @@ export abstract class WorkflowJobAbstract implements Generable { return GenerableType.WORKFLOW_JOB; } - private generateSteps( - steps?: StepsParameter, - flatten?: boolean, - ): AnyCommandShape[] | undefined { - return steps?.map((step) => step.generate(flatten)); - } - abstract get name(): string; abstract generate(flatten?: boolean): WorkflowJobShape; } diff --git a/src/lib/Components/Workflow/parsers/index.ts b/src/lib/Components/Workflow/parsers/index.ts index b21fe48..9ea1799 100644 --- a/src/lib/Components/Workflow/parsers/index.ts +++ b/src/lib/Components/Workflow/parsers/index.ts @@ -1,5 +1,6 @@ import { GenerableType } from '../../../Config/exports/Mapping'; import { errorParsing, parseGenerable } from '../../../Config/exports/Parsing'; +import { parseSteps } from '../../Commands/parsers'; import { Job } from '../../Job'; import { Workflow } from '../exports/Workflow'; import { WorkflowJob } from '../exports/WorkflowJob'; @@ -9,6 +10,7 @@ import { UnknownWorkflowJobShape, UnknownWorkflowShape, WorkflowDependencies, + WorkflowJobParameters, } from '../types'; /** @@ -29,14 +31,38 @@ export function parseWorkflowJob( GenerableType.WORKFLOW_JOB, workflowJobIn, (workflowJobArgs) => { + let args = workflowJobArgs; + let parsedPresteps, parsedPoststeps; + + if (args) { + if ('pre-steps' in args) { + const { 'pre-steps': steps, ...argsRestTemp } = args; + parsedPresteps = parseSteps(steps); + args = argsRestTemp; + } + + if ('post-steps' in args) { + const { 'post-steps': steps, ...argsRestTemp } = args; + parsedPoststeps = parseSteps(steps); + args = argsRestTemp; + } + } + + const parameters = args as WorkflowJobParameters | undefined; + if (workflowJobArgs?.type === 'approval') { - return new WorkflowJobApproval(name, workflowJobArgs); + return new WorkflowJobApproval(name, parameters); } const job = jobs.find((c) => c.name === name); if (job) { - return new WorkflowJob(job, workflowJobArgs); + return new WorkflowJob( + job, + parameters, + parsedPresteps, + parsedPoststeps, + ); } throw errorParsing(`Job ${name} not found in config`); diff --git a/src/lib/Components/Workflow/types/Workflow.types.ts b/src/lib/Components/Workflow/types/Workflow.types.ts index 70c3ec3..30eca82 100644 --- a/src/lib/Components/Workflow/types/Workflow.types.ts +++ b/src/lib/Components/Workflow/types/Workflow.types.ts @@ -15,11 +15,13 @@ export type UnknownWorkflowShape = { export type UnknownWorkflowJobShape = { requires?: string[]; - parameters?: { [key: string]: unknown }; + parameters?: { + [key: string]: unknown; + }; + 'pre-steps'?: unknown[]; + 'post-steps'?: unknown[]; name?: string; type?: 'approval'; - // 'pre-steps'?: { [key: string]: unknown }[]; - // 'post-steps'?: { [key: string]: unknown }[]; }; export type WorkflowDependencies = { diff --git a/src/lib/Components/Workflow/types/WorkflowJob.types.ts b/src/lib/Components/Workflow/types/WorkflowJob.types.ts index 7e9858c..b3c2fbf 100644 --- a/src/lib/Components/Workflow/types/WorkflowJob.types.ts +++ b/src/lib/Components/Workflow/types/WorkflowJob.types.ts @@ -1,15 +1,14 @@ +import { AnyCommandShape } from '../../Commands/types/Command.types'; import { FilterParameter, ListParameter, MatrixParameter, - StepsParameter, StringParameter, } from '../../Parameters/types'; import { ComponentParameter, JobParameterTypes, } from '../../Parameters/types/ComponentParameters.types'; -import { AnyCommandShape } from '../../Commands/types/Command.types'; /** * CircleCI provided parameters for all workflow jobs @@ -35,9 +34,6 @@ export interface WorkflowJobParameters * An "approval" type job is a special job which pauses the workflow. This "job" is not defined outside of the workflow, you may enter any potential name for the job name. As long as the parameter of "type" is present and equal to "approval" this job will act as a placeholder that awaits user input to continue. */ type?: approval; - - pre_steps?: StepsParameter; - post_steps?: StepsParameter; } export type approval = 'approval'; diff --git a/tests/Workflow.test.ts b/tests/Workflow.test.ts index 7e8f655..e9e44b5 100644 --- a/tests/Workflow.test.ts +++ b/tests/Workflow.test.ts @@ -341,11 +341,14 @@ describe('Add pre/post steps to workflow', () => { }); const job = new CircleCI.Job('my-job', docker, [helloWorld]); const myWorkflow = new CircleCI.Workflow('my-workflow'); - myWorkflow.addJob(job, { - name: 'custom-name', - pre_steps: [helloWorld], - post_steps: [helloWorld], - }); + myWorkflow.addJob( + job, + { + name: 'custom-name', + }, + [helloWorld], + [helloWorld], + ); it('Should match the expected output', () => { const expected = { 'my-workflow': { @@ -361,6 +364,10 @@ describe('Add pre/post steps to workflow', () => { }, }; const generatedWorkflow = myWorkflow.generate(true); + expect(generatedWorkflow).toEqual(expected); + expect(CircleCI.parsers.parseWorkflowList(expected, [job])[0]).toEqual( + myWorkflow, + ); }); });