def __init__(self, scope: core.Construct, id: str, *,
                    project_name: str,
                    github_owner,
                    github_repo,
                    buildspec_path = None,
                    environment_variables = {},
                    base_branch: str = "main",
                    release_branch: str = "bump_version",
                    create_webhooks = False):

        build_environment = BuildEnvironment(build_image=self.BUILD_IMAGE, privileged = True, compute_type = ComputeType.LARGE)

        trigger_on_pr_merged = FilterGroup.in_event_of(EventAction.PULL_REQUEST_MERGED).and_base_branch_is(base_branch).and_branch_is(release_branch).and_commit_message_is("release:.*")

        if create_webhooks:
            github_source = Source.git_hub(owner = github_owner,
                                            report_build_status = True,
                                            repo = github_repo,
                                            webhook = True,
                                            webhook_filters = [trigger_on_pr_merged])
        else:
            github_source = Source.git_hub(owner = github_owner,
                                            report_build_status = True,
                                            repo = github_repo)
            
        super().__init__(scope, id,
            project_name = project_name,
            environment_variables = environment_variables,
            build_spec=BuildSpec.from_object_to_yaml(BUILD_SPEC) if buildspec_path is None else BuildSpec.from_source_filename(buildspec_path),
            badge = True,
            source = github_source,
            environment = build_environment)
Esempio n. 2
0
    def __init__(self, scope: core.Construct, construct_id: str, cert_arn: str,
                 hosted_zone_id: str, domain_name: str, **kwargs) -> None:
        """
        :param cert_arn: ARN of certificate to use
        :param hosted_zone_id: ID of hosted zone to use
        :param domain_name: Domain name to use
        """
        super().__init__(scope, construct_id, **kwargs)

        ##################################
        # WEBSITE HOSTING INFRASTRUCTURE #
        ##################################

        # Grab hosted zone for the website to contain our records and an SSL certificate for HTTPS. These two have to
        # be grabbed from existing resources instead of created here because CloudFormation will time out waiting for a
        # newly-created cert to validate.
        self.hosted_zone = PublicHostedZone.from_public_hosted_zone_id(
            self, "personal-site-hosted-zone", hosted_zone_id)
        self.cert = Certificate.from_certificate_arn(self,
                                                     "personal-site-cert",
                                                     cert_arn)

        # Add an S3 bucket to host the website content
        self.website_bucket = Bucket(self,
                                     "personal-site-bucket",
                                     bucket_name=domain_name,
                                     removal_policy=RemovalPolicy.DESTROY,
                                     public_read_access=True,
                                     website_index_document="index.html",
                                     website_error_document="index.html")

        # Create a cloudfront distribution for the site
        self.distribution = Distribution(
            self,
            "personal-site-cf-distribution",
            default_behavior={
                "origin": S3Origin(self.website_bucket),
                "allowed_methods": AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
                "viewer_protocol_policy":
                ViewerProtocolPolicy.REDIRECT_TO_HTTPS
            },
            certificate=self.cert,
            minimum_protocol_version=SecurityPolicyProtocol.TLS_V1_2_2019,
            enable_ipv6=True,
            domain_names=[domain_name, f"www.{domain_name}"])

        # Point traffic to base and www.base to the cloudfront distribution, for both IPv4 and IPv6
        ARecord(self,
                "personal-site-a-record",
                zone=self.hosted_zone,
                record_name=f"{domain_name}.",
                target=RecordTarget.from_alias(
                    CloudFrontTarget(self.distribution)))
        ARecord(self,
                "personal-site-a-record-www",
                zone=self.hosted_zone,
                target=RecordTarget.from_alias(
                    CloudFrontTarget(self.distribution)),
                record_name=f"www.{domain_name}.")
        AaaaRecord(self,
                   "personal-site-aaaa-record",
                   zone=self.hosted_zone,
                   record_name=f"{domain_name}.",
                   target=RecordTarget.from_alias(
                       CloudFrontTarget(self.distribution)))
        AaaaRecord(self,
                   "personal-site-aaaa-record-www",
                   zone=self.hosted_zone,
                   target=RecordTarget.from_alias(
                       CloudFrontTarget(self.distribution)),
                   record_name=f"www.{domain_name}.")

        #############################
        # WEBSITE CD INFRASTRUCTURE #
        #############################

        # CodeBuild project to build the website
        self.code_build_project = \
            Project(self, "personal-site-builder",
                    project_name="PersonalWebsite",
                    description="Builds & deploys a personal static website on changes from GitHub",
                    source=Source.git_hub(
                        owner="c7c8",
                        repo="crmyers.dev",
                        clone_depth=1,
                        branch_or_ref="master",
                        webhook_filters=[
                            FilterGroup.in_event_of(EventAction.PUSH, EventAction.PULL_REQUEST_MERGED).and_branch_is(
                                "master")]),
                    artifacts=Artifacts.s3(bucket=self.website_bucket, include_build_id=False,
                                           package_zip=False,
                                           path="/"),
                    build_spec=BuildSpec.from_object_to_yaml({
                        "version": "0.2",
                        "phases": {
                            "install": {
                                "runtime-versions": {
                                    "nodejs": 10,
                                }
                            },
                            "pre_build": {
                                "commands": ["npm install"]
                            },
                            "build": {
                                "commands": [
                                    "npm run-script build &&",
                                    f"aws cloudfront create-invalidation --distribution-id={self.distribution.distribution_id} --paths '/*'"
                                ]
                            }
                        },
                        "artifacts": {
                            "files": ["./*"],
                            "name": ".",
                            "discard-paths": "no",
                            "base-directory": "dist/crmyers-dev"
                        }
                    }))
        self.code_build_project.role.add_to_policy(
            PolicyStatement(
                effect=Effect.ALLOW,
                resources=[
                    f"arn:aws:cloudfront::{self.account}:distribution/{self.distribution.distribution_id}"
                ],
                actions=['cloudfront:CreateInvalidation']))

        # Set up an SNS topic for text message notifications
        self.deployment_topic = Topic(self,
                                      'personal-site-deployment-topic',
                                      topic_name='WebsiteDeployments',
                                      display_name='Website Deployments')
        self.deployment_topic.add_subscription(SmsSubscription("+19255968684"))
        self.code_build_project.on_build_failed(
            "BuildFailed",
            target=targets.SnsTopic(self.deployment_topic,
                                    message=RuleTargetInput.from_text(
                                        "Build for crmyers.dev FAILED")))
        self.code_build_project.on_build_succeeded(
            "BuildSucceeded",
            target=targets.SnsTopic(self.deployment_topic,
                                    message=RuleTargetInput.from_text(
                                        "Build for crmyers.dev SUCCEEDED")))