diff --git a/packages/aws-cdk-lib/aws-codepipeline/lib/pipeline.ts b/packages/aws-cdk-lib/aws-codepipeline/lib/pipeline.ts index ab75f29c2e4c1..b8a0e732b18e3 100644 --- a/packages/aws-cdk-lib/aws-codepipeline/lib/pipeline.ts +++ b/packages/aws-cdk-lib/aws-codepipeline/lib/pipeline.ts @@ -494,8 +494,6 @@ export class Pipeline extends PipelineBase { Annotations.of(this).addWarningV2('@aws-cdk/aws-codepipeline:unspecifiedPipelineType', 'V1 pipeline type is implicitly selected when `pipelineType` is not set. If you want to use V2 type, set `PipelineType.V2`.'); } this.pipelineType = props.pipelineType ?? PipelineType.V1; - this.variables = props.variables ?? []; - this.triggers = props.triggers?.map(trigger => this.addTrigger(trigger)) ?? []; this.codePipeline = new CfnPipeline(this, 'Resource', { artifactStore: Lazy.any({ produce: () => this.renderArtifactStoreProperty() }), @@ -534,6 +532,12 @@ export class Pipeline extends PipelineBase { for (const stage of props.stages || []) { this.addStage(stage); } + for (const variable of props.variables || []) { + this.addVariable(variable); + } + for (const trigger of props.triggers || []) { + this.addTrigger(trigger); + } this.node.addValidation({ validate: () => this.validatePipeline() }); } @@ -572,9 +576,16 @@ export class Pipeline extends PipelineBase { * Adds a new Variable to this Pipeline. * * @param variable Variable instance to add to this Pipeline + * @returns the newly created variable */ - public addVariable(variable: Variable) { + public addVariable(variable: Variable): Variable { + // check for duplicate variables and names + if (this.variables.find(v => v.variableName === variable.variableName)) { + throw new Error(`Variable with duplicate name '${variable.variableName}' added to the Pipeline`); + } + this.variables.push(variable); + return variable; } /** @@ -585,6 +596,13 @@ export class Pipeline extends PipelineBase { */ public addTrigger(props: TriggerProps): Trigger { const trigger = new Trigger(props); + const actionName = props.gitConfiguration?.sourceAction.actionProperties.actionName; + + // check for duplicate source actions for triggers + if (actionName !== undefined && this.triggers.find(t => t.sourceAction?.actionProperties.actionName === actionName)) { + throw new Error(`Trigger with duplicate source action '${actionName}' added to the Pipeline`); + } + this.triggers.push(trigger); return trigger; } diff --git a/packages/aws-cdk-lib/aws-codepipeline/lib/trigger.ts b/packages/aws-cdk-lib/aws-codepipeline/lib/trigger.ts index 0809d29f18b3a..9a83e6408f0bb 100644 --- a/packages/aws-cdk-lib/aws-codepipeline/lib/trigger.ts +++ b/packages/aws-cdk-lib/aws-codepipeline/lib/trigger.ts @@ -93,7 +93,13 @@ export interface TriggerProps { * Trigger. */ export class Trigger { + /** + * The pipeline source action where the trigger configuration. + */ + public readonly sourceAction: IAction | undefined; + constructor(private readonly props: TriggerProps) { + this.sourceAction = props.gitConfiguration?.sourceAction; this.validate(); } @@ -147,7 +153,7 @@ export class Trigger { } return { - gitConfiguration: gitConfiguration, + gitConfiguration, providerType: this.props.providerType, }; } diff --git a/packages/aws-cdk-lib/aws-codepipeline/lib/variable.ts b/packages/aws-cdk-lib/aws-codepipeline/lib/variable.ts index 46b139ba1f34b..bddd2598d2100 100644 --- a/packages/aws-cdk-lib/aws-codepipeline/lib/variable.ts +++ b/packages/aws-cdk-lib/aws-codepipeline/lib/variable.ts @@ -31,7 +31,11 @@ export interface VariableProps { * Pipeline-Level variable. */ export class Variable { - private readonly variableName: string; + /** + * The name of a pipeline-level variable. + */ + public readonly variableName: string; + private readonly description?: string; private readonly defaultValue?: string; diff --git a/packages/aws-cdk-lib/aws-codepipeline/test/triggers.test.ts b/packages/aws-cdk-lib/aws-codepipeline/test/triggers.test.ts index 670a31003664e..1970bd42f556c 100644 --- a/packages/aws-cdk-lib/aws-codepipeline/test/triggers.test.ts +++ b/packages/aws-cdk-lib/aws-codepipeline/test/triggers.test.ts @@ -337,6 +337,30 @@ describe('triggers', () => { }).toThrow(/provider for actionProperties in sourceAction with name 'FakeSource' must be 'CodeStarSourceConnection', got 'Fake'/); }); + test('throw if source action with duplicate action name added to the Pipeline', () => { + const pipeline = new codepipeline.Pipeline(stack, 'Pipeline', { + pipelineType: codepipeline.PipelineType.V2, + triggers: [{ + providerType: codepipeline.ProviderType.CODE_STAR_SOURCE_CONNECTION, + gitConfiguration: { + sourceAction, + pushFilter: [{ + excludedTags: ['exclude1', 'exclude2'], + includedTags: ['include1', 'include2'], + }], + }, + }], + }); + expect(() => { + pipeline.addTrigger({ + providerType: codepipeline.ProviderType.CODE_STAR_SOURCE_CONNECTION, + gitConfiguration: { + sourceAction, + }, + }); + }).toThrow(/Trigger with duplicate source action 'CodeStarConnectionsSourceAction' added to the Pipeline/); + }); + test('throw if triggers are specified when pipelineType is not set to V2', () => { const pipeline = new codepipeline.Pipeline(stack, 'Pipeline', { pipelineType: codepipeline.PipelineType.V1, diff --git a/packages/aws-cdk-lib/aws-codepipeline/test/variables.test.ts b/packages/aws-cdk-lib/aws-codepipeline/test/variables.test.ts index 72b2127ccba04..912d89551a44b 100644 --- a/packages/aws-cdk-lib/aws-codepipeline/test/variables.test.ts +++ b/packages/aws-cdk-lib/aws-codepipeline/test/variables.test.ts @@ -338,6 +338,20 @@ describe('variables', () => { }); }).toThrow(/Description for variable 'var-name-1' must not be greater than 200 characters long, got 201/); }); + + test('throw if variable with duplicate name added to the Pipeline', () => { + const pipeline = new codepipeline.Pipeline(stack, 'Pipeline', { + variables: [variable1], + }); + const duplicated = new codepipeline.Variable({ + variableName: 'var-name-1', + description: 'description-dummy', + defaultValue: 'default-dummy', + }); + expect(() => { + pipeline.addVariable(duplicated); + }).toThrow(/Variable with duplicate name 'var-name-1' added to the Pipeline/); + }); }); });