constructor()

in cdk/lib/cdk-vue-application-pipeline.ts [39:235]


    constructor(scope: Construct, id: string, props?: StackProps) {
        super(scope, id, props);

        // Retrieve secrets for configuring the GitHub repository webhook and pipeline notifications email.
        const githubRepoOwner = SecretValue.secretsManager('GitHubSecrets', {jsonField: 'repo-owner'});
        const githubRepoName = SecretValue.secretsManager('GitHubSecrets', {jsonField: 'repo-name'});
        const githubRepoBranch = SecretValue.secretsManager('GitHubSecrets', {jsonField: 'repo-branch'});
        const githubRepoToken = SecretValue.secretsManager('GitHubSecrets', {jsonField: 'repo-token'});
        const notificationsEmail = SecretValue.secretsManager('GitHubSecrets', {jsonField: 'notifications-email'});

        // Pipeline artifacts to store repository source and build stage outputs.
        const pipelineArtifact = new Artifact('RepoSource');
        const buildArtifact = new Artifact('BuildOutput');
        const vueBuildArtifact = new Artifact('VueBuildOutput');

        // Create SNS topic for pipeline notifications like approvals.
        const pipelineNotificationTopic = new Topic(this, 'ApprovalSnsTopic', {
            topicName: 'ApprovalSnsTopic'
        });

        // CdkPipeline to auto-mutate this CDK stack and deploy the Vue application.
        const cdkPipeline = new CdkPipeline(this, 'VueComponentCdkPipeline', {
            pipelineName: 'VueComponentPipeline',
            cloudAssemblyArtifact: buildArtifact,
            synthAction: SimpleSynthAction.standardNpmSynth({
                sourceArtifact: pipelineArtifact,
                cloudAssemblyArtifact: buildArtifact,
                actionName: 'BuildCdk',
                subdirectory: 'cdk',
                buildCommand: 'npm run build',
                testCommands: [
                    'npm run test'
                ]
            }),
            sourceAction: new GitHubSourceAction({
                actionName: 'GitHubSource',
                branch: githubRepoBranch.toString(),
                output: pipelineArtifact,
                owner: githubRepoOwner.toString(),
                repo: githubRepoName.toString(),
                oauthToken: githubRepoToken,
                trigger: GitHubTrigger.WEBHOOK,
                runOrder: 1
            })
        });

        // Add build stage for the Vue application.
        const vueApplicationStage = cdkPipeline.addStage('BuildVue');
        vueApplicationStage.addActions(new CodeBuildAction({
            actionName: 'BuildVue',
            input: pipelineArtifact,
            outputs: [
                vueBuildArtifact
            ],
            project: new PipelineProject(this, "BuildVue", {
                buildSpec: BuildSpec.fromObject({
                    version: "0.2",
                    phases: {
                        install: {
                            "runtime-versions": {
                                nodejs: 12
                            }
                        },
                        "pre_build": {
                            commands: [
                                "cd vue-web-component-app",
                                "npm install"
                            ]
                        },
                        build: {
                            commands: [
                                "npm run lint",
                                "npm run test",
                                "npm run build",
                                "cp public/* dist"
                            ]
                        }
                    },
                    artifacts: {
                        files: [
                            "**/*"
                        ],
                        "base-directory": "vue-web-component-app/dist"
                    }
                }),
                environment: {
                    buildImage: LinuxBuildImage.AMAZON_LINUX_2_3
                }
            }),
            runOrder: 1
        }));

        // Creating S3 bucket to deploy the Vue application to.
        const deployBlueBucket = new Bucket(this, 'BlueVueComponentsBucket', {
            versioned: false,
            bucketName: `blue-vue-component-bucket-${this.region}-${this.account}`,
            publicReadAccess: false,
            removalPolicy: RemovalPolicy.DESTROY
        });

        // Creating S3 bucket to deploy the Vue application to.
        const deployGreenBucket = new Bucket(this, 'GreenVueComponentsBucket', {
            versioned: false,
            bucketName: `green-vue-component-bucket-${this.region}-${this.account}`,
            publicReadAccess: false,
            removalPolicy: RemovalPolicy.DESTROY
        });

        // Create CloudFront distribution OAI for the S3 bucket containing the Vue application.
        const oai = new OriginAccessIdentity(this, 'OriginAccessIdentity', {comment: "Origin Access Identity for Origin S3 bucket"});
        deployBlueBucket.grantRead(oai);
        deployGreenBucket.grantRead(oai);

        // Create Lambda@Edge function for A/B testing different application deployments.
        const edgeFunction = new EdgeFunction(this, 'ABEdgeFunction', {
            code: Code.fromAsset("lib/lambda"),
            handler: "ab-lambda-function.handler",
            runtime: Runtime.NODEJS_14_X
        });

        const greenOrigin = new S3Origin(
            deployGreenBucket,
            {
                originAccessIdentity: oai
            }
        );

        // Create CloudFront distribution with Vue deployment bucket as origin and AB Lambda@Edge function.
        const cfDistro = new Distribution(this, 'VueComponentDistribution', {
            defaultBehavior: {
                origin: greenOrigin,
                viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
                edgeLambdas: [{
                    eventType: LambdaEdgeEventType.VIEWER_REQUEST,
                    functionVersion: edgeFunction
                }]
            },
            defaultRootObject: 'index.html'
        });

        const blueOrigin = new S3Origin(
            deployBlueBucket,
            {
                originAccessIdentity: oai
            }
        );

        cfDistro.addBehavior('/blue/*',
            blueOrigin,
            {
                viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS
            }
        )

        // Add approval stage before deploying the Vue application
        const approvalBlueStage = cdkPipeline.addStage('ApprovalBlue');
        approvalBlueStage.addActions(new ManualApprovalAction({
            actionName: 'ApproveBlueDeploy',
            notifyEmails: [
                notificationsEmail.toString()
            ],
            additionalInformation: 'Approve Deployment to S3 for the blue deployment group?',
            externalEntityLink: `https://github.com/${githubRepoOwner}/${githubRepoName}`,
            notificationTopic: pipelineNotificationTopic,
            runOrder: 1
        }));

        // Add pipeline stage for deploying the Vue application to the "Blue" S3 target.
        const deployBlueStage = cdkPipeline.addStage('DeployBlue');
        deployBlueStage.addActions(new S3DeployAction({
            actionName: 'DeployVue',
            bucket: deployBlueBucket,
            input: vueBuildArtifact
        }));

        // Add approval stage before deploying the Vue application
        const approvalGreenStage = cdkPipeline.addStage('ApprovalGreen');
        approvalGreenStage.addActions(new ManualApprovalAction({
            actionName: 'ApproveDeploy',
            notifyEmails: [
                notificationsEmail.toString()
            ],
            additionalInformation: 'Approve Deployment to S3 for the green deployment group?',
            externalEntityLink: `https://github.com/${githubRepoOwner}/${githubRepoName}`,
            notificationTopic: pipelineNotificationTopic,
            runOrder: 1
        }));

        // Add pipeline stage for deploying the Vue application to the "Green" S3 target.
        const deployGreenStage = cdkPipeline.addStage('DeployGreen');
        deployGreenStage.addActions(new S3DeployAction({
            actionName: 'DeployVue',
            bucket: deployGreenBucket,
            input: vueBuildArtifact
        }));

    }