@flit/cdk-pipeline 1.4.4 → 2.0.0

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.
@@ -1,17 +1,17 @@
1
1
  import {
2
- BuildEnvironmentVariable,
3
- BuildSpec,
4
- mergeBuildSpecs,
5
- Project,
6
- ProjectProps,
2
+ BuildEnvironmentVariable,
3
+ BuildSpec,
4
+ mergeBuildSpecs,
5
+ Project,
6
+ ProjectProps,
7
7
  } from "aws-cdk-lib/aws-codebuild";
8
8
  import { Stack } from "aws-cdk-lib";
9
9
  import { IAction } from "aws-cdk-lib/aws-codepipeline";
10
10
  import {
11
- CloudFormationCreateReplaceChangeSetAction,
12
- CloudFormationExecuteChangeSetAction,
13
- CodeBuildAction,
14
- ManualApprovalAction,
11
+ CloudFormationCreateReplaceChangeSetAction,
12
+ CloudFormationExecuteChangeSetAction,
13
+ CodeBuildAction,
14
+ ManualApprovalAction,
15
15
  } from "aws-cdk-lib/aws-codepipeline-actions";
16
16
  import * as path from "path";
17
17
 
@@ -21,154 +21,154 @@ import { Pipeline } from "./pipeline";
21
21
  import { PublishAssetsAction } from "./publish-assets-action";
22
22
 
23
23
  export interface PipelineSegmentProps {
24
- /**
25
- * The input arfifact for the build stage.
26
- */
27
- readonly input: Artifact | Artifact[];
28
- /**
29
- * The command(s) to build the stack.
30
- * @example "cdk synth StackName --strict --exclusively"
31
- */
32
- readonly project: ProjectProps;
33
- /**
34
- * The environmental variables for the build stage.
35
- */
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
- /**
43
- * The artifact to hold the stack deployment output file.
44
- * @default no output artifact
45
- */
46
- readonly output?: Artifact;
47
- /**
48
- * The filename for the file in the output artifact
49
- * @default artifact.json
50
- */
51
- readonly outputFileName?: string;
52
- /**
53
- * Does this stage require manual approval of the change set?
54
- * @default false
55
- */
56
- readonly manualApproval?: Boolean;
24
+ /**
25
+ * The input arfifact for the build stage.
26
+ */
27
+ readonly input: Artifact | Artifact[];
28
+ /**
29
+ * The command(s) to build the stack.
30
+ * @example "cdk synth StackName --strict --exclusively"
31
+ */
32
+ readonly project: ProjectProps;
33
+ /**
34
+ * The environmental variables for the build stage.
35
+ */
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
+ /**
43
+ * The artifact to hold the stack deployment output file.
44
+ * @default no output artifact
45
+ */
46
+ readonly output?: Artifact;
47
+ /**
48
+ * The filename for the file in the output artifact
49
+ * @default artifact.json
50
+ */
51
+ readonly outputFileName?: string;
52
+ /**
53
+ * Does this stage require manual approval of the change set?
54
+ * @default false
55
+ */
56
+ readonly manualApproval?: Boolean;
57
57
  }
58
58
 
59
59
  /**
60
60
  * @category Segments
61
61
  */
62
62
  export class PipelineSegment extends Segment {
63
- readonly isPipeline = true;
64
- readonly props: PipelineSegmentProps;
63
+ readonly isPipeline = true;
64
+ readonly props: PipelineSegmentProps;
65
65
 
66
- constructor(props: PipelineSegmentProps) {
67
- super(props);
68
- this.props = props;
69
- }
66
+ constructor(props: PipelineSegmentProps) {
67
+ super(props);
68
+ this.props = props;
69
+ }
70
70
 
71
- construct(scope: Pipeline): SegmentConstructed {
72
- return new PipelineSegmentConstructed(scope, `Deploy${scope.stackName}`, {
73
- ...this.props,
74
- stack: scope,
75
- input: this.inputs[0],
76
- extraInputs: this.inputs.slice(1),
77
- });
78
- }
71
+ construct(scope: Pipeline): SegmentConstructed {
72
+ return new PipelineSegmentConstructed(scope, `Deploy${scope.node.id}`, {
73
+ ...this.props,
74
+ stack: scope,
75
+ input: this.inputs[0],
76
+ extraInputs: this.inputs.slice(1),
77
+ });
78
+ }
79
79
  }
80
80
 
