Skip to content

Commit 153224b

Browse files
committed
Merge branch 'master' of https://github.com/CMSgov/bluebutton-web-server into jimmyfagan/bb2-4884-CAN-v2
2 parents 12f5b1b + 76796b5 commit 153224b

132 files changed

Lines changed: 5493 additions & 4913 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ BB20_REMOTE_DEBUG_WAIT_ATTACH=false
77
SUPER_USER_NAME=root
88
SUPER_USER_PASSWORD=blue123
99
SUPER_USER_EMAIL=bluebutton@example.com
10-
## DB image migrations
11-
DB_MIGRATIONS=true
1210
## put a place holder Django secret
1311
DJANGO_SECRET_KEY=replace-me-with-real-secret
1412
# This value controls if some unit tests run that require being online.

.github/workflows/deploy-api-fargate.yml

Lines changed: 132 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ on:
1515
description: 'ECR image tag to deploy (e.g. r33)'
1616
required: true
1717
type: string
18+
migration_type:
19+
description: 'Choose when to run database migrations: before updating the service (pre-deploy) or after (post-deploy).'
20+
required: true
21+
type: choice
22+
default: 'none'
23+
options:
24+
- none
25+
- pre-deploy
26+
- post-deploy
1827

1928
env:
2029
AWS_REGION: us-east-1
@@ -23,13 +32,20 @@ permissions:
2332
id-token: write
2433
contents: read
2534

35+
# One active deployment per environment at a time — queue rather than cancel
36+
# so in-progress deploys finish before the next one starts.
37+
concurrency:
38+
group: deploy-api-${{ inputs.environment }}
39+
cancel-in-progress: false
40+
2641
jobs:
27-
deploy:
28-
name: Deploy ${{ inputs.image_tag || github.sha }} to ${{ inputs.environment || 'test' }}
29-
# sandbox uses prod CodeBuild runner (same account)
42+
prepare:
43+
name: Prepare ${{ inputs.image_tag }} for ${{ inputs.environment || 'test' }}
44+
# sandbox shares the prod CodeBuild runner and ECR repo
3045
runs-on:
3146
- codebuild-bb-${{ (inputs.environment || 'test') == 'test' && 'test' || 'prod' }}-web-server-${{ github.run_id }}-${{ github.run_attempt }}
32-
environment: ${{ inputs.environment || 'test' }}
47+
outputs:
48+
task_definition_arn: ${{ steps.register-task.outputs.task_definition_arn }}
3349

