@flit/cdk-pipeline 2.4.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flit/cdk-pipeline",
3
- "version": "2.4.0",
3
+ "version": "2.5.1",
4
4
  "description": "A highly customizable and extensible CI/CD pipeline intended as alternative to CDK's native CodePipeline",
5
5
  "keywords": [
6
6
  "aws",
@@ -51,18 +51,18 @@
51
51
  "useTabs": true
52
52
  },
53
53
  "devDependencies": {
54
- "@types/node": "^25.0.3",
55
- "aws-cdk-lib": "^2.232.0",
56
- "constructs": "^10.4.0",
57
- "jsii": "^5.9.22",
58
- "jsii-pacmak": "^1.125.0",
59
- "prettier": "^3.7.4",
60
- "prettier-plugin-packagejson": "^2.5.20",
54
+ "@types/node": "^25.5.0",
55
+ "aws-cdk-lib": "^2.244.0",
56
+ "constructs": "^10.6.0",
57
+ "jsii": "^5.9.34",
58
+ "jsii-pacmak": "^1.127.0",
59
+ "prettier": "^3.8.1",
60
+ "prettier-plugin-packagejson": "^3.0.2",
61
61
  "typescript": "^5.9.3"
62
62
  },
63
63
  "peerDependencies": {
64
- "aws-cdk-lib": "^2.232.0",
65
- "constructs": "^10.4.0"
64
+ "aws-cdk-lib": "^2.244.0",
65
+ "constructs": "^10.6.0"
66
66
  },
67
67
  "publishConfig": {
68
68
  "access": "public"
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  BuildEnvironmentVariable,
3
3
  BuildSpec,
4
+ ComputeType,
5
+ LinuxBuildImage,
4
6
  mergeBuildSpecs,
5
7
  Project,
6
8
  ProjectProps,
@@ -8,17 +10,15 @@ import {
8
10
  import { Stack } from "aws-cdk-lib";
9
11
  import { IAction } from "aws-cdk-lib/aws-codepipeline";
10
12
  import {
11
- CloudFormationCreateReplaceChangeSetAction,
12
13
  CloudFormationExecuteChangeSetAction,
13
14
  CodeBuildAction,
14
15
  ManualApprovalAction,
15
16
  } from "aws-cdk-lib/aws-codepipeline-actions";
16
- import * as path from "path";
17
17
 
18
18
  import { Artifact } from "./artifact";
19
19
  import { Segment, SegmentConstructed } from "./segment";
20
20
  import { Pipeline } from "./pipeline";
21
- import { PublishAssetsAction } from "./publish-assets-action";
21
+ import { PolicyStatement } from "aws-cdk-lib/aws-iam";
22
22
 
23
23
  export interface PipelineSegmentProps {
24
24
  /**
@@ -34,11 +34,6 @@ export interface PipelineSegmentProps {
34
34
  * The environmental variables for the build stage.
35
35
  */
36
36
  readonly environmentVariables?: { [key: string]: BuildEnvironmentVariable };
37
- /**
38
- * The name of the stack to apply this action to.
39
- * @default The name of the given stack.
40
- */
41
- readonly stackName?: string;
42
37
  /**
43
38
  * The artifact to hold the stack deployment output file.
44
39
  * @default no output artifact
@@ -82,7 +77,6 @@ export interface PipelineSegmentConstructedProps {
82
77
  readonly stack: Stack;
83
78
  readonly project: ProjectProps;
84
79
  readonly environmentVariables?: { [key: string]: BuildEnvironmentVariable };
85
- readonly stackName?: string;
86
80
  readonly input: Artifact;
87
81
  readonly extraInputs?: Artifact[];
88
82
  readonly output?: Artifact;
@@ -105,6 +99,61 @@ export class PipelineSegmentConstructed extends SegmentConstructed {
105
99
 
106
100
  const buildArtifact = props.output || new Artifact();
107
101
 
102
+ const prepareChangesProject = new Project(this, "PrepareChanges", {
103
+ environment: {
104
+ computeType: ComputeType.MEDIUM,
105
+ buildImage: LinuxBuildImage.AMAZON_LINUX_2_ARM_3,
106
+ },
107
+ buildSpec: BuildSpec.fromObject({
108
+ version: 0.2,
109
+ phases: {
110
+ install: {
111
+ "runtime-versions": {
112
+ nodejs: "24",
113
+ },
114
+ commands: "npm install -g aws-cdk",
115
+ },
116
+ build: {
117
+ commands: `npx cdk deploy ${props.stack.stackId} --app ./ --method prepare-change-set --change-set-name pipeline-${props.stack.stackId}-${this.name} --require-approval never`,
118
+ },
119
+ },
120
+ cache: {
121
+ paths: ["/root/.npm/**/*"],
122
+ },
123
+ }),
124
+ });
125
+
126
+ prepareChangesProject.addToRolePolicy(
127
+ new PolicyStatement({
128
+ actions: [
129
+ "ssm:GetParameter",
130
+ "cloudformation:CreateChangeSet",
131
+ "cloudformation:DescribeChangeSet",
132
+ "cloudformation:DescribeStacks",
133
+ "cloudformation:GetTemplate",
134
+ "cloudformation:DeleteChangeSet",
135
+ "iam:PassRole",
136
+ ],
137
+ resources: ["*"],
138
+ }),
139
+ );
140
+
141
+ prepareChangesProject.addToRolePolicy(
142
+ new PolicyStatement({
143
+ actions: ["sts:AssumeRole"],
144
+ resources: [`arn:*:iam::${Stack.of(this).account}:role/*`],
145
+ conditions: {
146
+ "ForAnyValue:StringEquals": {
147
+ "iam:ResourceTag/aws-cdk:bootstrap-role": [
148
+ "image-publishing",
149
+ "file-publishing",
150
+ "deploy",
151
+ ],
152
+ },
153
+ },
154
+ }),
155
+ );
156
+
108
157
  this.actions = [
109
158
  new CodeBuildAction({
110
159
  actionName: "Build",
@@ -120,50 +169,40 @@ export class PipelineSegmentConstructed extends SegmentConstructed {
120
169
  props.project.buildSpec,
121
170
  BuildSpec.fromObject({
122
171
  artifacts: {
123
- files: [path.join(scope.buildDir, "**/*")],
172
+ "base-directory": scope.buildDir,
173
+ files: ["**/*"],
124
174
  },
125
175
  }),
126
- )
176
+ )
127
177
  : BuildSpec.fromObject({
128
178
  artifacts: {
129
- files: [path.join(scope.buildDir, "**/*")],
179
+ "base-directory": scope.buildDir,
180
+ files: ["**/*"],
130
181
  },
131
- }),
182
+ }),
132
183
  }),
