Skip to content

Commit

Permalink
Merge pull request #1771 from alphagov/review_apps_pr_workflow
Browse files Browse the repository at this point in the history
GitHub Actions workflow for review apps
  • Loading branch information
AP-Hunt authored Feb 20, 2025
2 parents 5a3180d + 9bd21d7 commit 1102160
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 11 deletions.
92 changes: 92 additions & 0 deletions .github/workflows/review_apps_on_pr_change.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: "Review apps: on PR change"
on:
pull_request:
# being explicit about what to trigger on.
# matches the docs for the default types
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request
types: [opened, reopened, synchronize]
jobs:
update-review-app:
# this references a codebuild project configured in forms-deploy
# see: https://docs.aws.amazon.com/codebuild/latest/userguide/action-runner.html
runs-on: codebuild-review-forms-admin-gha-runner-${{github.run_id}}-${{github.run_attempt}}

permissions:
pull-requests: write

steps:
- name: Generate container image URI
run: |
echo "CONTAINER_IMAGE_URI=842676007477.dkr.ecr.eu-west-2.amazonaws.com/forms-admin:pr-${{github.event.pull_request.number}}-${{github.event.pull_request.head.sha}}-$(date +%s)" >> "$GITHUB_ENV"
- name: Checkout code
uses: actions/checkout@v4

- name: Build container
run: |
# Docker credentials are configured in CodeBuild
# CodeBuild retrieves the credentials from ParameterStore
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
docker build \
--tag "${{env.CONTAINER_IMAGE_URI}}" \
.
- name: Push container
id: build-container
run: |
aws ecr get-login-password --region eu-west-2 \
| docker login --username AWS --password-stdin 842676007477.dkr.ecr.eu-west-2.amazonaws.com
echo "Pushing container image"
echo "${{env.CONTAINER_IMAGE_URI}}"
docker push "${CONTAINER_IMAGE_URI}"
- name: Determine Terraform version
id: terraform-version
run: |
cat .review_apps/.terraform-version | xargs printf "TF_VERSION=%s" >> "$GITHUB_OUTPUT"
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{steps.terraform-version.outputs.TF_VERSION}}

- name: Deploy review app
id: deploy
run: |
cd .review_apps/
terraform init -backend-config="key=review-apps/forms-admin/pr-${{github.event.pull_request.number}}.tfstate"
terraform apply \
-var "pull_request_number=${{github.event.pull_request.number}}" \
-var "forms_admin_container_image=${{env.CONTAINER_IMAGE_URI}}" \
-no-color \
-auto-approve
echo "REVIEW_APP_URL=$(terraform output -raw review_app_url)" >> "$GITHUB_OUTPUT"
echo "ECS_CLUSTER_ID=$(terraform output -raw review_app_ecs_cluster_id)" >> "$GITHUB_OUTPUT"
echo "ECS_SERVICE_NAME=$(terraform output -raw review_app_ecs_service_name)" >> "$GITHUB_OUTPUT"
- name: Wait for AWS ECS deployments to finish
run: |
aws ecs wait services-stable \
--cluster "${{steps.deploy.outputs.ECS_CLUSTER_ID}}" \
--services "${{steps.deploy.outputs.ECS_SERVICE_NAME}}"
- name: Comment on PR
env:
GH_TOKEN: ${{ github.token }}
run: |
cat <<EOF > "${{runner.temp}}/pr-comment.md"
:tada: A review copy of this PR has been deployed! You can reach it at ${{steps.deploy.outputs.REVIEW_APP_URL}}.
It may take 5 minutes or so for the application to be fully deployed and working. If it still isn't ready
after 5 minutes, there may be something wrong with the ECS task. You will need to go to the integration AWS account
to debug, or otherwise ask an infrastructure person.
For more details please see the [review app wiki page](https://github.com/alphagov/forms-team/wiki/Review-apps)
EOF
gh pr comment "${{github.event.pull_request.html_url}}" --body-file "${{runner.temp}}/pr-comment.md"
36 changes: 36 additions & 0 deletions .github/workflows/review_apps_on_pr_close.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: "Review apps: on PR close"
on:
pull_request:
# only run when a PR is closed or merged
types: [closed]
env:
IMAGE_TAG: "842676007477.dkr.ecr.eu-west-2.amazonaws.com/forms-admin:pr-${{github.event.pull_request.number}}-${{github.event.pull_request.head.ref}}"
jobs:
delete-review-app:
# this references a codebuild project configured in forms-deploy
# see: https://docs.aws.amazon.com/codebuild/latest/userguide/action-runner.html
runs-on: codebuild-review-forms-admin-gha-runner-${{github.run_id}}-${{github.run_attempt}}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Determine Terraform version
id: terraform-version
run: |
cat .review_apps/.terraform-version | xargs printf "TF_VERSION=%s" >> "$GITHUB_OUTPUT"
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{steps.terraform-version.outputs.TF_VERSION}}

