Skip to content

Commit 1ead1cc

Browse files
authored
Merge pull request #559 from NHSDigital/feature/thju1-NRL-633-persistentPREnvironments
NRL-633 Persistent Environments for Pull Requests
2 parents 837a4b0 + 1d47eaf commit 1ead1cc

File tree

3 files changed

+187
-74
lines changed

3 files changed

+187
-74
lines changed
Lines changed: 84 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,45 @@
1-
name: CI
1+
name: Deploy PR Environment
2+
run-name: "${{ github.event.action == 'synchronize' && 'Update' || 'Create' }} PR Environment - #${{ github.event.pull_request.number }} (${{ github.event.pull_request.title }})"
23

3-
on: pull_request
4+
on:
5+
pull_request:
6+
types: [opened, reopened, synchronize]
7+
8+
concurrency:
9+
group: environment-${{ github.event.pull_request.number }}
10+
cancel-in-progress: false
411

512
permissions:
613
id-token: write
714
contents: read
815
actions: write
16+
issues: write
17+
pull-requests: write
918

1019
jobs:
11-
set-uniquish-id:
12-
# Set a uniquish ID - good enough for our purposes since it must be close enough to unique for
13-
# a) Terraform / AWS to allow clean build/destroys without side-effects (e.g. we don't
14-
# want resources marked for deletion to be recreated in another CI run)
15-
# b) Not to fall foul of character limits on AWS resource names: the ID must be short
16-
name: Set Unique Environment ID
20+
set-environment-id:
21+
name: Set Environment ID
1722
runs-on: [self-hosted, ci]
1823
steps:
19-
- name: Set a uniquish ID
20-
id: set_uniqish_id
24+
- name: Set a ID based on the branch name
25+
id: set_environment_id
2126
run: |
22-
TIME_IN_SECONDS_SINCE_MIDNIGHT=$(date -d "1970-01-01 UTC $(date +%T)" +%s)
23-
echo "uniqish_id=${GITHUB_SHA::7}-${TIME_IN_SECONDS_SINCE_MIDNIGHT}" >> $GITHUB_OUTPUT
27+
JIRA_TICKET=$(
28+
echo '${{ github.event.pull_request.head.ref }}' | \
29+
grep -Po --color=none '[A-z]{3,4}-[0-9]{3,5}' | \
30+
sed 's/-//g' | \
31+
tr '[:upper:]' '[:lower:]' || \
32+
true
33+
)
34+
BRANCH_HASH=$(echo '${{ github.event.pull_request.head.ref }}${{ github.event.pull_request.id }}' | sha256sum | head -c 6)
35+
36+
if [ -z "$JIRA_TICKET" ]; then
37+
echo "environment_id=${BRANCH_HASH}" > $GITHUB_OUTPUT
38+
else
39+
echo "environment_id=${JIRA_TICKET}-${BRANCH_HASH}" > $GITHUB_OUTPUT
40+
fi
2441
outputs:
25-
uniqish_id: ${{ steps.set_uniqish_id.outputs.uniqish_id }}
42+
environment_id: ${{ steps.set_environment_id.outputs.environment_id }}
2643