81
81
  export interface PipelineSegmentConstructedProps {
82
- readonly stack: Stack;
83
- readonly project: ProjectProps;
84
- readonly environmentVariables?: { [key: string]: BuildEnvironmentVariable };
85
- readonly stackName?: string;
86
- readonly input: Artifact;
87
- readonly extraInputs?: Artifact[];
88
- readonly output?: Artifact;
89
- readonly outputFileName?: string;
90
- readonly manualApproval?: Boolean;
82
+ readonly stack: Stack;
83
+ readonly project: ProjectProps;
84
+ readonly environmentVariables?: { [key: string]: BuildEnvironmentVariable };
85
+ readonly stackName?: string;
86
+ readonly input: Artifact;
87
+ readonly extraInputs?: Artifact[];
88
+ readonly output?: Artifact;
89
+ readonly outputFileName?: string;
90
+ readonly manualApproval?: Boolean;
91
91
  }
92
92
 
93
93
  export class PipelineSegmentConstructed extends SegmentConstructed {
94
- readonly name: string;
95
- readonly actions: IAction[];
94
+ readonly name: string;
95
+ readonly actions: IAction[];
96
96
 
97
- constructor(
98
- scope: Pipeline,
99
- id: string,
100
- props: PipelineSegmentConstructedProps,
101
- ) {
102
- super(scope, id);
97
+ constructor(
98
+ scope: Pipeline,
99
+ id: string,
100
+ props: PipelineSegmentConstructedProps,
101
+ ) {
102
+ super(scope, id);
103
103
 
104
- this.name = props.stack.stackName;
104
+ this.name = props.stack.stackName;
105
105
 
106
- const buildArtifact = props.output || new Artifact();
106
+ const buildArtifact = props.output || new Artifact();
107
107
 
108
- this.actions = [
109
- new CodeBuildAction({
110
- actionName: "Build",
111
- runOrder: 1,
112
- input: props.input,
113
- extraInputs: props.extraInputs,
114
- outputs: [buildArtifact],
115
- environmentVariables: props.environmentVariables,
116
- project: new Project(this, "UpdateCodeBuild", {
117
- ...props.project,
118
- buildSpec: props.project.buildSpec
119
- ? mergeBuildSpecs(
120
- props.project.buildSpec,
121
- BuildSpec.fromObject({
122
- artifacts: {
123
- files: [path.join(scope.buildDir, "**/*")],
124
- },
125
- }),
126
- )
127
- : BuildSpec.fromObject({
128
- artifacts: {
129
- files: [path.join(scope.buildDir, "**/*")],
130
- },
131
- }),
132
- }),
133
- }),
134
- new PublishAssetsAction(this, "PublishAssets", {
135
- actionName: "PublishAssets",
136
- runOrder: 2,
137
- 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: `${props.stack.stackName}Changes`,
147
- adminPermissions: true,
148
- templatePath: buildArtifact.atPath(
149
- path.join(scope.buildDir, props.stack.templateFile),
150
- ),
151
- }),
152
- ...(props.manualApproval
153
- ? [
154
- new ManualApprovalAction({
155
- actionName: "ApproveChanges",
156
- runOrder: 4,
157
- }),
158
- ]
159
- : []),
160
- new CloudFormationExecuteChangeSetAction({
161
- actionName: "ExecuteChanges",
162
- runOrder: props.manualApproval ? 5 : 4,
163
- stackName: props.stackName ? props.stackName : props.stack.stackName,
164
- account: props.stack.account,
165
- region: props.stack.region,
166
- changeSetName: `${props.stack.stackName}Changes`,
167
- }),
168
- ];
169
- }
108
+ this.actions = [
109
+ new CodeBuildAction({
110
+ actionName: "Build",
111
+ runOrder: 1,
112
+ input: props.input,
113
+ extraInputs: props.extraInputs,
114
+ outputs: [buildArtifact],
115
+ environmentVariables: props.environmentVariables,
116
+ project: new Project(this, "UpdateCodeBuild", {
117
+ ...props.project,
118
+ buildSpec: props.project.buildSpec
119
+ ? mergeBuildSpecs(
120
+ props.project.buildSpec,
121
+ BuildSpec.fromObject({
122
+ artifacts: {
123
+ files: [path.join(scope.buildDir, "**/*")],
124
+ },
125
+ }),
126
+ )
127
+ : BuildSpec.fromObject({
128
+ artifacts: {
129
+ files: [path.join(scope.buildDir, "**/*")],
130
+ },
131
+ }),
132
+ }),
133
+ }),
134
+ new PublishAssetsAction(this, "PublishAssets", {
135
+ actionName: "PublishAssets",
136
+ runOrder: 2,
137
+ 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: `${props.stack.stackName}Changes`,
147
+ adminPermissions: true,
148
+ templatePath: buildArtifact.atPath(
149
+ path.join(scope.buildDir, props.stack.templateFile),
150
+ ),
151
+ }),
152
+ ...(props.manualApproval
153
+ ? [
154
+ new ManualApprovalAction({
155
+ actionName: "ApproveChanges",
156
+ runOrder: 4,
157
+ }),
158
+ ]
159
+ : []),
160
+ new CloudFormationExecuteChangeSetAction({
161
+ actionName: "ExecuteChanges",
162
+ runOrder: props.manualApproval ? 5 : 4,
163
+ stackName: props.stackName ? props.stackName : props.stack.stackName,
164
+ account: props.stack.account,
165
+ region: props.stack.region,
166
+ changeSetName: `${props.stack.stackName}Changes`,
167
+ }),
168
+ ];
169
+ }
170
170
  }