133
184
  }),
134
- new PublishAssetsAction(this, "PublishAssets", {
135
- actionName: "PublishAssets",
185
+ new CodeBuildAction({
186
+ actionName: "PrepareChanges",
136
187
  runOrder: 2,
137
188
  input: buildArtifact,
138
- manifestPath: scope.buildDir,
139
- }),
140
- new CloudFormationCreateReplaceChangeSetAction({
141
- actionName: "PrepareChanges",
142
- runOrder: 3,
143
- stackName: props.stackName ? props.stackName : props.stack.stackName,
144
- account: props.stack.account,
145
- region: props.stack.region,
146
- changeSetName: `${this.name}Changes`,
147
- adminPermissions: true,
148
- templatePath: buildArtifact.atPath(
149
- path.join(scope.buildDir, props.stack.templateFile),
150
- ),
189
+ project: prepareChangesProject,
151
190
  }),
152
191
  ...(props.manualApproval
153
192
  ? [
154
193
  new ManualApprovalAction({
155
194
  actionName: "ApproveChanges",
156
- runOrder: 4,
195
+ runOrder: 3,
157
196
  }),
158
- ]
197
+ ]
159
198
  : []),
160
199
  new CloudFormationExecuteChangeSetAction({
161
200
  actionName: "ExecuteChanges",
162
- runOrder: props.manualApproval ? 5 : 4,
163
- stackName: props.stackName ? props.stackName : props.stack.stackName,
201
+ runOrder: props.manualApproval ? 3 : 4,
202
+ stackName: props.stack.stackName,
164
203
  account: props.stack.account,
165
204
  region: props.stack.region,
166
- changeSetName: `${this.name}Changes`,
205
+ changeSetName: `pipeline-${props.stack.stackId}-${this.name}`,
167
206
  }),
168
207
  ];
