Skip to content

Commit 8a40b1a

Browse files
authored
Merge pull request #83 from ashphy/dploy-with-cdk
Deploy CDK
2 parents 95d450b + 5a13363 commit 8a40b1a

File tree

16 files changed

+5381
-513
lines changed

16 files changed

+5381
-513
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ jobs:
1313
uses: actions/setup-node@v4
1414
with:
1515
node-version: 20
16+
cache: "npm"
17+
1618
- run: npm ci
1719

1820
- name: Run ESLint

.github/workflows/deploy.yml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: Deploy Web App
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
env:
9+
CDK_DEFAULT_ACCOUNT: ${{ vars.CDK_DEFAULT_ACCOUNT }}
10+
CDK_DEFAULT_REGION: ${{ vars.CDK_DEFAULT_REGION }}
11+
12+
jobs:
13+
deploy_infra:
14+
name: Deploy Infrastructure
15+
runs-on: ubuntu-latest
16+
permissions:
17+
id-token: write
18+
contents: read
19+
outputs:
20+
s3_url: ${{ steps.extract_cdk_outputs.outputs.s3_url }}
21+
distribution_id: ${{ steps.extract_cdk_outputs.outputs.distribution_id }}
22+
steps:
23+
- uses: actions/checkout@v4
24+
- uses: actions/setup-node@v4
25+
with:
26+
node-version: 20
27+
cache: "npm"
28+
29+
- run: npm ci
30+
working-directory: infra
31+
- run: npm run build
32+
working-directory: infra
33+
- uses: aws-actions/configure-aws-credentials@v4
34+
with:
35+
role-to-assume: ${{ vars.CDK_DEPLOY_ROLE_ARN }}
36+
aws-region: ${{ vars.CDK_DEFAULT_REGION }}
37+
- run: npm run cdk -- deploy --all --require-approval never --outputs-file output.json
38+
working-directory: infra
39+
40+
- id: extract_cdk_outputs
41+
run: |
42+
echo "s3_url=$(jq -r '.JSONPathOnlineEvaluatorInfraStack.WebsiteBucketURI' output.json)" >> $GITHUB_OUTPUT
43+
echo "distribution_id=$(jq -r '.JSONPathOnlineEvaluatorInfraStack.DistributionId' output.json)" >> $GITHUB_OUTPUT
44+
working-directory: infra
45+
46+
deploy_app:
47+
name: Upload to Amazon S3
48+
needs: deploy_infra
49+
runs-on: ubuntu-latest
50+
permissions:
51+
id-token: write
52+
contents: read
53+
steps:
54+
- uses: actions/checkout@v4
55+
- uses: actions/setup-node@v4
56+
with:
57+
node-version: 20
58+
cache: "npm"
59+
60+
- run: npm ci
61+
- run: npm run build
62+
63+
- uses: aws-actions/configure-aws-credentials@v4
64+
with:
65+
role-to-assume: ${{ vars.CDK_DEPLOY_ROLE_ARN }}
66+
aws-region: ${{ vars.CDK_DEFAULT_REGION }}
67+
68+
- name: Copy files to the website with the AWS CLI
69+
run: |
70+
aws s3 sync dist ${{ needs.deploy_infra.outputs.s3_url }} --delete --exact-timestamps
71+
72+
- name: Invalidate CloudFront cache
73+
run: |
74+
aws cloudfront create-invalidation --distribution-id ${{ needs.deploy_infra.outputs.distribution_id }} --paths "/*"

.github/workflows/release.yml

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ jobs:
1717
uses: actions/setup-node@v4
1818
with:
1919
node-version: 20
20+
cache: "npm"
2021

2122
- run: npm ci
2223
- run: npm run build
@@ -58,29 +59,6 @@ jobs:
5859
draft: false
5960
prerelease: false
6061

61-
publish_to_s3:
62-
name: Upload to Amazon S3
63-
needs: build
64-
runs-on: ubuntu-latest
65-
permissions:
66-
id-token: write
67-
contents: read
68-
steps:
69-
- name: Download assets
70-
uses: actions/download-artifact@v4
71-
with:
72-
name: dist
73-
74-
- name: Configure AWS credentials
75-
uses: aws-actions/configure-aws-credentials@v4
76-
with:
77-
role-to-assume: arn:aws:iam::285224135196:role/jsonpath-deploy
78-
aws-region: us-west-2
79-
80-
- name: Copy files to the website with the AWS CLI
81-
run: |
82-
aws s3 sync . s3://jsonpath.com
83-
8462
push_to_registry:
8563
name: Push Docker image to Docker Hub
8664
needs: build