171
171
 
172
172
  export function isPipeline(item: Segment): item is PipelineSegment {
173
- return item.isPipeline;
173
+ return item.isPipeline;
174
174
  }
package/src/pipeline.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { App, Stack, StackProps } from "aws-cdk-lib";
2
2
  import { Construct } from "constructs";
3
3
  import {
4
- Pipeline as AwsPipeline,
5
- IAction,
6
- PipelineType,
4
+ Pipeline as AwsPipeline,
5
+ IAction,
6
+ PipelineType,
7
7
  } from "aws-cdk-lib/aws-codepipeline";
8
8
  import * as path from "path";
9
9
 
@@ -12,120 +12,120 @@ import { isSource } from "./source-segment";
12
12
  import { isPipeline } from "./pipeline-segment";
13
13
 
14
14
  export interface PipelineProps extends StackProps {
15
- /**
16
- * The name of the generated pipeline.
17
- * @default Stack ID
18
- */
19
- readonly pipelineName?: string;
20
- /**
21
- * The path to the cdk projects root directory containing the cdk.json file
22
- * relative to the asset root
23
- * @default "."
24
- */
25
- readonly rootDir?: string;
26
- /**
27
- * The segments to populating the pipeline.
28
- */
29
- readonly segments: (Segment | Segment[])[];
15
+ /**
16
+ * The name of the generated pipeline.
17
+ * @default Stack ID
18
+ */
19
+ readonly pipelineName?: string;
20
+ /**
21
+ * The path to the cdk projects root directory containing the cdk.json file
22
+ * relative to the asset root
23
+ * @default "."
24
+ */
25
+ readonly rootDir?: string;
26
+ /**
27
+ * The segments to populating the pipeline.
28
+ */
29
+ readonly segments: (Segment | Segment[])[];
30
30
  }
31
31
 
32
32
  /**
33
33
  * @category Constructs
34
34
  */