169
208
  }
@@ -3,13 +3,14 @@ import {
3
3
  BuildEnvironmentVariable,
4
4
  BuildEnvironmentVariableType,
5
5
  BuildSpec,
6
+ ComputeType,
7
+ LinuxBuildImage,
6
8
  mergeBuildSpecs,
7
9
  Project,
8
10
  ProjectProps,
9
11
  } from "aws-cdk-lib/aws-codebuild";
10
12
  import { IAction } from "aws-cdk-lib/aws-codepipeline";
11
13
  import {
12
- CloudFormationCreateReplaceChangeSetAction,
13
14
  CloudFormationExecuteChangeSetAction,
14
15
  CodeBuildAction,
15
16
  ManualApprovalAction,
@@ -20,7 +21,6 @@ import * as path from "path";
20
21
  import { Artifact } from "./artifact";
21
22
  import { Segment, SegmentConstructed } from "./segment";
22
23
  import { Pipeline } from "./pipeline";
23
- import { PublishAssetsAction } from "./publish-assets-action";
24
24
 
25
25
  export interface StackSegmentProps {
26
26
  /**
@@ -44,11 +44,6 @@ export interface StackSegmentProps {
44
44
  * The environmental variables for the build stage.
45
45
  */
46
46
  readonly environmentVariables?: { [key: string]: BuildEnvironmentVariable };
47
- /**
48
- * The name of the stack to deploy the changes to.
49
- * @default The name of the given stack.
50
- */
51
- readonly stackName?: string;
52
47
  /**
53
48
  * The artifact to hold the output of the build if this stack includes a build.
54
49
  */
@@ -100,7 +95,6 @@ export interface StackSegmentConstructedProps {
100
95
  readonly stack: Stack;
101
96
  readonly project?: ProjectProps;
102
97
  readonly environmentVariables?: { [key: string]: BuildEnvironmentVariable };
103
- readonly stackName?: string;
104
98
  readonly input: Artifact;
105
99
  readonly extraInputs?: Artifact[];
106
100
  readonly buildOutput?: Artifact;
@@ -136,12 +130,12 @@ export class StackSegmentConstructed extends SegmentConstructed {
136
130
  files: [path.join(scope.buildDir, "**/*")],
137
131
  },
138
132
  }),
139
- )
133
+ )
140
134
  : BuildSpec.fromObject({
141
135
  artifacts: {
142
136
  files: [path.join(scope.buildDir, "**/*")],
143
137
  },
144
- }),
138
+ }),
145
139
  });
146
140
 
