Repository: DFE-Digital/get-into-teaching-app
Pull request #4639: CI-CD for domains
Author: login: elaiyganesan
Labels: name: DevOps
name: Review
Created: 2025-03-06T09:03:28Z | Merged: 2025-03-11T08:42:12Z

## Context
adding workflows for domain deployment to build workflows

## Changes proposed in this pull request
updated build.yml adding calls to the deploy domains github actions.
output.tf is added to provide external_urls for testing

## Guidance to review
checkout branch and run the following

```
make ci domains-infra-plan 
make ci test domains-plan
make ci beta domains-plan
make ci production domains-plan
```
Review the github runs

test
https://github.com/DFE-Digital/get-into-teaching-app/actions/runs/13766260976/job/38493428548
beta
https://github.com/DFE-Digital/get-into-teaching-app/actions/runs/13766330341/job/38493658886
production
https://github.com/DFE-Digital/get-into-teaching-app/actions/runs/13766528194/job/38494422672

verify the code in the github action
verify the list of domain_environments is correct

## Link to Trello card
https://trello.com/c/qyXB3RQA/1972-implement-ci-cd-for-domains-on-all-services
Checklist

- [x]  Attach to Trello card
- [x]  Rebased main
- [x]  Cleaned commit history
- [x]  Tested by running locally


Diff:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f47b60bcfe..95ca4f6707 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -836,3 +836,63 @@ jobs:
           SLACK_TITLE: Production Release ${{github.event.title}}
           SLACK_MESSAGE: Failure deploying Production release
           SLACK_WEBHOOK: ${{ steps.keyvault-yaml-secret.outputs.SLACK_WEBHOOK }}