35
35
  export class Pipeline extends Stack {
36
- readonly pipelineName: string;
37
- readonly rootDir: string;
38
- readonly buildDir: string;
36
+ readonly pipelineName: string;
37
+ readonly rootDir: string;
38
+ readonly buildDir: string;
39
39
 
40
- constructor(
41
- scope: Construct,
42
- id: string,
43
- readonly props: PipelineProps,
44
- ) {
45
- super(scope, id, props);
40
+ constructor(
41
+ scope: Construct,
42
+ id: string,
43
+ readonly props: PipelineProps,
44
+ ) {
45
+ super(scope, id, props);
46
46
 
47
- this.pipelineName = props.pipelineName || id;
48
- this.rootDir = props.rootDir || ".";
49
- this.buildDir = path.join(this.rootDir, (this.node.root as App).outdir);
47
+ this.pipelineName = props.pipelineName || id;
48
+ this.rootDir = props.rootDir || ".";
49
+ this.buildDir = path.join(this.rootDir, (this.node.root as App).outdir);
50
50
 
51
- if (!this.bundlingRequired) return;
51
+ if (!this.bundlingRequired) return;
52
52
 
53
- const segments = props.segments.map((segment) =>
54
- Array.isArray(segment) ? segment : [segment],
55
- );
53
+ const segments = props.segments.map((segment) =>
54
+ Array.isArray(segment) ? segment : [segment],
55
+ );
56
56
 
57
- segments.forEach((unit) => {
58
- unit.forEach((segment) => {
59
- segment.inputs.forEach((artifact) => {
60
- if (!artifact.producer) {
61
- throw new Error("Artifact consumed but never produced.");
62
- }
63
- });
64
- });
65
- });
57
+ segments.forEach((unit) => {
58
+ unit.forEach((segment) => {
59
+ segment.inputs.forEach((artifact) => {
60
+ if (!artifact.producer) {
61
+ throw new Error("Artifact consumed but never produced.");
62
+ }
63
+ });
64
+ });
65
+ });
66
66
 
67
- if (segments[0].filter(isSource).length !== segments[0].length) {
68
- throw new Error("First segment must contain only source segments");
69
- }
67
+ if (segments[0].filter(isSource).length !== segments[0].length) {
68
+ throw new Error("First segment must contain only source segments");
69
+ }
70
70
 
71
- if (segments.slice(1).find((unit) => unit.filter(isSource).length)) {
72
- throw new Error("Only the first segment can contain source segments");
73
- }
71
+ if (segments.slice(1).find((unit) => unit.filter(isSource).length)) {
72
+ throw new Error("Only the first segment can contain source segments");
73
+ }
74
74
 
75
- if (
76
- segments[1].length === 1 &&
77
- segments[1].filter(isPipeline).length !== segments[1].length
78
- ) {
79
- throw new Error("Second segment must be the pipeline segment");
80
- }
75
+ if (
76
+ segments[1].length !== 1 ||
77
+ segments[1].filter(isPipeline).length !== segments[1].length
78
+ ) {
79
+ throw new Error("Second segment must be the pipeline segment");
80
+ }
81
81
 
82
- if (segments.slice(2).find((unit) => unit.filter(isPipeline).length)) {
83
- throw new Error("Only the second segment can be the pipeline segment");
84
- }
82
+ if (segments.slice(2).find((unit) => unit.filter(isPipeline).length)) {
83
+ throw new Error("Only the second segment can be the pipeline segment");
84
+ }
85
85
 
86
- new AwsPipeline(this, "Pipeline", {
87
- pipelineName: props.pipelineName,
88
- restartExecutionOnUpdate: true,
89
- pipelineType: PipelineType.V2,
90
- stages: [
91
- {
92
- stageName: "Source",
93
- actions: [
94
- ...segments[0].reduce(
95
- (actions, segment) => [
96
- ...actions,
97
- ...segment.construct(this).actions,
98
- ],
99
- [] as IAction[],
100
- ),
101
- ],
102
- },
103
- {
104
- stageName: "Pipeline",
105
- actions: [
106
- ...segments[1].reduce(
107
- (actions, segment) => [
108
- ...actions,
109
- ...segment.construct(this).actions,
110
- ],
111
- [] as IAction[],
112
- ),
113
- ],
114
- },
115
- ...segments.slice(2).map((unit) => {
116
- const builds = unit.reduce(
117
- (segments, segment) => [...segments, segment.construct(this)],
118
- [] as SegmentConstructed[],
119
- );
120
- return {
121
- stageName: builds.map((build) => build.name).join(""),
122
- actions: builds.reduce(
123
- (actions, build) => [...actions, ...build.actions],
124
- [] as IAction[],
125
- ),
126
- };
127
- }),
128
- ],
129
- });
130
- }
86
+ new AwsPipeline(this, "Pipeline", {
87
+ pipelineName: props.pipelineName,
88
+ restartExecutionOnUpdate: true,
89
+ pipelineType: PipelineType.V2,
90
+ stages: [
91
+ {
92
+ stageName: "Source",
93
+ actions: [
94
+ ...segments[0].reduce(
95
+ (actions, segment) => [
96
+ ...actions,
97
+ ...segment.construct(this).actions,
98
+ ],
99
+ [] as IAction[],
100
+ ),
101
+ ],
102
+ },
103
+ {
104
+ stageName: "Pipeline",
105
+ actions: [
106
+ ...segments[1].reduce(
107
+ (actions, segment) => [
108
+ ...actions,
109
+ ...segment.construct(this).actions,
110
+ ],
111
+ [] as IAction[],
112
+ ),
113
+ ],
114
+ },
115
+ ...segments.slice(2).map((unit) => {
116
+ const builds = unit.reduce(
117
+ (segments, segment) => [...segments, segment.construct(this)],
118
+ [] as SegmentConstructed[],
119
+ );
120
+ return {
121
+ stageName: builds.map((build) => build.name).join("-"),
122
+ actions: builds.reduce(
123
+ (actions, build) => [...actions, ...build.actions],
124
+ [] as IAction[],
125
+ ),
126
+ };
127
+ }),
128
+ ],
129
+ });
130
+ }
131
131
  }