Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
152 changes: 152 additions & 0 deletions .aws/cfn/storybook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
Description: React Starter UI Storybook component resources

Parameters:
EnvironmentCode:
Type: String
Description: Select an Environment
AllowedValues:
- dev
- qa
- prod
Default: dev
ConstraintDescription: Must select a valid environment

Mappings:
EnvironmentAttributeMap:
dev:
CertificateArn: arn:aws:acm:us-east-1:988218269141:certificate/3d110b0f-8b3d-4ddc-bbd8-fab08ae6f038
CloudFrontOAID: E2U9SKLVDD8TPN
HostedZone: dev.leanstacks.net
qa:
CertificateArn: arn:aws:acm:us-east-1:339939222800:certificate/5cd1bce7-1323-4625-a49e-5e72d1cff7ef
CloudFrontOAID: E322H9D7WOKWXW
HostedZone: qa.leanstacks.net
prod:
CertificateArn: arn:aws:acm:us-east-1:854599584783:certificate/fc25a13b-0c9f-4c79-a20f-a13f5d2245b3
CloudFrontOAID: EVMQ2O0M1MS7S
HostedZone: leanstacks.net

Resources:
##
# S3 Bucket for the Storybook App
##
BucketApp:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub
- 'reactstarter-ui-sb.${HostedZone}-${AWS::Region}-${AWS::AccountId}'
- HostedZone: !FindInMap [EnvironmentAttributeMap, !Ref EnvironmentCode, HostedZone]

##
# Bucket Policy allows access from AWS CloudFront
##
BucketPolicyApp:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref BucketApp
PolicyDocument:
Statement:
- Action:
- s3:GetObject
Effect: Allow
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref BucketApp
- '/*'
Principal:
AWS: !Sub
- 'arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOAID}'
- CloudFrontOAID:
!FindInMap [EnvironmentAttributeMap, !Ref EnvironmentCode, CloudFrontOAID]

##
# CloudFront Distribution for the Storybook App - SPA errors and behaviors
##
DistributionApp:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Comment: !Sub 'React Starter UI Storybook (${EnvironmentCode})'
Aliases:
- !Sub
- 'react-starter-storybook.${HostedZone}'
- HostedZone: !FindInMap [EnvironmentAttributeMap, !Ref EnvironmentCode, HostedZone]
CustomErrorResponses:
- ErrorCode: 404
ResponsePagePath: '/index.html'
ResponseCode: 200
- ErrorCode: 403
ResponsePagePath: '/index.html'
ResponseCode: 200
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
DefaultTTL: 60
ForwardedValues:
Cookies:
Forward: none
QueryString: false
TargetOriginId: S3-APP
ViewerProtocolPolicy: redirect-to-https
DefaultRootObject: index.html
Enabled: true
HttpVersion: http2
Origins:
- DomainName: !GetAtt BucketApp.DomainName
Id: S3-APP
S3OriginConfig:
OriginAccessIdentity: !Sub
- 'origin-access-identity/cloudfront/${CloudFrontOAID}'
- CloudFrontOAID:
!FindInMap [EnvironmentAttributeMap, !Ref EnvironmentCode, CloudFrontOAID]
PriceClass: PriceClass_100
ViewerCertificate:
AcmCertificateArn:
!FindInMap [EnvironmentAttributeMap, !Ref EnvironmentCode, CertificateArn]
SslSupportMethod: sni-only

##
# Route53 'A' record for the Storybook CloudFront Distribution
##
RecordSetAppA:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: !Sub
- '${HostedZone}.'
- HostedZone: !FindInMap [EnvironmentAttributeMap, !Ref EnvironmentCode, HostedZone]
Name: !Sub
- 'react-starter-storybook.${HostedZone}'
- HostedZone: !FindInMap [EnvironmentAttributeMap, !Ref EnvironmentCode, HostedZone]
Type: A
AliasTarget:
HostedZoneId: Z2FDTNDATAQYW2
DNSName: !GetAtt DistributionApp.DomainName

##
# Route53 'AAAA' record for the Storybook CloudFront Distribution
##
RecordSetAppAAAA:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: !Sub
- '${HostedZone}.'
- HostedZone: !FindInMap [EnvironmentAttributeMap, !Ref EnvironmentCode, HostedZone]
Name: !Sub
- 'react-starter-storybook.${HostedZone}'
- HostedZone: !FindInMap [EnvironmentAttributeMap, !Ref EnvironmentCode, HostedZone]
Type: AAAA
AliasTarget:
HostedZoneId: Z2FDTNDATAQYW2
DNSName: !GetAtt DistributionApp.DomainName

Outputs:
AppBucketName:
Description: The application S3 bucket name
Value: !Ref BucketApp

DomainName:
Description: The application domain name
Value: !Ref RecordSetAppA
12 changes: 9 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ concurrency:
cancel-in-progress: true