2744
build:
2845
name: Build Application
@@ -67,10 +84,23 @@ jobs:
6784
name: build-artifacts
6885
path: dist/*.zip
6986

87+
- name: Add Failure Pull Request Comment
88+
uses: actions/github-script@v7
89+
if: ${{ failure() }}
90+
with:
91+
script: |
92+
github.rest.issues.createComment({
93+
issue_number: context.issue.number,
94+
owner: context.repo.owner,
95+
repo: context.repo.repo,
96+
body: `💥 Something went wrong while building the pull request environment.\n[Check Output Logs](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`
97+
})
98+
7099
deploy:
71-
name: Deploy CI Environment
100+
name: Deploy PR Environment
72101
runs-on: [self-hosted, ci]
73-
needs: [set-uniquish-id, build]
102+
needs: [set-environment-id, build]
103+
74104
steps:
75105
- name: Git Clone - ${{ github.event.pull_request.head.ref }}
76106
uses: actions/checkout@v4
@@ -99,7 +129,7 @@ jobs:
99129
with:
100130
aws-region: eu-west-2
101131
role-to-assume: ${{ secrets.CI_ROLE_NAME }}
102-
role-session-name: github-actions-ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}
132+
role-session-name: github-actions-ci-${{ needs.set-environment-id.outputs.environment_id }}
103133

104134
- name: Retrieve Server Certificates
105135
run: aws s3 cp s3://nhsd-nrlf--truststore/server/dev.pem truststore/server/dev.pem
@@ -111,8 +141,8 @@ jobs:
111141
- name: Terraform Init
112142
run: |
113143
terraform -chdir=terraform/infrastructure init
114-
terraform -chdir=terraform/infrastructure workspace new ci-${{ needs.set-uniquish-id.outputs.uniqish_id }} || \
115-
terraform -chdir=terraform/infrastructure workspace select ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}
144+
terraform -chdir=terraform/infrastructure workspace new ${{ needs.set-environment-id.outputs.environment_id }} || \
145+
terraform -chdir=terraform/infrastructure workspace select ${{ needs.set-environment-id.outputs.environment_id }}
116146
117147
- name: Terraform Plan
118148
run: |
@@ -129,6 +159,7 @@ jobs:
129159
path: terraform/infrastructure/tfplan*
130160

131161
- name: Terraform Apply
162+
id: terraform-apply
132163
run: |
133164
terraform -chdir=terraform/infrastructure apply tfplan
134165
@@ -138,9 +169,33 @@ jobs:
138169
name: terraform-outputs
139170
path: terraform/infrastructure/output.json
140171

172+
- name: Add Success Pull Request Comment
173+
uses: actions/github-script@v7
174+
if: ${{ success() }}
175+
with:
176+
script: |
177+
github.rest.issues.createComment({
178+
issue_number: context.issue.number,
179+
owner: context.repo.owner,
180+
repo: context.repo.repo,
181+
body: "🚀 PR environment successfully deployed.\nCommit Hash: `${{ github.event.pull_request.head.sha }}`\nURL: https://${{ needs.set-environment-id.outputs.environment_id }}.api.record-locator.dev.national.nhs.uk/"
182+
})
183+
184+
- name: Add Failure Pull Request Comment
185+
uses: actions/github-script@v7
186+
if: ${{ failure() }}
187+
with:
188+
script: |
189+
github.rest.issues.createComment({
190+
issue_number: context.issue.number,
191+
owner: context.repo.owner,
192+
repo: context.repo.repo,
193+
body: `💥 Something went wrong while deploying the pull request environment.\n[Check Output Logs](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`
194+
})
195+
141196
integration-test:
142197
name: Run Integration Tests
143-
needs: [set-uniquish-id, deploy]
198+
needs: [set-environment-id, deploy]
144199
runs-on: [self-hosted, ci]
145200

146201
steps:
@@ -168,7 +223,7 @@ jobs:
168223
with:
169224
aws-region: eu-west-2
170225
role-to-assume: ${{ secrets.CI_ROLE_NAME }}
171-
role-session-name: github-actions-ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}
226+
role-session-name: github-actions-ci-${{ needs.set-environment-id.outputs.environment_id }}
172227

173228
- name: Retrieve Client Certificates
174229
run: |
@@ -182,21 +237,21 @@ jobs:
182237
- name: Configure Dev Account Credentials
183238
id: configure-dev-account-credentials
184239
run: |
185-
aws_credentials=$(aws sts assume-role --role-arn arn:aws:iam::${{ steps.get_account_id.outputs.aws_account_id }}:role/terraform --role-session-name github-actions-ci-${{ needs.set-uniquish-id.outputs.uniqish_id }} --output json)
240+
aws_credentials=$(aws sts assume-role --role-arn arn:aws:iam::${{ steps.get_account_id.outputs.aws_account_id }}:role/terraform --role-session-name github-actions-ci-${{ needs.set-environment-id.outputs.environment_id }} --output json)
186241
echo "aws_access_key_id=$(echo $aws_credentials | jq -r '.Credentials.AccessKeyId')" >> "$GITHUB_OUTPUT"
187242
echo "aws_secret_access_key=$(echo $aws_credentials | jq -r '.Credentials.SecretAccessKey')" >> "$GITHUB_OUTPUT"
188243
echo "aws_session_token=$(echo $aws_credentials | jq -r '.Credentials.SessionToken')" >> "$GITHUB_OUTPUT"
189244
190245
- name: Run Integration Tests
191-
run: make test-features-integration TF_WORKSPACE=ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}
246+
run: make test-features-integration TF_WORKSPACE=${{ needs.set-environment-id.outputs.environment_id }}
192247
env:
193248
AWS_ACCESS_KEY_ID: ${{ steps.configure-dev-account-credentials.outputs.aws_access_key_id }}
194249
AWS_SECRET_ACCESS_KEY: ${{ steps.configure-dev-account-credentials.outputs.aws_secret_access_key }}
195250
AWS_SESSION_TOKEN: ${{ steps.configure-dev-account-credentials.outputs.aws_session_token }}
196251

197252
performance-test:
198253
name: Run Performance Tests
199-
needs: [set-uniquish-id, integration-test]
254+
needs: [set-environment-id, integration-test]
200255
runs-on: [self-hosted, ci]
201256

202257
steps:
@@ -226,7 +281,7 @@ jobs:
226281
with:
227282
aws-region: eu-west-2
228283
role-to-assume: ${{ secrets.CI_ROLE_NAME }}
229-
role-session-name: github-actions-ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}
284+
role-session-name: github-actions-ci-${{ needs.set-environment-id.outputs.environment_id }}
230285

231286
- name: Pull Client Certificates
232287
run: make truststore-pull-client ENV=dev
@@ -238,23 +293,23 @@ jobs:
238293
- name: Configure Dev Account Credentials
239294
id: configure-dev-account-credentials
240295
run: |
241-
aws_credentials=$(aws sts assume-role --role-arn arn:aws:iam::${{ steps.get_account_id.outputs.aws_account_id }}:role/terraform --role-session-name github-actions-ci-${{ needs.set-uniquish-id.outputs.uniqish_id }} --output json)
296+
aws_credentials=$(aws sts assume-role --role-arn arn:aws:iam::${{ steps.get_account_id.outputs.aws_account_id }}:role/terraform --role-session-name github-actions-ci-${{ needs.set-environment-id.outputs.environment_id }} --output json)
242297
echo "aws_access_key_id=$(echo $aws_credentials | jq -r '.Credentials.AccessKeyId')" >> "$GITHUB_OUTPUT"
243298
echo "aws_secret_access_key=$(echo $aws_credentials | jq -r '.Credentials.SecretAccessKey')" >> "$GITHUB_OUTPUT"
244299
echo "aws_session_token=$(echo $aws_credentials | jq -r '.Credentials.SessionToken')" >> "$GITHUB_OUTPUT"
245300
246301
- name: Setup Environment Test Data
247-
run: make test-performance-prepare TF_WORKSPACE=ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}
302+
run: make test-performance-prepare TF_WORKSPACE=${{ needs.set-environment-id.outputs.environment_id }}
248303
env:
249304
AWS_ACCESS_KEY_ID: ${{ steps.configure-dev-account-credentials.outputs.aws_access_key_id }}
250305
AWS_SECRET_ACCESS_KEY: ${{ steps.configure-dev-account-credentials.outputs.aws_secret_access_key }}
251306
AWS_SESSION_TOKEN: ${{ steps.configure-dev-account-credentials.outputs.aws_session_token }}
252307

253308
- name: Run Performance Test - Baseline
254-
run: make test-performance-baseline HOST=ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}.api.record-locator.dev.national.nhs.uk ENV_TYPE=dev
309+
run: make test-performance-baseline HOST=${{ needs.set-environment-id.outputs.environment_id }}.api.record-locator.dev.national.nhs.uk ENV_TYPE=dev
255310

256311
- name: Run Performance Test - Stress
257-
run: make test-performance-stress HOST=ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}.api.record-locator.dev.national.nhs.uk ENV_TYPE=dev
312+
run: make test-performance-stress HOST=${{ needs.set-environment-id.outputs.environment_id }}.api.record-locator.dev.national.nhs.uk ENV_TYPE=dev
258313

259314
- name: Process Performance Test Outputs
260315
run: make test-performance-output
@@ -266,53 +321,8 @@ jobs:
266321
path: dist/*.png
267322

268323
- name: Cleanup Environment Test Data
269-
run: make test-performance-cleanup TF_WORKSPACE=ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}
324+
run: make test-performance-cleanup TF_WORKSPACE=${{ needs.set-environment-id.outputs.environment_id }}
270325
env:
271326
AWS_ACCESS_KEY_ID: ${{ steps.configure-dev-account-credentials.outputs.aws_access_key_id }}
272327
AWS_SECRET_ACCESS_KEY: ${{ steps.configure-dev-account-credentials.outputs.aws_secret_access_key }}
273328
AWS_SESSION_TOKEN: ${{ steps.configure-dev-account-credentials.outputs.aws_session_token }}
274-
275-
destroy:
276-
name: Destroy CI Environment
277-
needs: [set-uniquish-id, deploy, integration-test, performance-test]
278-
runs-on: [self-hosted, ci]
279-
if: ${{ always() }}
280-
281-
steps:
282-
- name: Git Clone - ${{ github.event.pull_request.head.ref }}
283-
uses: actions/checkout@v4
284-
with:
285-
ref: ${{ github.event.pull_request.head.ref }}
286-
287-
- name: Setup asdf cache
288-
uses: actions/cache@v4
289-
with:
290-
path: ~/.asdf
291-
key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}
292-
restore-keys: |
293-
${{ runner.os }}-asdf-
294-
295-
- name: Configure AWS Credentials
296-
uses: aws-actions/configure-aws-credentials@v4
297-
with:
298-
aws-region: eu-west-2
299-
role-to-assume: ${{ secrets.CI_ROLE_NAME }}
300-
role-session-name: github-actions-ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}
301-
302-
- name: Get AWS Account ID
303-
id: get_account_id
304-
run: echo "aws_account_id=$(aws secretsmanager get-secret-value --secret-id nhsd-nrlf--mgmt--dev-account-id --query SecretString --output text)" >> "$GITHUB_OUTPUT"
305-
306-
- name: Terraform Init
307-
run: |
308-
terraform -chdir=terraform/infrastructure init
309-
terraform -chdir=terraform/infrastructure workspace new ci-${{ needs.set-uniquish-id.outputs.uniqish_id }} || \
310-
terraform -chdir=terraform/infrastructure workspace select ci-${{ needs.set-uniquish-id.outputs.uniqish_id }}
311-
312-
- name: Terraform Destroy
313-
run: |
314-
terraform -chdir=terraform/infrastructure destroy \
315-
--var-file=etc/dev.tfvars \
316-
--var assume_account=${{ steps.get_account_id.outputs.aws_account_id }} \
317-
--var assume_role=terraform \
318-
-auto-approve
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Create PR Environment
2+
run-name: "Destroy PR Environment - #${{ github.event.pull_request.number }} (${{ github.event.pull_request.title }})"
3+
4+
on:
5+
pull_request:
6+
types: [closed]
7+
8+
concurrency:
9+
group: environment-${{ github.event.pull_request.number }}
10+
cancel-in-progress: true
11+
12+
permissions:
13+
id-token: write
14+
contents: read
15+
actions: write
16+
issues: write
17+
pull-requests: write
18+
19+
jobs:
20+
set-environment-id:
21+
name: Set Environment ID
22+
runs-on: [self-hosted, ci]
23+
steps:
24+
- name: Set a ID based on the branch name
25+
id: set_environment_id
26+
run: |
27+
JIRA_TICKET=$(
28+
echo '${{ github.event.pull_request.head.ref }}' | \
29+
grep -Po --color=none '[A-z]{3,4}-[0-9]{3,5}' | \
30+
sed 's/-//g' | \
31+
tr '[:upper:]' '[:lower:]' || \
32+
true
33+
)
34+
BRANCH_HASH=$(echo '${{ github.event.pull_request.head.ref }}${{ github.event.pull_request.id }}' | sha256sum | head -c 6)
35+
36+
if [ -z "$JIRA_TICKET" ]; then
37+
echo "environment_id=${BRANCH_HASH}" > $GITHUB_OUTPUT
38+
else
39+
echo "environment_id=${JIRA_TICKET}-${BRANCH_HASH}" > $GITHUB_OUTPUT
40+
fi
41+
42+
outputs:
43+
environment_id: ${{ steps.set_environment_id.outputs.environment_id }}
44+
45+
destroy:
46+
name: Destroy PR Environment
47+
needs: [set-environment-id]
48+
runs-on: [self-hosted, ci]
49+
50+
steps:
51+
- name: Git Clone - ${{ github.event.pull_request.head.ref }}
52+
uses: actions/checkout@v4
53+
with:
54+
ref: ${{ github.event.pull_request.head.ref }}
55+
56+
- name: Setup asdf cache
57+
uses: actions/cache@v4
58+
with:
59+
path: ~/.asdf
60+
key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}
61+
restore-keys: |
62+
${{ runner.os }}-asdf-
63+
64+
- name: Configure AWS Credentials
65+
uses: aws-actions/configure-aws-credentials@v4
66+
with:
67+
aws-region: eu-west-2
68+
role-to-assume: ${{ secrets.CI_ROLE_NAME }}
69+
role-session-name: github-actions-ci-${{ needs.set-environment-id.outputs.environment_id }}
70+
71+
- name: Get AWS Account ID
72+
id: get_account_id
73+
run: echo "aws_account_id=$(aws secretsmanager get-secret-value --secret-id nhsd-nrlf--mgmt--dev-account-id --query SecretString --output text)" >> "$GITHUB_OUTPUT"
74+
75+
- name: Terraform Init
76+
run: |
77+
terraform -chdir=terraform/infrastructure init
78+
terraform -chdir=terraform/infrastructure workspace new ${{ needs.set-environment-id.outputs.environment_id }} || \
79+
terraform -chdir=terraform/infrastructure workspace select ${{ needs.set-environment-id.outputs.environment_id }}
80+
81+
- name: Terraform Destroy
82+
run: |
83+
terraform -chdir=terraform/infrastructure destroy \
84+
--var-file=etc/dev.tfvars \
85+
--var assume_account=${{ steps.get_account_id.outputs.aws_account_id }} \
86+
--var assume_role=terraform \
87+
-auto-approve
88+
89+
- name: Add Failure Pull Request Comment
90+
uses: actions/github-script@v7
91+
if: ${{ failure() }}
92+
with:
93+
script: |
94+
github.rest.issues.createComment({
95+
issue_number: context.issue.number,
96+
owner: context.repo.owner,
97+
repo: context.repo.repo,
98+
body: `💥 Something went wrong while destroying the pull request environment.\n[Check Output Logs](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`
99+
})

tests/features/steps/2_request.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ def create_post_document_reference_step(context: Context, ods_code: str):
8080
doc_ref = create_test_document_reference(items)
8181
context.response = client.create(doc_ref.dict(exclude_none=True))
8282

83+
if context.response.status_code == 201:
84+
doc_ref_id = context.response.headers["Location"].split("/")[-1]
85+
context.add_cleanup(lambda: context.repository.delete_by_id(doc_ref_id))
86+
8387

8488
@when("producer '{ods_code}' reads a DocumentReference with ID '{doc_ref_id}'")
8589
def producer_read_document_reference_step(

0 commit comments

Comments
 (0)