3450
steps:
3551
- uses: actions/checkout@v4
@@ -59,7 +75,6 @@ jobs:
5975
id: verify-image
6076
run: |
6177
ENV="${{ inputs.environment || 'test' }}"
62-
# sandbox and prod share the same ECR repo (bb-prod-api)
6378
BUCKET_ENV="${ENV}"
6479
if [[ "$ENV" == "sandbox" ]]; then
6580
BUCKET_ENV="prod"
@@ -79,20 +94,19 @@ jobs:
7994
echo "Image verified: ${REPO_NAME}:${IMAGE_TAG}"
8095
8196
- name: Get current task definition
82-
id: current-task
8397
run: |
8498
ENV="${{ inputs.environment || 'test' }}"
8599
FAMILY="bb-${ENV}-api-family"
86100
87101
echo "Fetching current task definition for ${FAMILY}..."
88102
TASK_DEF=$(aws ecs describe-task-definition --task-definition "$FAMILY" --query 'taskDefinition')
89103
90-
# Update the image in the container definition
104+
CONTAINER_NAME="bb-${ENV}-api"
91105
UPDATED=$(echo "$TASK_DEF" | jq \
92106
--arg IMAGE "${{ steps.verify-image.outputs.image }}" \
93-
'.containerDefinitions[0].image = $IMAGE')
107+
--arg CONTAINER "$CONTAINER_NAME" \
108+
'(.containerDefinitions[] | select(.name == $CONTAINER) | .image) = $IMAGE')
94109
95-
# Strip fields that cannot be included in register-task-definition
96110
CLEANED=$(echo "$UPDATED" | jq 'del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)')
97111
98112
echo "$CLEANED" > /tmp/task-definition.json
@@ -109,17 +123,89 @@ jobs:
109123
echo "task_definition_arn=$NEW_TASK_DEF" >> "$GITHUB_OUTPUT"
110124
echo "Registered: $NEW_TASK_DEF"
111125
126+
# Run migrations before the service update.
127+
# First, we check for pending migrations. Then, we wait for a team member to approve the deployment.
128+
# Finally, we run the migrations. If any of these steps fail, the deployment stops to prevent issues.
129+
130+
pre-showmigrations:
131+
name: Pre-deploy showmigrations on ${{ inputs.environment || 'test' }}
132+
needs: prepare
133+
if: inputs.migration_type == 'pre-deploy'
134+
uses: ./.github/workflows/run-manage-command.yml
135+
with:
136+
environment: ${{ inputs.environment || 'test' }}
137+
command: showmigrations
138+
task_definition_arn: ${{ needs.prepare.outputs.task_definition_arn }}
139+
secrets: inherit
140+
141+
approve-pre-migration:
142+
name: Approve pre-deploy migration on ${{ inputs.environment || 'test' }}
143+
needs: pre-showmigrations
144+
if: inputs.migration_type == 'pre-deploy'
145+
runs-on: ubuntu-latest
146+
timeout-minutes: 60
147+
environment: ${{ inputs.environment || 'test' }}
148+
steps:
149+
- name: Confirm approval
150+
run: echo "Approved by ${{ github.actor }} — running migrate --noinput against the new image."
151+
152+
pre-migrate:
153+
name: Pre-deploy migrate --noinput on ${{ inputs.environment || 'test' }}
154+
needs: [prepare, approve-pre-migration]
155+
if: inputs.migration_type == 'pre-deploy'
156+
uses: ./.github/workflows/run-manage-command.yml
157+
with:
158+
environment: ${{ inputs.environment || 'test' }}
159+
command: migrate --noinput
160+
task_definition_arn: ${{ needs.prepare.outputs.task_definition_arn }}
161+
secrets: inherit
162+
163+
update-service:
164+
name: Deploy ${{ inputs.image_tag || github.sha }} to ${{ inputs.environment || 'test' }}
165+
needs: [prepare, pre-showmigrations, approve-pre-migration, pre-migrate]
166+
if: ${{ !failure() && !cancelled() }}
167+
runs-on:
168+
- codebuild-bb-${{ (inputs.environment || 'test') == 'test' && 'test' || 'prod' }}-web-server-${{ github.run_id }}-${{ github.run_attempt }}
169+
# Gate the deploy for 'none' and 'post-deploy' — in both cases the deploy happens
170+
# before any migration approval, so it needs its own gate.
171+
# Only 'pre-deploy' skips this gate: its approval already ran upstream (approve-pre-migration),
172+
# and the deploy auto-follows the same image right after the migration.
173+
environment: ${{ inputs.migration_type != 'pre-deploy' && (inputs.environment || 'test') || '' }}
174+
175+
steps:
176+
- uses: actions/checkout@v4
177+
178+
- name: Setup AWS credentials
179+
uses: ./.github/actions/setup-tofu
180+
with:
181+
environment: ${{ inputs.environment || 'test' }}
182+
non-prod-account: ${{ secrets.NON_PROD_ACCOUNT }}
183+
prod-account: ${{ secrets.PROD_ACCOUNT }}
184+
test-role-id: ${{ secrets.TEST_AWS_ROLE_ID_MASK }}
185+
prod-role-id: ${{ secrets.PROD_AWS_ROLE_ID_MASK }}
186+
112187
- name: Update ECS service
113188
run: |
114189
ENV="${{ inputs.environment || 'test' }}"
115190
CLUSTER="bb-${ENV}-cluster"
116191
SERVICE="bb-${ENV}-api-service"
192+
TASK_DEF="${{ needs.prepare.outputs.task_definition_arn }}"
193+
194+
if [[ -z "$TASK_DEF" ]]; then
195+
echo "Warning: TASK_DEF from prepare job is empty. Querying the latest task definition for family bb-${ENV}-api-family..."
196+
TASK_DEF=$(aws ecs describe-task-definition --task-definition "bb-${ENV}-api-family" --query 'taskDefinition.taskDefinitionArn' --output text)
197+
fi
117198
118-
echo "Updating ${SERVICE} on ${CLUSTER}..."
199+
if [[ -z "$TASK_DEF" ]]; then
200+
echo "::error::Could not resolve task definition ARN."
201+
exit 1
202+
fi
203+
204+
echo "Updating ${SERVICE} on ${CLUSTER} with task definition ${TASK_DEF}..."
119205
aws ecs update-service \
120206
--cluster "$CLUSTER" \
121207
--service "$SERVICE" \
122-
--task-definition "${{ steps.register-task.outputs.task_definition_arn }}" \
208+
--task-definition "$TASK_DEF" \
123209
--force-new-deployment \
124210
--query 'service.serviceName' \
125211
--output text
@@ -139,3 +225,38 @@ jobs:
139225
}
140226
141227
echo "Deployment complete and stable."
228+
229+
# Run migrations after the service update.
230+
# The new code is already running, so we run migrations on the live database.
231+
# We still check for pending migrations, wait for approval, and then run them.
232+
233+
post-showmigrations:
234+
name: Post-deploy showmigrations on ${{ inputs.environment || 'test' }}
235+
needs: update-service
236+
if: inputs.migration_type == 'post-deploy'
237+
uses: ./.github/workflows/run-manage-command.yml
238+
with:
239+
environment: ${{ inputs.environment || 'test' }}
240+
command: showmigrations
241+
secrets: inherit
242+
243+
approve-post-migration:
244+
name: Approve post-deploy migration on ${{ inputs.environment || 'test' }}
245+
needs: post-showmigrations
246+
if: inputs.migration_type == 'post-deploy'
247+
runs-on: ubuntu-latest
248+
timeout-minutes: 60
249+
environment: ${{ inputs.environment || 'test' }}
250+
steps:
251+
- name: Confirm approval
252+
run: echo "Approved by ${{ github.actor }} — running migrate --noinput against the live service."
253+
254+
post-migrate:
255+
name: Post-deploy migrate --noinput on ${{ inputs.environment || 'test' }}
256+
needs: approve-post-migration
257+
if: inputs.migration_type == 'post-deploy'
258+
uses: ./.github/workflows/run-manage-command.yml
259+
with:
260+
environment: ${{ inputs.environment || 'test' }}
261+
command: migrate --noinput
262+
secrets: inherit