env:
AWS_CFN_TEMPLATE: template.yml
AWS_CFN_TEMPLATE_APP: .aws/cfn/app.yml
AWS_CFN_TEMPLATE_STORYBOOK: .aws/cfn/storybook.yml
AWS_REGION: ${{ vars.AWS_REGION }}
AWS_ROLE_ARN: ${{ vars.AWS_ROLE_ARN_DEV }}
ENV_FILE: ${{ secrets.ENV_CI }}
Expand Down Expand Up @@ -140,7 +141,12 @@ jobs:
role-to-assume: ${{ env.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}

- name: Validate AWS CloudFormation Template
- name: Validate App Template
run: |-
aws cloudformation validate-template \
--template-body file://${{ env.AWS_CFN_TEMPLATE }}
--template-body file://${{ env.AWS_CFN_TEMPLATE_APP }}

- name: Validate Storybook Template
run: |-
aws cloudformation validate-template \
--template-body file://${{ env.AWS_CFN_TEMPLATE_STORYBOOK }}
22 changes: 22 additions & 0 deletions .github/workflows/deploy-app-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Deploy App to Development

on:
push:
branches:
- main
tags:
- dev

concurrency:
group: ${{ github.workflow }}

jobs:
deploy:
name: Deploy App DV
uses: ./.github/workflows/deploy-app.yml
with:
aws_cfn_stack_name: ls-ui-reactstarter-resources-dev
aws_role_arn: ${{ vars.AWS_ROLE_ARN_DEV }}
env: dev
secrets:
env_file: ${{ secrets.ENV_DEV }}
23 changes: 23 additions & 0 deletions .github/workflows/deploy-app-prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Deploy App to Production

on:
release:
types:
- published
push:
tags:
- prod

concurrency:
group: ${{ github.workflow }}

jobs:
deploy:
name: Deploy App PR
uses: ./.github/workflows/deploy-app.yml
with:
aws_cfn_stack_name: ls-ui-reactstarter-resources-prod
aws_role_arn: ${{ vars.AWS_ROLE_ARN_PROD }}
env: prod
secrets:
env_file: ${{ secrets.ENV_PROD }}
22 changes: 22 additions & 0 deletions .github/workflows/deploy-app-qa.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Deploy App to QA

on:
push:
branches:
- release/*
tags:
- qa

concurrency:
group: ${{ github.workflow }}

jobs:
deploy:
name: Deploy App QA
uses: ./.github/workflows/deploy-app.yml
with:
aws_cfn_stack_name: ls-ui-reactstarter-resources-qa
aws_role_arn: ${{ vars.AWS_ROLE_ARN_QA }}
env: qa
secrets:
env_file: ${{ secrets.ENV_QA }}
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
name: Deploy to Development
name: Deploy React App

on:
push:
branches:
- main
tags:
- dev

concurrency:
group: ${{ github.workflow }}

env:
APP_NAME: react-starter.leanstacks.net
AWS_CFN_STACK_NAME: ls-ui-reactstarter-resources-dev
AWS_CFN_TEMPLATE: template.yml
AWS_ENV_CODE: dev
AWS_REGION: ${{ vars.AWS_REGION }}
AWS_ROLE_ARN: ${{ vars.AWS_ROLE_ARN_DEV }}
ENV_FILE: ${{ secrets.ENV_DEV }}
workflow_call:
inputs:
app_name:
required: false
type: string
default: 'react-starter.leanstacks.net'
aws_cfn_stack_name:
required: false
type: string
default: 'ls-ui-reactstarter-resources'
aws_cfn_template:
required: false
type: string
default: '.aws/cfn/app.yml'
aws_region:
required: false
type: string
default: 'us-east-1'
aws_role_arn:
required: true
type: string
env:
required: false
type: string
default: 'dev'
secrets:
env_file:
required: true

jobs:
deploy:
Expand Down Expand Up @@ -45,12 +56,12 @@ jobs:

- name: Create Environment Configuration
run: |
echo "${{ env.ENV_FILE }}" > .env
echo "${{ secrets.ENV_FILE }}" > .env
echo "VITE_BUILD_DATE=$(date +'%Y-%m-%d')" >> .env
echo "VITE_BUILD_TIME=$(date +'%H:%M:%S%z')" >> .env
echo "VITE_BUILD_TS=$(date +'%Y-%m-%dT%H:%M:%S%z')" >> .env
echo "VITE_BUILD_COMMIT_SHA=${{ github.sha }}" >> .env
echo "VITE_BUILD_ENV_CODE=${{ env.AWS_ENV_CODE }}" >> .env
echo "VITE_BUILD_ENV_CODE=${{ inputs.env }}" >> .env
echo "VITE_BUILD_WORKFLOW_NAME=${{ github.workflow }}" >> .env
echo "VITE_BUILD_WORKFLOW_RUN_NUMBER=${{ github.run_number }}" >> .env
echo "VITE_BUILD_WORKFLOW_RUN_ATTEMPT=${{ github.run_attempt }}" >> .env
Expand All @@ -61,23 +72,23 @@ jobs:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
role-to-assume: ${{ inputs.aws_role_arn }}
aws-region: ${{ inputs.aws_region }}

- name: Deploy AWS CloudFormation Stack
run: |-
aws cloudformation deploy \
--stack-name ${{ env.AWS_CFN_STACK_NAME }} \
--template-file ${{ env.AWS_CFN_TEMPLATE }} \
--parameter-overrides EnvironmentCode=${{ env.AWS_ENV_CODE }} \
--tags App=${{ env.APP_NAME }} Env=${{ env.AWS_ENV_CODE }} OU=leanstacks Owner='Matthew Warman'
--stack-name ${{ inputs.aws_cfn_stack_name }} \
--template-file ${{ inputs.aws_cfn_template }} \
--parameter-overrides EnvironmentCode=${{ inputs.env }} \
--tags App=${{ inputs.app_name }} Env=${{ inputs.env }} OU=leanstacks Owner='Matthew Warman'

- name: Get CloudFormation Stack Outputs
id: cloudformation
run: |-
APP_BUCKET_NAME=$(
aws cloudformation describe-stacks \
--stack-name ${{ env.AWS_CFN_STACK_NAME }} \
--stack-name ${{ inputs.aws_cfn_stack_name }} \
--query "Stacks[0].Outputs[?OutputKey=='AppBucketName'].OutputValue | [0]"
)
echo "APP_BUCKET_NAME=$APP_BUCKET_NAME" >> "$GITHUB_OUTPUT"
Expand Down
Loading