infra/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
*.js
2+
!lib/cloudfront-functions/*.js
3+
!jest.config.js
4+
*.d.ts
5+
node_modules
6+
7+
# CDK asset staging directory
8+
.cdk.staging
9+
cdk.out
10+
output.json

infra/.npmignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.ts
2+
!*.d.ts
3+
4+
# CDK asset staging directory
5+
.cdk.staging
6+
cdk.out

infra/bin/infra.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env node
2+
import * as cdk from "aws-cdk-lib";
3+
import { InfraStack } from "../lib/infra-stack";
4+
import { DomainStack } from "../lib/domain-stack";
5+
import { CertificateStack } from "../lib/certificate-stack";
6+
7+
const app = new cdk.App();
8+
cdk.Tags.of(app).add("project", "JSONPathOnlineEvaluator");
9+
10+
const zoneName = "jsonpath.com";
11+
const domainName = "jsonpath.com";
12+
13+
const domainStack = new DomainStack(app, "JSONPathOnlineEvaluatorDomainStack", {
14+
zoneName,
15+
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: "us-east-1" },
16+
crossRegionReferences: true,
17+
});
18+
19+
const certificateStack = new CertificateStack(
20+
app,
21+
"JSONPathOnlineEvaluatorCertificateStack",
22+
{
23+
hostedZone: domainStack.hostedZone,
24+
domainName,
25+
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: "us-east-1" },
26+
crossRegionReferences: true,
27+
}
28+
);
29+
30+
new InfraStack(app, "JSONPathOnlineEvaluatorInfraStack", {
31+
hostedZone: domainStack.hostedZone,
32+
domainName,
33+
certificate: certificateStack.certificate,
34+
env: {
35+
account: process.env.CDK_DEFAULT_ACCOUNT,
36+
region: process.env.CDK_DEFAULT_REGION,
37+
},
38+
crossRegionReferences: true,
39+
});

infra/cdk.json

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
{
2+
"app": "npx ts-node --prefer-ts-exts bin/infra.ts",
3+
"watch": {
4+
"include": [
5+
"**"
6+
],
7+
"exclude": [
8+
"README.md",
9+
"cdk*.json",
10+
"**/*.d.ts",
11+
"**/*.js",
12+
"tsconfig.json",
13+
"package*.json",
14+
"yarn.lock",
15+
"node_modules",
16+
"test"
17+
]
18+
},
19+
"context": {
20+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
21+
"@aws-cdk/core:checkSecretUsage": true,
22+
"@aws-cdk/core:target-partitions": [
23+
"aws",
24+
"aws-cn"
25+
],
26+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
27+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
28+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
29+
"@aws-cdk/aws-iam:minimizePolicies": true,
30+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
31+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
32+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
33+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
34+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
35+
"@aws-cdk/core:enablePartitionLiterals": true,
36+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
37+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
38+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
39+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
40+
"@aws-cdk/aws-route53-patters:useCertificate": true,
41+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
42+
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
43+
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
44+
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
45+
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
46+
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
47+
"@aws-cdk/aws-redshift:columnId": true,
48+
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
49+
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
50+
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
51+
"@aws-cdk/aws-kms:aliasNameRef": true,
52+
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
53+
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
54+
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
55+
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
56+
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
57+
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
58+
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
59+
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
60+
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
61+
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
62+
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
63+
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
64+
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
65+
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
66+
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
67+
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
68+
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
69+
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
70+
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false,
71+
"@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": false,
72+
"@aws-cdk/aws-ecs:disableEcsImdsBlocking": true,
73+
"@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true,
74+
"@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true,
75+
"@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true,
76+
"@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true,
77+
"@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true,
78+
"@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true,
79+
"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true,
80+
"@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true,
81+
"@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true,
82+
"@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true,
83+
"@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true,
84+
"@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true
85+
}
86+
}

infra/jest.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = {
2+
testEnvironment: 'node',
3+
roots: ['<rootDir>/test'],
4+
testMatch: ['**/*.test.ts'],
5+
transform: {
6+
'^.+\\.tsx?$': 'ts-jest'
7+
}
8+
};

infra/lib/certificate-stack.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as cdk from "aws-cdk-lib";
2+
import type { Construct } from "constructs";
3+
4+
import type * as route53 from "aws-cdk-lib/aws-route53";
5+
import * as acm from "aws-cdk-lib/aws-certificatemanager";
6+
7+
interface CertificateStackProps extends cdk.StackProps {
8+
hostedZone: route53.IHostedZone;
9+
domainName: string;
10+
}
11+
12+
export class CertificateStack extends cdk.Stack {
13+
readonly certificate: acm.Certificate;
14+
15+
constructor(scope: Construct, id: string, props: CertificateStackProps) {
16+
super(scope, id, props);
17+
18+
this.certificate = new acm.Certificate(this, "Certificate", {
19+
domainName: props.domainName,
20+
validation: acm.CertificateValidation.fromDns(props.hostedZone),
21+
});
22+
}
23+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
async function handler(event) {
2+
const request = event.request;
3+
const uri = request.uri;
4+
5+
const response = event.response;
6+
const headers = response.headers;
7+
8+
if (response.statusCode >= 200 && response.statusCode < 400) {
9+
if (uri.startsWith("/assets/")) {
10+
headers["cache-control"] = { value: "public,max-age=31536000" };
11+
} else {
12+
headers["cache-control"] = { value: "public,max-age=0,must-revalidate" };
13+
}
14+
}
15+
16+
return response;
17+
}

0 commit comments

Comments
 (0)