-
Notifications
You must be signed in to change notification settings - Fork 0
194 lines (175 loc) · 8.7 KB
/
code-deploy-client.yml
File metadata and controls
194 lines (175 loc) · 8.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
name: Sync content with S3 Staging/Beta
on:
workflow_call:
inputs:
AWS_ACCOUNT:
required: true
type: string
STACK:
required: true
type: string
WORKING_DIR:
required: true
type: string
TARGET_BRANCH:
required: true
type: string
DOMAIN:
required: true
type: string
BUILD_DIR:
required: true
type: string
# TODO(cleanup): once Wallet beta is merged into main and all
# callers have stopped passing this input, remove both the input
# and the "Invalidate additional CloudFront distributions" step
# below. The WalletCoopStack ↔ PersonStack pairing is now handled
# automatically by the dedicated step further down — no caller
# needs to opt in. Kept here only so an in-flight Wallet beta
# workflow that still passes EXTRA_DISTRIBUTION_STACKS doesn't
# error with "unknown input".
EXTRA_DISTRIBUTION_STACKS:
required: false
type: string
default: ''
description: |
DEPRECATED — paired-distribution invalidation is now hard-coded
for WalletCoopStack ↔ PersonStack (see step below). Input kept
accepted for one merge cycle so existing callers don't break.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
# GitHub-Slack app sends a workflow status message with live updates to #code-* channel
sync:
name: Upload to Amazon S3
runs-on: ubuntu-24.04
permissions:
id-token: write
contents: read
steps:
- name: Build role name
run: |
# Use shell string manipulation to extract the repository name
REPO_NAME="${GITHUB_REPOSITORY#*/}"
ROLE_NAME="arn:aws:iam::${{ inputs.AWS_ACCOUNT }}:role/${REPO_NAME}-repo"
# Set the environment variable for future steps
echo "ROLE_NAME=${ROLE_NAME}" >> $GITHUB_ENV
- name: Configure web-sync AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.ROLE_NAME }}
aws-region: us-west-2
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.TARGET_BRANCH }}
- name: Get HELLO_VERSION
run: |
PACKAGE_FILE="package.json"
VERSION=$(jq -r '.version' "$PACKAGE_FILE")
echo "HELLO_VERSION=${VERSION}" >> $GITHUB_ENV
- name: Check repo version vs staged version
if: ${{ inputs.TARGET_BRANCH == 'main' }}
run: |
STAGE_VERSION=$(curl -sI "https://${{ inputs.DOMAIN }}/" | grep -i "x-amz-meta-version" | awk '{print $2}' | tr -d '\r')
echo "HELLO_VERSION: $HELLO_VERSION"
echo "STAGE_VERSION: $STAGE_VERSION"
if [ $STAGE_VERSION = $HELLO_VERSION ]; then
echo "$HELLO_VERSION has already been staged."
exit 1
fi
# Restore npm dependencies -----------------------
- name: Restore client node_modules
uses: actions/cache/restore@v4
id: client-node-modules-cache
with:
path: ./${{ inputs.WORKING_DIR }}/node_modules
key: ${{ runner.os }}-${{ runner.arch }}-client-node-modules-${{ hashFiles(format('{0}/package-lock.json', inputs.WORKING_DIR)) }}
- name: Install client dependencies
if: steps.client-node-modules-cache.outputs.cache-hit != 'true'
run: cd ${{ inputs.WORKING_DIR }} && npm ci
# ------------------------------------------------
- name: Build content
run: cd ${{ inputs.WORKING_DIR }} && npm run build
- name: Get bucket and distribution_id
run: |
BUCKET_NAME=$(aws cloudformation describe-stacks --stack-name ${{ inputs.STACK }} --query 'Stacks[0].Outputs[?OutputKey==`BucketNameOutput`].OutputValue' --output text)
DISTRIBUTION_ID=$(aws cloudformation describe-stacks --stack-name ${{ inputs.STACK }} --query 'Stacks[0].Outputs[?OutputKey==`DistributionIdOutput`].OutputValue' --output text)
echo "BUCKET_NAME=${BUCKET_NAME}" >> $GITHUB_ENV
echo "DISTRIBUTION_ID=${DISTRIBUTION_ID}" >> $GITHUB_ENV
- name: Cleanup S3 bucket
run: aws s3 rm s3://${BUCKET_NAME} --recursive
- name: Create versioned copies of root files for rollback and cp to S3
run: |
cd ${{inputs.BUILD_DIR}}
for file in *; do
if [ -f "$file" ]; then
aws s3 cp --metadata version=${HELLO_VERSION} --content-type "text/html; charset=UTF-8" --cache-control max-age=0 ${file} s3://${BUCKET_NAME}/
# dont create version files when deploying to beta
if [ "${{ inputs.TARGET_BRANCH }}" != "beta" ]; then
aws s3 cp --metadata version=${HELLO_VERSION} --content-type "text/html; charset=UTF-8" --cache-control max-age=0 ${file} s3://${BUCKET_NAME}/${HELLO_VERSION}/${file}
fi
fi
done
- name: Copy S3 assets to S3 bucket with the AWS CLI
run: aws s3 cp --metadata version=${HELLO_VERSION} ${{inputs.BUILD_DIR}}/assets s3://${BUCKET_NAME}/assets --recursive
- name: Upload .well-known directory if present
run: |
cd ${{inputs.BUILD_DIR}}
if [ -d ".well-known" ]; then
aws s3 cp --metadata version=${HELLO_VERSION} --content-type "application/json" --cache-control max-age=3600 .well-known/ s3://${BUCKET_NAME}/.well-known/ --recursive
fi
- name: Upload mobile fallback to sub-paths
run: |
cd ${{inputs.BUILD_DIR}}
if [ -f "mobile" ]; then
aws s3 cp --metadata version=${HELLO_VERSION} --content-type "text/html; charset=UTF-8" --cache-control max-age=0 mobile s3://${BUCKET_NAME}/mobile/callback
fi
- name: Invalidate CloudFront cache
run: aws cloudfront create-invalidation --distribution-id ${DISTRIBUTION_ID} --paths "/*"
# WalletCoopStack and PersonStack share a single S3 bucket (the
# wallet bucket) — PersonStack's CloudFront distribution serves
# person.<domain> from that same origin. A client deploy that
# uploads to the wallet bucket therefore has to invalidate both
# distributions; otherwise person.<domain> serves stale assets
# until its default TTL expires.
#
# PersonStack grants this OIDC role cloudfront:CreateInvalidation
# on its distribution (non-prod only — prod client deploys go
# through hellocoop/Deploy with its own role + invalidation).
#
# Hard-coded coupling instead of a generic input because no other
# consumer of this reusable workflow has a paired distribution
# today. If that changes, switch to a configurable mapping.
- name: Invalidate paired Person distribution (WalletCoopStack only)
if: ${{ inputs.STACK == 'WalletCoopStack' }}
run: |
PERSON_DIST_ID=$(aws cloudformation describe-stacks --stack-name PersonStack --query 'Stacks[0].Outputs[?OutputKey==`DistributionIdOutput`].OutputValue' --output text)
if [ -z "$PERSON_DIST_ID" ] || [ "$PERSON_DIST_ID" = "None" ]; then
echo "::error::WalletCoopStack deploy expected a paired PersonStack with DistributionIdOutput, but none was found."
exit 1
fi
echo "Invalidating paired PersonStack ($PERSON_DIST_ID)"
aws cloudfront create-invalidation --distribution-id "$PERSON_DIST_ID" --paths "/*"
# TODO(cleanup): remove this step (and the EXTRA_DISTRIBUTION_STACKS
# input above) once Wallet's beta has merged to main and all caller
# workflows have dropped the input. Kept temporarily so an
# in-flight Wallet beta deploy that still passes the input doesn't
# break. Note: when both this AND the auto-paired step run for a
# WalletCoopStack deploy, PersonStack gets invalidated twice —
# harmless (CloudFront /* invalidations are effectively free) but
# noisy.
- name: Invalidate additional CloudFront distributions (DEPRECATED)
if: ${{ inputs.EXTRA_DISTRIBUTION_STACKS != '' }}
run: |
IFS=',' read -ra STACKS <<< "${{ inputs.EXTRA_DISTRIBUTION_STACKS }}"
for STACK in "${STACKS[@]}"; do
STACK="${STACK// /}"
EXTRA_DIST_ID=$(aws cloudformation describe-stacks --stack-name "$STACK" --query 'Stacks[0].Outputs[?OutputKey==`DistributionIdOutput`].OutputValue' --output text)
if [ -z "$EXTRA_DIST_ID" ] || [ "$EXTRA_DIST_ID" = "None" ]; then
echo "::error::DistributionIdOutput not found on stack $STACK"
exit 1
fi
echo "Invalidating $STACK ($EXTRA_DIST_ID)"
aws cloudfront create-invalidation --distribution-id "$EXTRA_DIST_ID" --paths "/*"
done