.github/workflows/publish-release.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
with:
1919
fetch-depth: 0
2020
fetch-tags: true
21+
ref: ${{ github.ref }}
2122

2223
- name: Verify on master branch
2324
run: |
@@ -70,7 +71,7 @@ jobs:
7071
BODY="${NEW_TAG} - ${RELEASE_DATE}"
7172
BODY="${BODY}\n================"
7273
73-
while IFS= read -r line; do
74+
while IFS= read -r line || [[ -n "$line" ]]; do
7475
HASH=$(echo "$line" | cut -d' ' -f1)
7576
SUBJECT=$(echo "$line" | cut -d' ' -f2-)
7677
@@ -85,7 +86,7 @@ jobs:
8586
BODY="${BODY}\n- ${SUBJECT}"
8687
fi
8788
fi
88-
done < <(git log --pretty=format:'%H %s' ${PREV_TAG}..HEAD)
89+
done < <(git log --pretty=tformat:'%H %s' ${PREV_TAG}..HEAD)
8990
9091
echo -e "$BODY" > /tmp/release_notes.md
9192
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: Pull Request Checks
2+
3+
on:
4+
pull_request:
5+
branches: [master]
6+
paths-ignore:
7+
- 'docs/**'
8+
- '*.md'
9+
workflow_dispatch:
10+
11+
jobs:
12+
ruff:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Install python dependencies
20+
run: |
21+
python3 -m venv venv
22+
source venv/bin/activate
23+
python3 -m pip install --upgrade pip setuptools wheel
24+
pip install -r requirements/requirements.dev.txt --no-deps --prefer-binary --require-hashes
25+
26+
- name: Run Ruff Linter
27+
run: |
28+
source venv/bin/activate
29+
ruff check
30+
31+
unit-tests:
32+
runs-on: ubuntu-latest
33+
34+
steps:
35+
- name: Checkout code
36+
uses: actions/checkout@v4
37+
38+
- name: Install python dependencies
39+
run: |
40+
python3 -m venv venv
41+
source venv/bin/activate
42+
python3 -m pip install --upgrade pip setuptools wheel
43+
pip install -r requirements/requirements.dev.txt --no-deps --prefer-binary --require-hashes
44+
45+
- name: Run Unit Tests
46+
run: |
47+
source venv/bin/activate
48+
pytest -m 'not integration'
49+
50+
integration-tests:
51+
needs: [ruff, unit-tests]
52+
env:
53+
AWS_REGION: us-east-1
54+
55+
permissions:
56+
id-token: write
57+
contents: read
58+
59+
# This will only run on test
60+
runs-on: codebuild-bb-test-web-server-${{ github.run_id }}-${{ github.run_attempt }}
61+
62+
steps:
63+
- name: Checkout Code
64+
uses: actions/checkout@v4
65+
66+
- name: Setup AWS credentials
67+
uses: ./.github/actions/setup-tofu
68+
with:
69+
environment: test
70+
non-prod-account: ${{ secrets.NON_PROD_ACCOUNT }}
71+
prod-account: ${{ secrets.PROD_ACCOUNT }}
72+
test-role-id: ${{ secrets.TEST_AWS_ROLE_ID_MASK }}
73+
prod-role-id: ${{ secrets.PROD_AWS_ROLE_ID_MASK }}
74+
75+
- name: Build BBAPI
76+
run: |
77+
cd ./ops/containers/bb-api
78+
make build-codebuild
79+
80+
- name: Start Stack
81+
run: |
82+
cd ./ops/containers/bb-api
83+
make run-codebuild
84+
85+
- name: Execute Integration Tests
86+
run: |
87+
cd ./ops/containers/bb-api
88+
make run-codebuild-integration
89+
90+
- name: Teardown Stack
91+
if: always()
92+
run: |
93+
cd ./ops/containers/bb-api
94+
make teardown-codebuild

0 commit comments

Comments
 (0)