public FrontEndCdkPipelineStack()

in frontend-infrastructure/src/main/java/com/recognise/frontend/pipeline/FrontEndCdkPipelineStack.java [45:180]


    public FrontEndCdkPipelineStack(Construct scope, String id, StackProps props) {
        super(scope, id, props);

        Topic topic = null;

        if (!contextValue("approval_emails").isEmpty()) {
            String[] approval_emails = contextValue("approval_emails").split(",");
            topic = Topic.Builder.create(this, "ApprovalNotificationTopic")
                    .displayName("ApprovalNotificationTopic")
                    .topicName("ApprovalNotificationTopic")
                    .build();


            for (String email : approval_emails) {
                topic.addSubscription(EmailSubscription.Builder.create(email).build());
            }
        }

        Bucket frontEndArtifactBucket = Bucket.Builder.create(this, "FrontEndArtifactBucket")
                .versioned(true)
                .build();

        Trail frontEndTrail = Trail.Builder.create(this, "FrontEndCodeCdkPipelineAwsCloudTrail")
                .isMultiRegionTrail(true)
                .trailName("FrontEndCodeCdkPipelineAwsCloudTrail")
                .managementEvents(ReadWriteType.WRITE_ONLY)
                .includeGlobalServiceEvents(true)
                .build();

        String sourceZip = "frontend-source.zip";

        frontEndTrail.addS3EventSelector(singletonList(S3EventSelector.builder()
                .bucket(frontEndArtifactBucket)
                .objectPrefix(sourceZip)
                .build()));

        HashMap<String, BuildEnvironmentVariable> envVar = new HashMap<>();

        envVar.put("SOURCE_OBJECT_KEY", BuildEnvironmentVariable.builder()
                .value(sourceZip)
                .build());

        envVar.put("SOURCE_OUTPUT_BUCKET", BuildEnvironmentVariable.builder()
                .value(frontEndArtifactBucket.getBucketName())
                .build());

        envVar.put("FOLDER_TO_INCLUDE", BuildEnvironmentVariable.builder()
                .value("frontend frontend-infrastructure")
                .build());

        Project detectorBuild = Project.Builder.create(this, "WebApplicationFrontEndCdkPipelineDetector")
                .projectName("WebApplicationFrontEndCdkPipelineDetector")
                .description("Detects if frontend or frontend infra is updated. It will then invoke frontend pipeline")
                .buildSpec(BuildSpec.fromSourceFilename("buildspec-copyartifact.yaml"))
                .environment(BuildEnvironment.builder()
                        .computeType(LARGE)
                        .buildImage(AMAZON_LINUX_2_ARM)
                        .build())
                .source(Source.gitHub(GitHubSourceProps.builder()
                        .cloneDepth(0)
                        .owner(contextValue("owner"))
                        .repo(contextValue("repo"))
                        .webhookFilters(asList(FilterGroup.inEventOf(EventAction.PUSH)
                                .andFilePathIs("frontend/"), FilterGroup.inEventOf(EventAction.PUSH)
                                .andFilePathIs("frontend-infrastructure/")))
                        .webhook(true)
                        .build()))
                .environmentVariables(envVar)
                .build();

        detectorBuild.addToRolePolicy(PolicyStatement.Builder.create()
                .effect(Effect.ALLOW)
                .actions(asList(
                        "s3:PutObject",
                        "s3:GetObject",
                        "s3:GetObjectVersion"))
                .resources(singletonList(frontEndArtifactBucket.getBucketArn() + "/*"))
                .build());

        detectorBuild.addToRolePolicy(PolicyStatement.Builder.create()
                .effect(Effect.ALLOW)
                .actions(singletonList(
                        "s3:ListBucket"))
                .resources(singletonList(frontEndArtifactBucket.getBucketArn()))
                .build());

        CodePipeline codePipeline = CodePipeline.Builder.create(this, "WebApplicationFrontEndCdkPipeline")
                .pipelineName("WebApplicationFrontEndCdkPipeline")
                .crossAccountKeys(true)
                // Self mutation is very much needed here coz of https://github.com/aws/aws-cdk/issues/9080.
                // Else the publishing actions might try to publish obsolete hash
                .selfMutation(true)
                .synth(new CodeBuildStep("BuildFrontendInfrastructureProject", CodeBuildStepProps.builder()
                        //.partialBuildSpec(BuildSpec.fromSourceFilename(contextValue("frontend_infra_build_spec")))
                        .commands(asList(
                                "cd frontend",
                                "npm install --global npm && npm ci",
                                "npm run build",
                                "CI=true npm test",
                                "cd ../frontend-infrastructure",
                                "npm install -g aws-cdk",
                                "mvn clean install --quiet",
                                "cdk synth"
                        ))
                        .primaryOutputDirectory("./frontend-infrastructure/cdk.out")
                        .input(CodePipelineSource.s3(frontEndArtifactBucket, sourceZip, S3SourceOptions.builder()
                                .trigger(S3Trigger.EVENTS)
                                .actionName("S3FrontEndSource")
                                .build()))
                        .projectName("BuildFrontendInfrastructureProject")
                        .build()))
                .codeBuildDefaults(CodeBuildOptions.builder()
                        .buildEnvironment(BuildEnvironment.builder()
                                .computeType(LARGE)
                                .buildImage(AMAZON_LINUX_2_ARM)
                                .build())
                        .build())
                .build();

        List<Step> preProStep = new ArrayList<>();

        if (null != topic) {
            preProStep.add(ManualApprovalStep.Builder.create("Approval")
                    .comment("Approve before site is deployed for public.")
                    .build());
        }

        codePipeline.addStage(new ApplicationStage(this, "prod", software.amazon.awscdk.core.StageProps.builder()
                .env(Environment.builder()
                        .region(props.getEnv().getRegion())
                        .account(props.getEnv().getAccount())
                        .build())
                .build()), AddStageOpts.builder()
                .pre(preProStep)
                .build());
    }