-
Notifications
You must be signed in to change notification settings - Fork 0
401 lines (347 loc) · 14.9 KB
/
pr-commit-stage.yml
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
name: PR Commit Stage
# This workflow is triggered on pull requests to the main branch
on:
pull_request:
branches: [ main ]
jobs:
checkout_and_lint:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '14.17'
- name: Cache Node Modules
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
# Cache dependencies using a key for installers and dependencies
path: node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Install Dependencies
run: npm install
- name: Run Lint
run: npm run lint
test:
needs: checkout_and_lint
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '14.17'
- name: Cache Node Modules
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
# Cache dependencies using a key for installers and dependencies
path: node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: No-op Test Placeholder
run: echo "No tests implemented yet"
build-image:
needs: [ test ]
runs-on: ubuntu-latest
outputs:
imageURL: ${{ steps.generate_ghcr_tag.outputs.image }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: generate ghcr tag
id: generate_ghcr_tag
run: |
SHORT_SHA=${{ github.event.pull_request.head.sha }}
SHORT_SHA=${SHORT_SHA:0:7} # Using Bash substring extraction
echo "image=ghcr.io/${{ github.repository }}/nextjs-app:${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }}-$SHORT_SHA" >> $GITHUB_OUTPUT
- name: Build and Push Docker Image
uses: docker/build-push-action@v5
with:
build-args: |
MAPBOX_API_TOKEN=${{secrets.MAPBOX_API_TOKEN}}
platforms: linux/amd64
context: .
file: ./Dockerfile
push: true
tags: |
${{ steps.generate_ghcr_tag.outputs.image }}
- name: Comment PR with GHCR details
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
📦 New Docker Image has been pushed to Github Container Registry (GHCR)
Image: ${{ steps.generate_ghcr_tag.outputs.image }}
setup-copilot:
runs-on: ubuntu-latest
outputs:
copilot-path: ${{ steps.setup.outputs.copilot-path }}
steps:
- name: Create a temporary directory for downloading
id: setup
run: |
mkdir -p ${{ runner.temp }}/copilot-download
echo "copilot-path=${{ runner.temp }}/copilot-download/copilot" >> $GITHUB_OUTPUT
- name: Download Copilot CLI
run: |
curl -Lo ${{ steps.setup.outputs.copilot-path }} https://github.com/aws/copilot-cli/releases/latest/download/copilot-linux
- name: Make binary executable
run: chmod +x ${{ steps.setup.outputs.copilot-path }}
- name: Upload Copilot CLI to Artifacts
uses: actions/upload-artifact@v4
with:
name: copilot-cli
path: ${{ steps.setup.outputs.copilot-path }}
init-copilot:
runs-on: ubuntu-latest
needs: setup-copilot
steps:
- name: Download Copilot CLI from Artifacts
uses: actions/download-artifact@v4
with:
name: copilot-cli
path: /usr/local/bin
- name: Ensure Copilot is executable
run: chmod +x /usr/local/bin/copilot
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/ocean-watch-deployer
role-duration-seconds: 1800
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Check for existing Copilot application
id: check_app
run: |
if copilot app ls | grep -qw "ocean-watch"; then
echo "App exists."
echo "app_exists=true" >> $GITHUB_ENV
else
echo "App does not exist."
echo "app_exists=false" >> $GITHUB_ENV
fi
- name: Notify User That A Bootstrap is Needed
if: env.app_exists == 'false'
run: |
echo "Manually run the `bootstrap-copilot-project` workflow first."
exit 1
shell: bash
create-copilot-environment:
needs: [ init-copilot ]
runs-on: ubuntu-latest
steps:
- name: Download Copilot CLI from Artifacts
uses: actions/download-artifact@v4
with:
name: copilot-cli
path: /usr/local/bin
- name: Ensure Copilot is executable
run: chmod +x /usr/local/bin/copilot
- name: Configure AWS Credentials
id: creds
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/ocean-watch-deployer
role-duration-seconds: 1800
output-credentials: true
- name: Checkout Repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Check for existing Copilot environment
id: check_environment
run: |
if copilot env show --name ${{ github.head_ref }} --json; then
echo "Environment exists."
echo "environment_exists=true" >> $GITHUB_ENV
else
echo "Environment does not exist."
echo "environment_exists=false" >> $GITHUB_ENV
fi
- name: Initialize Environment
id: init-environment
if: env.environment_exists == 'false'
run: |
if ! copilot env init --name ${{ github.head_ref }} --app ocean-watch --default-config --region ${{ secrets.AWS_REGION }} --aws-session-token ${{ steps.creds.outputs.aws-session-token }}; then
echo "Failed to initialize environment."
exit 1
fi
- name: Deploy Environment
run: |
if ! copilot env deploy --name ${{ github.head_ref }} --app ocean-watch; then
echo "Failed to deploy environment."
exit 1
fi
- name: Commit copilot environment configs
run: |
git config --global user.email "[email protected]"
git config --global user.name "GitHub Action"
git add -A # Adds all changes, including untracked files
git diff-index --quiet HEAD || git commit -m "AWS copilot environment configs generated by GitHub Actions Bot"
git push origin HEAD:${{ github.head_ref }} # Ensure you're pushing to the correct branch
deploy:
needs: [ build-image, create-copilot-environment ]
runs-on: ubuntu-latest
steps:
- name: Download Copilot CLI from Artifacts
uses: actions/download-artifact@v4
with:
name: copilot-cli
path: /usr/local/bin
- name: Ensure Copilot is executable
run: chmod +x /usr/local/bin/copilot
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/ocean-watch-deployer
role-duration-seconds: 1800
- name: Checkout Repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Handle AWS Secret --> GHCR Access
run: |
# Install jq if it's not available
sudo apt-get update && sudo apt-get install -y jq
SECRET_NAME="ocean-watch-env-${{ github.head_ref }}"
SECRET_VALUE='{"username":"${{ secrets.AWS_GHCR_ACCESS_TOKEN }}","password":"${{ secrets.AWS_GHCR_ACCESS_TOKEN }}"}'
TAGS='Key=project,Value=OceanWatch Key=program,Value=Oceans Key=application,Value=OceanWatch Key=copilot-application,Value=ocean-watch Key=copilot-environment,Value=${{ github.head_ref }}'
DESCRIPTION='Read-only access to github container registry'
# Check if the AWS Secret already exists
SECRET_INFO=$(aws secretsmanager describe-secret --secret-id $SECRET_NAME || echo "not_found")
if [[ "$SECRET_INFO" == "not_found" ]]; then
echo "Secret does not exist, creating..."
# Create the secret and extract the ARN
SECRET_OUTPUT=$(aws secretsmanager create-secret --name $SECRET_NAME --secret-string "$SECRET_VALUE" --tags $TAGS --description "$DESCRIPTION")
SECRET_ARN=$(echo $SECRET_OUTPUT | jq -r .ARN)
echo "Secret created with ARN: $SECRET_ARN"
else
echo "Secret already exists."
# Extract the ARN from existing secret info
SECRET_ARN=$(echo $SECRET_INFO | jq -r .ARN)
fi
# Store the ARN for use in subsequent steps
echo "SECRET_ARN=$SECRET_ARN" >> $GITHUB_ENV
- name: Check for existing Copilot service deployment
id: check_service_deployment
run: |
if copilot svc show --name nextjs-app --json; then
echo "Service exists."
echo "service_exists=true" >> $GITHUB_ENV
else
echo "Service does not exist."
echo "service_exists=false" >> $GITHUB_ENV
fi
- name: Initialize Service
id: init-service
if: env.service_exists == 'false'
run: |
export IMAGE_LOCATION="${{ needs.build-image.outputs.imageURL }}"
export GHCR_ACCESS="${{ env.SECRET_ARN }}"
if ! copilot svc init --app ocean-watch --name nextjs-app --svc-type "Load Balanced Web Service"; then
echo "Failed to initialize service."
exit 1
fi
- name: Deploy App to AWS using Copilot
run: |
export IMAGE_LOCATION="${{ needs.build-image.outputs.imageURL }}"
export GHCR_ACCESS="${{ env.SECRET_ARN }}"
if ! copilot svc deploy --force --name nextjs-app --env ${{ github.head_ref }}; then
echo "Failed to deploy service."
copilot svc delete --name nextjs-app --env ${{ github.head_ref }} --yes
exit 1
fi
- name: Show Service Information
id: service_info
run: |
ENV_NAME="${{ github.head_ref }}"
SERVICE_JSON=$(copilot svc show --app ocean-watch --name nextjs-app --json)
SERVICE_URL=$(echo "$SERVICE_JSON" | jq -r --arg ENV_NAME "$ENV_NAME" '.routes[] | select(.environment == $ENV_NAME) | .url')
if [[ -z "$SERVICE_URL" || "$SERVICE_URL" == "null" ]]; then
echo "No URL found for the specified environment: $ENV_NAME"
echo "$SERVICE_JSON"
exit 1
fi
echo "url=$SERVICE_URL" >> $GITHUB_OUTPUT
echo "Service URL: $SERVICE_URL"
- name: Comment PR with Service URL
if: github.event_name == 'pull_request'
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
🚀 Deployment successful!
🌐 Your service in environment `${{ github.head_ref }}` is now available at: ${{ steps.service_info.outputs.url }}
- name: Commit Copilot Service Configs
id: commit-changes
run: |
# Capture the original SHA for comparison
ORIG_SHA="${{ github.event.pull_request.head.sha }}"
git config --global user.email "[email protected]"
git config --global user.name "GitHub Action"
git add -A # Adds all changes, including untracked files
git diff-index --quiet HEAD || git commit -m "AWS copilot configs generated by GitHub Actions Bot"
git push origin HEAD:${{ github.head_ref }} # Ensure you're pushing to the correct branch
# Capture the current SHA after potential commit
CURRENT_SHA=$(git rev-parse HEAD)
# Compare SHAs to determine if a new commit was made
if [ "$ORIG_SHA" != "$CURRENT_SHA" ]; then
echo "AWS Copilot Configuration Changes Detected."
echo "config_changes_exist=true" >> $GITHUB_ENV
else
echo "No AWS Copilot Configuration Changes Detected."
echo "config_changes_exist=false" >> $GITHUB_ENV
fi
shell: bash
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Add Updated SHA to GHCR Image
if: env.config_changes_exist == 'true'
run: |
ORIG_SHORT_SHA=${{ github.event.pull_request.head.sha }}
ORIG_SHORT_SHA=${ORIG_SHORT_SHA:0:7} # Using Bash substring extraction
CURRENT_SHORT_SHA=$(git rev-parse HEAD)
CURRENT_SHORT_SHA=${CURRENT_SHORT_SHA:0:7} # Using Bash substring extraction
docker pull ghcr.io/${{ github.repository }}/nextjs-app:${{ github.event.pull_request.head.ref }}-$ORIG_SHORT_SHA
docker tag ghcr.io/${{ github.repository }}/nextjs-app:${{ github.event.pull_request.head.ref }}-$ORIG_SHORT_SHA ghcr.io/${{ github.repository }}/nextjs-app:${{ github.event.pull_request.head.ref }}-$CURRENT_SHORT_SHA
docker push --all-tags ghcr.io/${{ github.repository }}/nextjs-app
shell: bash