147
141
  Object.entries(
@@ -174,7 +168,7 @@ export class StackSegmentConstructed extends SegmentConstructed {
174
168
  ? v.value.split(":").slice(0, 7).join(":")
175
169
  : `arn:aws:secretsmanager:*:${
176
170
  Stack.of(this).account
177
- }:secret:${v.value}-*`,
171
+ }:secret:${v.value}-*`,
178
172
  ],
179
173
  }),
180
174
  );
@@ -182,6 +176,61 @@ export class StackSegmentConstructed extends SegmentConstructed {
182
176
  }
183
177
  });
184
178
 
179
+ const prepareChangesProject = new Project(this, "PrepareChanges", {
180
+ environment: {
181
+ computeType: ComputeType.MEDIUM,
182
+ buildImage: LinuxBuildImage.AMAZON_LINUX_2_ARM_3,
183
+ },
184
+ buildSpec: BuildSpec.fromObject({
185
+ version: 0.2,
186
+ phases: {
187
+ install: {
188
+ "runtime-versions": {
189
+ nodejs: "24",
190
+ },
191
+ commands: "npm install -g aws-cdk",
192
+ },
193
+ build: {
194
+ commands: `npx cdk deploy ${props.stack.stackId} --app ./ --method prepare-change-set --change-set-name pipeline-${props.stack.stackId}-${this.name} --require-approval never`,
195
+ },
196
+ },
197
+ cache: {
198
+ paths: ["/root/.npm/**/*"],
199
+ },
200
+ }),
201
+ });
202
+
203
+ prepareChangesProject.addToRolePolicy(
204
+ new PolicyStatement({
205
+ actions: [
206
+ "ssm:GetParameter",
207
+ "cloudformation:CreateChangeSet",
208
+ "cloudformation:DescribeChangeSet",
209
+ "cloudformation:DescribeStacks",
210
+ "cloudformation:GetTemplate",
211
+ "cloudformation:DeleteChangeSet",
212
+ "iam:PassRole",
213
+ ],
214
+ resources: ["*"],
215
+ }),
216
+ );
217
+
218
+ prepareChangesProject.addToRolePolicy(
219
+ new PolicyStatement({
220
+ actions: ["sts:AssumeRole"],
221
+ resources: [`arn:*:iam::${Stack.of(this).account}:role/*`],
222
+ conditions: {
223
+ "ForAnyValue:StringEquals": {
224
+ "iam:ResourceTag/aws-cdk:bootstrap-role": [
225
+ "image-publishing",
226
+ "file-publishing",
227
+ "deploy",
228
+ ],
229
+ },
230
+ },
231
+ }),
232
+ );
233
+
185
234
  this.actions = [
186
235
  ...(buildArtifact
187
236
  ? [
@@ -194,53 +243,41 @@ export class StackSegmentConstructed extends SegmentConstructed {
194
243
  environmentVariables: props.environmentVariables,
195
244
  project: codeBuildProject,
196
245
  }),
197
- new PublishAssetsAction(this, "PublishAssets", {
198
- actionName: `${this.name}PublishAssets`,
199
- runOrder: 2,
200
- input: buildArtifact,
201
- manifestPath: scope.buildDir,
202
- }),
203
- ]
246
+ ]
204
247
  : []),
205
- new CloudFormationCreateReplaceChangeSetAction({
248
+ new CodeBuildAction({
206
249
  actionName: `${this.name}PrepareChanges`,
207
- runOrder: buildArtifact ? 3 : 1,
208
- stackName: props.stackName ? props.stackName : props.stack.stackName,
209
- account: props.stack.account,
210
- region: props.stack.region,
211
- changeSetName: `${this.name}Changes`,
212
- adminPermissions: true,
213
- templatePath: (buildArtifact ? buildArtifact : props.input).atPath(
214
- path.join(scope.buildDir, props.stack.templateFile),
215
- ),
250
+ runOrder: buildArtifact ? 2 : 1,
251
+ input: buildArtifact ? buildArtifact : props.input,
252
+ project: prepareChangesProject,
216
253
  }),
217
254
  ...(props.manualApproval
218
255
  ? [
219
256
  new ManualApprovalAction({
220
257
  actionName: `${this.name}ApproveChanges`,
221
- runOrder: buildArtifact ? 4 : 2,
258
+ runOrder: buildArtifact ? 3 : 2,
222
259
  }),
223
- ]
260
+ ]
224
261
  : []),
225
262
  new CloudFormationExecuteChangeSetAction({
226
263
  actionName: `${this.name}ExecuteChanges`,
227
264
  runOrder: props.manualApproval
228
265
  ? buildArtifact
229
- ? 5
266
+ ? 4
230
267
  : 3
231
268
  : buildArtifact
232
- ? 4
233
- : 2,
234
- stackName: props.stackName ? props.stackName : props.stack.stackName,
269
+ ? 3
270
+ : 2,
271
+ stackName: props.stack.stackName,
235
272
  account: props.stack.account,
236
273
  region: props.stack.region,
237
- changeSetName: `${this.name}Changes`,
274
+ changeSetName: `pipeline-${props.stack.stackId}-${this.name}`,
238
275
  output: props.stackOutput,
239
276
  outputFileName: props.outputFileName
240
277
  ? props.outputFileName
241
278
  : props.stackOutput
242
- ? "artifact.json"
243
- : undefined,
279
+ ? "artifact.json"
280
+ : undefined,
244
281
  }),
245
282
  ];
246
283
  }