- name: Delete review app
run: |
cd .review_apps/
terraform init -backend-config="key=review-apps/forms-admin/pr-${{github.event.pull_request.number}}.tfstate"
terraform destroy \
-var "pull_request_number=${{github.event.pull_request.number}}" \
-var "forms_admin_container_image=${{env.IMAGE_TAG}}" \
-no-color \
-auto-approve
45 changes: 45 additions & 0 deletions .review_apps/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 42 additions & 11 deletions .review_apps/ecs_task_definition.tf
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
locals {
logs_stream_prefix = "${data.terraform_remote_state.review.outputs.review_apps_log_group_name}/pr-${var.pull_request_number}"

service_timestamp = provider::time::rfc3339_parse(plantimestamp())
review_app_hostname = "pr-${var.pull_request_number}.review.forms.service.gov.uk"

forms_admin_startup_commands = [
"bundle config unset --local without",
"echo $PATH",
"bundle install",
"rails db:prepare",
"rails s -b 0.0.0.0"
"echo $PATH",
"bin/rails db:prepare",
"bin/rails s -b 0.0.0.0"
]

forms_admin_shell_script = join(" && ", local.forms_admin_startup_commands)
Expand All @@ -22,15 +23,15 @@ locals {
{ name = "SETTINGS__ACT_AS_USER_ENABLED", value = "true" },
{ name = "SETTINGS__AUTH_PROVIDER", value = "developer" },
{ name = "SETTINGS__FORMS_API__AUTH_KEY", value = "unsecured_api_key_for_review_apps_only" },
{ name = "SETTINGS__FORMS_API__BASE_URL", value = "pr-${var.pull_request_number}.review.forms.service.gov.uk" },
{ name = "SETTINGS__FORMS_API__BASE_URL", value = "http://localhost:9292" },
{ name = "SETTINGS__FORMS_ENV", value = "review" },
{ name = "SETTINGS__FORMS_RUNNER__URL", value = "https://forms.service.gov.uk/" },
]

forms_api_env_vars = [
{ name = "DATABASE_URL", value = "postgres://postgres:[email protected]:5432" },
{ name = "EMAIL", value = "[email protected]" },
{ name = "RAILS_DEVELOPMENT_HOSTS", value = "pr-${var.pull_request_number}.review.forms.service.gov.uk" },
{ name = "RAILS_DEVELOPMENT_HOSTS", value = "localhost:9292" },
{ name = "RAILS_ENV", value = "production" },
{ name = "SECRET_KEY_BASE", value = "unsecured_secret_key_material" },
{ name = "SETTINGS__FORMS_API__AUTH_KEY", value = "unsecured_api_key_for_review_apps_only" },
Expand All @@ -55,27 +56,32 @@ resource "aws_ecs_task_definition" "task" {
execution_role_arn = data.terraform_remote_state.review.outputs.ecs_task_execution_role_arn

container_definitions = jsonencode([

# forms-admin
{
name = "forms-admin"
image = var.forms_admin_container_image
command = ["sh", "-c", local.forms_admin_shell_script]
command = []
essential = true
environment = local.forms_admin_env_vars

dockerLabels = {
"traefik.http.routers.forms-admin-pr-${var.pull_request_number}.rule" : "Host(`pr-${var.pull_request_number}.review.forms.service.gov.uk`)",
"traefik.http.middlewares.forms-admin-pr-${var.pull_request_number}.basicauth.users" : data.terraform_remote_state.review.outputs.traefik_basic_auth_credentials

"traefik.http.routers.forms-admin-pr-${var.pull_request_number}.rule" : "Host(`${local.review_app_hostname}`)",
"traefik.http.routers.forms-admin-pr-${var.pull_request_number}.service" : "forms-admin-pr-${var.pull_request_number}",
"traefik.http.routers.forms-admin-pr-${var.pull_request_number}.middlewares" : "forms-admin-pr-${var.pull_request_number}@ecs"

"traefik.http.services.forms-admin-pr-${var.pull_request_number}.loadbalancer.server.port" : "3000",
"traefik.http.services.forms-admin-pr-${var.pull_request_number}.loadbalancer.healthcheck.path" : "/up",
"traefik.enable" : "true"
"traefik.enable" : "true",
},

portMappings = [
{
containerPort = 3000
protocol = "tcp"
appProtocl = "http"
appProtocol = "http"
}
]

Expand Down Expand Up @@ -140,7 +146,7 @@ resource "aws_ecs_task_definition" "task" {
# postgres
{
name = "postgres"
image = "postgres:13.12"
image = "public.ecr.aws/docker/library/postgres:13.12"
command = []
essential = true

Expand All @@ -164,6 +170,31 @@ resource "aws_ecs_task_definition" "task" {
}
},

# forms-admin-seeding
{
name = "forms-admin-seeding"
image = var.forms_admin_container_image
command = ["rake", "db:setup"]
essential = false
environment = local.forms_admin_env_vars

logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = data.terraform_remote_state.review.outputs.review_apps_log_group_name
awslogs-region = "eu-west-2"
awslogs-stream-prefix = "${local.logs_stream_prefix}/forms-admin-seeding"
}
}

dependsOn = [
{
containerName = "postgres"
condition = "HEALTHY"
}
]
},

# forms-api-seeding
{
name = "forms-api-seeding"
Expand Down
14 changes: 14 additions & 0 deletions .review_apps/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output "review_app_url" {
description = "The full URL of the review app"
value = "https://${local.review_app_hostname}/"
}

output "review_app_ecs_cluster_id" {
description = "The id of the AWS ECS cluster into which the review app is deployed "
value = data.terraform_remote_state.review.outputs.ecs_cluster_id
}

output "review_app_ecs_service_name" {
description = "The name of the AWS ECS service for this review app"
value = aws_ecs_service.app.name
}

0 comments on commit 1102160

Please sign in to comment.