+  
+  deploy_domains_infra:
+    name: Deploy Domains Infrastructure
+    needs: [production]
+    runs-on: ubuntu-latest
+    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+    concurrency: production
+    environment:
+      name: production
+    permissions:
+      id-token: write
+
+    steps:
+      - uses: azure/login@v2
+        with:
+          client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+
+      - name: Deploy Domains Infrastructure
+        id: deploy_domains_infra
+        uses: DFE-Digital/github-actions/deploy-domains-infra@master
+        with:
+          azure-client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          azure-tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          azure-subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+          slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
+
+  deploy_domains_env:
+    name: Deploy Domains to ${{ matrix.domain_environment }} environment
+    runs-on: ubuntu-latest
+    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+    concurrency: deploy_${{ matrix.domain_environment }}
+    needs: [deploy_domains_infra]
+    strategy:
+      max-parallel: 1
+      matrix:
+        domain_environment: [test, beta, production]
+    environment:
+      name: production
+    permissions:
+      id-token: write
+
+    steps:
+      - uses: azure/login@v2
+        with:
+          client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+
+      - name: Deploy Domains Environment
+        id: deploy_domains_env
+        uses: DFE-Digital/github-actions/deploy-domains-env@master
+        with:
+          azure-client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          azure-tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          azure-subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+          environment: ${{ matrix.domain_environment }}
+          healthcheck: healthcheck.json
+          slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
\ No newline at end of file
diff --git a/terraform/aks/.terraform.lock.hcl b/terraform/aks/.terraform.lock.hcl
index c181eba43f..e4fd310f59 100644
--- a/terraform/aks/.terraform.lock.hcl
+++ b/terraform/aks/.terraform.lock.hcl
@@ -6,6 +6,7 @@ provider "registry.terraform.io/eppo/environment" {
   constraints = "1.3.5"
   hashes = [
     "h1:1Af95/IhzW16rbX8kSApfrAi8vwc5+7uVbCeyVaGw2E=",
+    "h1:J0rtl6GrLyBKYz6PQ5BXsyYfjHbgMEoAHEQQ3u0vPBc=",
     "h1:pceowuRAKcjLd+g4noIJdX6CBIWavlM4BvRTsGfH0uQ=",
     "zh:00e7a6bf7f0f09cc4871d7f4fee2c943ce61c05b9802365a97703d6c2e63e3dc",
     "zh:018d92e621177d053ed5c32e8220efa8c019852c4d60cc7539683bac28470d9b",
@@ -31,6 +32,7 @@ provider "registry.terraform.io/hashicorp/azurerm" {
   hashes = [
     "h1:2QbjtN4oMXzdA++Nvrj/wSmWZTPgXKOSFGGQCLEMrb4=",
     "h1:BCR3NIorFSvGG3v/+JOiiw3VM4PkChLO4m84wzD9NDo=",
+    "h1:SJM/KQDW9blKFmLMaupsZVYtcZ0fYpjLHEriMgCBGCY=",
     "zh:02b6606aff025fc2a962b3e568e000300abe959adac987183c24dac8eb057f4d",
     "zh:2a23a8ce24ff9e885925ffee0c3ea7eadba7a702541d05869275778aa47bdea7",
     "zh:57d10746384baeca4d5c56e88872727cdc150f437b8c5e14f0542127f7475e24",
@@ -52,6 +54,7 @@ provider "registry.terraform.io/hashicorp/google" {
   hashes = [
     "h1:BOwY9eXbFeMU+DC1L8RW1CfcGPIiF1rMxNAxjssqNgk=",
     "h1:bNj7UyO9+IdcTbkZJgjULH89DrJSaBCRw89zt6g8ajg=",
+    "h1:mllWOZFO8u2kD2kRTdDDAa8Jt+vb8Uxhf6C0lwLxoz8=",
     "zh:0c181f9b9f0ab81731e5c4c2d20b6d342244506687437dad94e279ef2a588f68",
     "zh:12a4c333fc0ba670e87f09eb574e4b7da90381f9929ef7c866048b6841cc8a6a",
     "zh:15c277c2052df89429051350df4bccabe4cf46068433d4d8c673820d9756fc00",
@@ -73,6 +76,7 @@ provider "registry.terraform.io/hashicorp/kubernetes" {
   hashes = [
     "h1:3j4XBR5UWQA7xXaiEnzZp0bHbcwOhWetHYKTWIrUTI0=",
     "h1:Cj3RHyw3wE3AkNlCtSNrZfjFNkShvaZR0K/K3pJlYJU=",
+    "h1:HqeU0sZBh+2loFYqPMFx7jJamNUPEykyqJ9+CkMCYE0=",
     "zh:0e715d7fb13a8ad569a5fdc937b488590633f6942e986196fdb17cd7b8f7720e",
     "zh:495fc23acfe508ed981e60af9a3758218b0967993065e10a297fdbc210874974",
     "zh:4b930a8619910ef528bc90dae739cb4236b9b76ce41367281e3bc3cf586101c7",
@@ -89,22 +93,21 @@ provider "registry.terraform.io/hashicorp/kubernetes" {
 }
 
 provider "registry.terraform.io/hashicorp/random" {
-  version = "3.6.3"
+  version = "3.7.1"
   hashes = [
-    "h1:f6jXn4MCv67kgcofx9D49qx1ZEBv8oyvwKDMPBr0A24=",
-    "h1:zG9uFP8l9u+yGZZvi5Te7PV62j50azpgwPunq2vTm1E=",
-    "zh:04ceb65210251339f07cd4611885d242cd4d0c7306e86dda9785396807c00451",
-    "zh:448f56199f3e99ff75d5c0afacae867ee795e4dfda6cb5f8e3b2a72ec3583dd8",
-    "zh:4b4c11ccfba7319e901df2dac836b1ae8f12185e37249e8d870ee10bb87a13fe",
-    "zh:4fa45c44c0de582c2edb8a2e054f55124520c16a39b2dfc0355929063b6395b1",
-    "zh:588508280501a06259e023b0695f6a18149a3816d259655c424d068982cbdd36",
-    "zh:737c4d99a87d2a4d1ac0a54a73d2cb62974ccb2edbd234f333abd079a32ebc9e",
+    "h1:/qtweZW2sk0kBNiQM02RvBXmlVdI9oYqRMCyBZ8XA98=",
+    "zh:3193b89b43bf5805493e290374cdda5132578de6535f8009547c8b5d7a351585",
+    "zh:3218320de4be943e5812ed3de995946056db86eb8d03aa3f074e0c7316599bef",
+    "zh:419861805a37fa443e7d63b69fb3279926ccf98a79d256c422d5d82f0f387d1d",
+    "zh:4df9bd9d839b8fc11a3b8098a604b9b46e2235eb65ef15f4432bde0e175f9ca6",
+    "zh:5814be3f9c9cc39d2955d6f083bae793050d75c572e70ca11ccceb5517ced6b1",
+    "zh:63c6548a06de1231c8ee5570e42ca09c4b3db336578ded39b938f2156f06dd2e",
+    "zh:697e434c6bdee0502cc3deb098263b8dcd63948e8a96d61722811628dce2eba1",
     "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
-    "zh:a357ab512e5ebc6d1fda1382503109766e21bbfdfaa9ccda43d313c122069b30",
-    "zh:c51bfb15e7d52cc1a2eaec2a903ac2aff15d162c172b1b4c17675190e8147615",
-    "zh:e0951ee6fa9df90433728b96381fb867e3db98f66f735e0c3e24f8f16903f0ad",
-    "zh:e3cdcb4e73740621dabd82ee6a37d6cfce7fee2a03d8074df65086760f5cf556",
-    "zh:eff58323099f1bd9a0bec7cb04f717e7f1b2774c7d612bf7581797e1622613a0",
+    "zh:a0b8e44927e6327852bbfdc9d408d802569367f1e22a95bcdd7181b1c3b07601",
+    "zh:b7d3af018683ef22794eea9c218bc72d7c35a2b3ede9233b69653b3c782ee436",
+    "zh:d63b911d618a6fe446c65bfc21e793a7663e934b2fef833d42d3ccd38dd8d68d",
+    "zh:fa985cd0b11e6d651f47cff3055f0a9fd085ec190b6dbe99bf5448174434cdea",
   ]
 }
 
@@ -112,6 +115,7 @@ provider "registry.terraform.io/statuscakedev/statuscake" {
   version     = "2.2.2"
   constraints = "2.2.2"
   hashes = [
+    "h1:OoqL/K/eNLahbfMwJvYZHo9kacafjtrJKhd6cLrubZ4=",
     "h1:nVaJkDBk4sv0yWFzg3p+yeJGzE8mB4KJv3Q6/UgU164=",
     "h1:wFoZJfmNvG6XTf65NLai67geSHqYV1Tilx7OITrHilE=",
     "zh:0916313344c579d6e05d70f88129a10fe48f7dabe0e61cad17874d6c496f288d",
diff --git a/terraform/domains/environment_domains/.terraform.lock.hcl b/terraform/domains/environment_domains/.terraform.lock.hcl
index 2ea2d9c7ed..59fb75c467 100644
--- a/terraform/domains/environment_domains/.terraform.lock.hcl
+++ b/terraform/domains/environment_domains/.terraform.lock.hcl
@@ -6,6 +6,7 @@ provider "registry.terraform.io/hashicorp/azurerm" {
   constraints = "3.116.0"
   hashes = [
     "h1:2QbjtN4oMXzdA++Nvrj/wSmWZTPgXKOSFGGQCLEMrb4=",
+    "h1:SJM/KQDW9blKFmLMaupsZVYtcZ0fYpjLHEriMgCBGCY=",
     "zh:02b6606aff025fc2a962b3e568e000300abe959adac987183c24dac8eb057f4d",
     "zh:2a23a8ce24ff9e885925ffee0c3ea7eadba7a702541d05869275778aa47bdea7",
     "zh:57d10746384baeca4d5c56e88872727cdc150f437b8c5e14f0542127f7475e24",
diff --git a/terraform/domains/environment_domains/output.tf b/terraform/domains/environment_domains/output.tf
new file mode 100644
index 0000000000..b602e987ff
--- /dev/null
+++ b/terraform/domains/environment_domains/output.tf
@@ -0,0 +1,10 @@
+output "external_urls" {
+  value = flatten([
+    for zone_name, zone_values in var.hosted_zone : [
+      for domain in zone_values["domains"] : (startswith(domain, "apex") ?
+        "https://${zone_name}" :
+        "https://${domain}.${zone_name}"
+      )
+    ]
+  ])
+}
\ No newline at end of file
diff --git a/terraform/domains/infrastructure/.terraform.lock.hcl b/terraform/domains/infrastructure/.terraform.lock.hcl
index 2ea2d9c7ed..59fb75c467 100644
--- a/terraform/domains/infrastructure/.terraform.lock.hcl
+++ b/terraform/domains/infrastructure/.terraform.lock.hcl
@@ -6,6 +6,7 @@ provider "registry.terraform.io/hashicorp/azurerm" {
   constraints = "3.116.0"
   hashes = [
     "h1:2QbjtN4oMXzdA++Nvrj/wSmWZTPgXKOSFGGQCLEMrb4=",
+    "h1:SJM/KQDW9blKFmLMaupsZVYtcZ0fYpjLHEriMgCBGCY=",
     "zh:02b6606aff025fc2a962b3e568e000300abe959adac987183c24dac8eb057f4d",
     "zh:2a23a8ce24ff9e885925ffee0c3ea7eadba7a702541d05869275778aa47bdea7",
     "zh:57d10746384baeca4d5c56e88872727cdc150f437b8c5e14f0542127f7475e24",


Reviews:
user: login: RMcVelia
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T14:15:35Z
user: login: elaiyganesan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T08:56:58Z
user: login: RMcVelia
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T10:07:09Z
user: login: elaiyganesan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T13:32:56Z
user: login: elaiyganesan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T13:33:09Z
user: login: RMcVelia
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T15:21:22Z
user: login: RMcVelia
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T16:36:24Z

Review comments:
diff_hunk: @@ -0,0 +1,8 @@
+output "external_urls" {
+  value = flatten([
+    for domain in var.domains : (domain == "apex" ?
path: terraform/domains/environment_domains/output.tf
user: login: RMcVelia
body: var.domains doesn't exist see 'make test domains-plan' from your branch
created_at: 2025-03-07T14:15:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,8 @@
+output "external_urls" {
+  value = flatten([
+    for domain in var.domains : (domain == "apex" ?
path: terraform/domains/environment_domains/output.tf
user: login: elaiyganesan
body: I have fixed this so the map values are taken from var.hosted_zone. Thanks
created_at: 2025-03-10T08:56:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -836,3 +836,62 @@ jobs:
           SLACK_TITLE: Production Release ${{github.event.title}}
           SLACK_MESSAGE: Failure deploying Production release
           SLACK_WEBHOOK: ${{ steps.keyvault-yaml-secret.outputs.SLACK_WEBHOOK }}
+  
+  deploy_domains_infra:
+    name: Deploy Domains Infrastructure
+    runs-on: ubuntu-latest
+    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+    concurrency: deploy_production
+    environment:
+      name: production
+    permissions:
+      id-token: write
+
+    steps:
+      - uses: azure/login@v2
+        with:
+          client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+
+      - name: Deploy Domains Infrastructure
+        id: deploy_domains_infra
+        uses: DFE-Digital/github-actions/deploy-domains-infra@master
+        with:
+          azure-client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          azure-tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          azure-subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+          slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
+
+  deploy_domains_env:
+    name: Deploy Domains to ${{ matrix.domain_environment }} environment
+    runs-on: ubuntu-latest
+    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+    concurrency: deploy_${{ matrix.domain_environment }}
+    needs: [deploy_domains_infra]
+    strategy:
+      max-parallel: 1
+      matrix:
+        domain_environment: [test, beta, production]
+    environment:
+      name: production
+    permissions:
+      id-token: write
+
+    steps:
+      - uses: azure/login@v2
+        with:
+          client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+
+      - name: Deploy Domains Environment
+        id: deploy_domains_env
+        uses: DFE-Digital/github-actions/deploy-domains-env@master
+        with:
+          azure-client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          azure-tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          azure-subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+          environment: ${{ matrix.domain_environment }}
+          healthcheck: healthcheck
path: .github/workflows/build.yml
user: login: RMcVelia
body: should be healthcheck.json
created_at: 2025-03-10T10:02:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+output "external_urls" {
+  value = flatten([
+    for zone_name, zone_values in var.hosted_zone : [
+      for domain in zone_values["domains"] : (domain == "apex" ?
path: terraform/domains/environment_domains/output.tf
user: login: RMcVelia
body: beta uses apexb, so to get the external_url right need something like
`for domain in zone_values["domains"] : (startswith(domain, "apex") ?`
otherwise we get apexb.beta-getintoteaching.education.gov.uk which doesn't exist
created_at: 2025-03-10T10:04:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -836,3 +836,62 @@ jobs:
           SLACK_TITLE: Production Release ${{github.event.title}}
           SLACK_MESSAGE: Failure deploying Production release
           SLACK_WEBHOOK: ${{ steps.keyvault-yaml-secret.outputs.SLACK_WEBHOOK }}
+  
+  deploy_domains_infra:
+    name: Deploy Domains Infrastructure
+    runs-on: ubuntu-latest
+    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+    concurrency: deploy_production
+    environment:
+      name: production
+    permissions:
+      id-token: write
+
+    steps:
+      - uses: azure/login@v2
+        with:
+          client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+
+      - name: Deploy Domains Infrastructure
+        id: deploy_domains_infra
+        uses: DFE-Digital/github-actions/deploy-domains-infra@master
+        with:
+          azure-client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          azure-tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          azure-subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+          slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
+
+  deploy_domains_env:
+    name: Deploy Domains to ${{ matrix.domain_environment }} environment
+    runs-on: ubuntu-latest
+    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+    concurrency: deploy_${{ matrix.domain_environment }}
+    needs: [deploy_domains_infra]
+    strategy:
+      max-parallel: 1
+      matrix:
+        domain_environment: [test, beta, production]
+    environment:
+      name: production
+    permissions:
+      id-token: write
+
+    steps:
+      - uses: azure/login@v2
+        with:
+          client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+
+      - name: Deploy Domains Environment
+        id: deploy_domains_env
+        uses: DFE-Digital/github-actions/deploy-domains-env@master
+        with:
+          azure-client-id:  ${{ secrets.AZURE_CLIENT_ID  }}
+          azure-tenant-id:  ${{ secrets.AZURE_TENANT_ID   }}
+          azure-subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID   }}
+          environment: ${{ matrix.domain_environment }}
+          healthcheck: healthcheck
path: .github/workflows/build.yml
user: login: elaiyganesan
body: Yeah. I have updated. Thanks
created_at: 2025-03-10T13:32:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+output "external_urls" {
+  value = flatten([
+    for zone_name, zone_values in var.hosted_zone : [
+      for domain in zone_values["domains"] : (domain == "apex" ?
path: terraform/domains/environment_domains/output.tf
user: login: elaiyganesan
body: Yeah. I have updated. Thanks
created_at: 2025-03-10T13:33:09Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-10T16:26:23Z
body: Review app deployed to https://get-into-teaching-app-review-4639.test.teacherservices.cloud
<!-- Sticky Pull Request CommentAKS -->
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-03-10T16:26:54Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=DFE-Digital_get-into-teaching-app&pullRequest=4639) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [12 New issues](https://sonarcloud.io/project/issues?id=DFE-Digital_get-into-teaching-app&pullRequest=4639&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [8 Accepted issues](https://sonarcloud.io/project/issues?id=DFE-Digital_get-into-teaching-app&pullRequest=4639&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=DFE-Digital_get-into-teaching-app&pullRequest=4639&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [95.5% Coverage on New Code](https://sonarcloud.io/component_measures?id=DFE-Digital_get-into-teaching-app&pullRequest=4639&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.3% Duplication on New Code](https://sonarcloud.io/component_measures?id=DFE-Digital_get-into-teaching-app&pullRequest=4639&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=DFE-Digital_get-into-teaching-app&pullRequest=4639)


author_association: NONE