Individual application page #15088
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build and deploy | |
on: | |
push: | |
branches: | |
- main # Push to branch other than main deploys directly to environment with the same name. ie 'dev' branch deploys to 'dev' environment | |
paths-ignore: | |
- 'bigquery/**' | |
- 'documentation/**' | |
- 'terraform/common/**' | |
- 'spec/fixtures/files/*.md' | |
- 'app/mailers/previewing_emails.md' | |
- 'README.md' | |
- 'app/assets/stylesheets/README.md' | |
- 'app/components/README.md' | |
- '.github/pull_request_template.md' | |
pull_request: | |
types: | |
- labeled | |
- synchronize | |
- reopened | |
concurrency: workflow-Build-and-deploy-${{ github.event.pull_request.number }} | |
env: | |
DOCKER_REPOSITORY: ghcr.io/dfe-digital/teaching-vacancies | |
jobs: | |
build: | |
if: contains(github.event.pull_request.labels.*.name, 'deploy') || github.event_name != 'pull_request' | |
name: Build docker image | |
outputs: | |
matrix_environments: ${{ env.MATRIX_ENVIRONMENTS }} | |
docker_image_tag: ${{ env.DOCKER_IMAGE_TAG }} | |
commit_sha: ${{ env.COMMIT_SHA }} | |
LINK_TO_RUN: ${{ env.LINK_TO_RUN }} | |
runs-on: ubuntu-20.04 | |
steps: | |
- uses: actions/checkout@v4 | |
name: Checkout Code | |
- 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: eu-west-2 | |
role-to-assume: Deployments | |
role-duration-seconds: 3600 | |
role-skip-session-tagging: true | |
- name: Get secrets from AWS ParameterStore | |
uses: dkershner6/aws-ssm-getparameters-action@v2 | |
with: | |
parameterPairs: "/teaching-vacancies/github_action/infra/slack_webhook = SLACK_WEBHOOK, | |
/teaching-vacancies/github_action/infra/snyk = SNYK_TOKEN" | |
- name: Set environment variables (Push) | |
if: github.event_name == 'push' | |
run: | | |
GIT_REF=${{ github.ref }} | |
echo "GIT_BRANCH=${GIT_REF##*/}" >> $GITHUB_ENV | |
echo "COMMIT_SHA=${GITHUB_SHA}" >> $GITHUB_ENV | |
- name: Set environment variables (Pull request) | |
if: github.event_name == 'pull_request' | |
run: | | |
# This is the actual PR branch | |
GIT_REF=${{ github.head_ref }} | |
echo "GIT_BRANCH=${GIT_REF##*/}" >> $GITHUB_ENV | |
# This is the latest commit on the actual PR branch | |
echo "COMMIT_SHA=${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV | |
- name: Set common environment variables | |
run: | | |
echo "DOCKER_IMAGE_TAG=${GIT_BRANCH}-${COMMIT_SHA}" >> $GITHUB_ENV | |
echo "LINK_TO_RUN=https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" >> $GITHUB_ENV | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Login to GitHub Container Registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Build and push docker image from builder target | |
uses: docker/build-push-action@v6 | |
with: | |
build-args: | | |
BUILDKIT_INLINE_CACHE=1 | |
RAILS_MASTER_KEY=${{ secrets.RAILS_MASTER_KEY }} | |
# Cache from builder target tagged with branch name, may be empty first time branch is pushed | |
# Cache from builder target tagged with main branch name, always present, maybe less recent | |
cache-from: | | |
${{ env.DOCKER_REPOSITORY }}:builder-${{ env.GIT_BRANCH }} | |
${{ env.DOCKER_REPOSITORY }}:builder-main | |
push: true | |
# Tag with branch name for reuse | |
tags: ${{ env.DOCKER_REPOSITORY }}:builder-${{ env.GIT_BRANCH }} | |
target: builder | |
- name: Build and push docker image from production target | |
uses: docker/build-push-action@v6 | |
with: | |
build-args: | | |
BUILDKIT_INLINE_CACHE=1 | |
COMMIT_SHA=${{ env.COMMIT_SHA }} | |
RAILS_MASTER_KEY=${{ secrets.RAILS_MASTER_KEY }} | |
# Cache from builder target built above, always present | |
# Cache from production target tagged with branch name, may be empty first time branch is pushed | |
# Cache from production target tagged with main branch name, always present, maybe less recent | |
cache-from: | | |
${{ env.DOCKER_REPOSITORY }}:builder-${{ env.GIT_BRANCH }} | |
${{ env.DOCKER_REPOSITORY }}:${{ env.GIT_BRANCH }} | |
${{ env.DOCKER_REPOSITORY }}:main | |
push: false | |
load: true | |
# Tag with branch name for reuse | |
# Tag with branch name and commit sha for unique identification | |
tags: | | |
${{ env.DOCKER_REPOSITORY }}:${{ env.GIT_BRANCH }} | |
${{ env.DOCKER_REPOSITORY }}:${{ env.DOCKER_IMAGE_TAG }} | |
target: production | |
- name: Set matrix environments (Push to main) | |
if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
run: echo "MATRIX_ENVIRONMENTS={\"environment\":[\"staging\",\"production\",\"qa\"]}" >> $GITHUB_ENV | |
- name: Set matrix environments (Push to non main branch) | |
if: github.event_name == 'push' && github.ref != 'refs/heads/main' | |
run: echo "MATRIX_ENVIRONMENTS={\"environment\":[\"${GIT_BRANCH}\"]}" >> $GITHUB_ENV | |
- name: Set matrix environments (Pull request) | |
if: github.event_name == 'pull_request' | |
run: echo "MATRIX_ENVIRONMENTS={\"environment\":[\"review\"]}" >> $GITHUB_ENV | |
- name: Scan ${{ env.DOCKER_REPOSITORY }}:${{ env.DOCKER_IMAGE_TAG }} image | |
run: | | |
docker run -t -e "SNYK_TOKEN=${{ env.SNYK_TOKEN }}" \ | |
-v "/var/run/docker.sock:/var/run/docker.sock" \ | |
-v "$GITHUB_WORKSPACE:/project" \ | |
snyk/snyk-cli:docker test --docker ${{ env.DOCKER_REPOSITORY }}:${{ env.DOCKER_IMAGE_TAG }} --file=Dockerfile --fail-on=all | |
- name: Push ${{ env.DOCKER_REPOSITORY }} images | |
if: ${{ success() }} | |
run: docker image push --all-tags ${{ env.DOCKER_REPOSITORY }} | |
- name: Notify twd_tv_dev channel on build workflow failure | |
if: failure() | |
uses: rtCamp/[email protected] | |
env: | |
SLACK_CHANNEL: twd_tv_dev | |
SLACK_USERNAME: CI Deployment | |
SLACK_TITLE: Build failure | |
SLACK_MESSAGE: | | |
Build failure on branch ${{env.GIT_BRANCH}} <!channel> | |
See: <${{ env.LINK_TO_RUN }}|Workflow run> | |
SLACK_WEBHOOK: ${{env.SLACK_WEBHOOK}} | |
SLACK_COLOR: failure | |
deploy: | |
name: Deploy app | |
environment: ${{ matrix.environment }} | |
strategy: | |
max-parallel: 1 | |
# Creates a variable 'environment' from the build job output 'matrix_environments' | |
# Its value is the list of environments. The matrix iterates once per environment and the value is accessed via ${{ matrix.environment }} | |
matrix: ${{fromJSON(needs.build.outputs.matrix_environments)}} | |
needs: [build] | |
runs-on: ubuntu-20.04 | |
steps: | |
- uses: actions/checkout@v4 | |
name: Checkout Code | |
- 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: eu-west-2 | |
role-to-assume: Deployments | |
role-duration-seconds: 3600 | |
role-skip-session-tagging: true | |
- name: Get secrets from AWS ParameterStore | |
uses: dkershner6/aws-ssm-getparameters-action@v2 | |
with: | |
parameterPairs: "/teaching-vacancies/github_action/infra/slack_webhook = SLACK_WEBHOOK" | |
- name: Set environment variables from build output | |
run: | | |
echo "COMMIT_SHA=${{ needs.build.outputs.commit_sha }}" >> $GITHUB_ENV | |
echo "DOCKER_IMAGE_TAG=${{ needs.build.outputs.docker_image_tag }}" >> $GITHUB_ENV | |
echo "LINK_TO_RUN=${{ needs.build.outputs.LINK_TO_RUN}}" >> $GITHUB_ENV | |
- name: Set environment variable (Push) | |
if: github.event_name == 'push' | |
run: | | |
ENVIRONMENT=${{ matrix.environment }} | |
echo "ENVIRONMENT=${ENVIRONMENT}" >> $GITHUB_ENV | |
- name: Set environment variable (Pull request) | |
if: github.event_name == 'pull_request' | |
run: | | |
ENVIRONMENT=review-pr-${{ github.event.number }} | |
echo "ENVIRONMENT=${ENVIRONMENT}" >> $GITHUB_ENV | |
- name: Deploy App to ${{ env.ENVIRONMENT }} environment | |
id: deploy_app_to_env | |
uses: ./.github/actions/deploy/ | |
with: | |
environment: ${{ env.ENVIRONMENT }} | |
tag: ${{ env.DOCKER_IMAGE_TAG }} | |
pr_id: ${{ github.event.number }} | |
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
azure-credentials: ${{ secrets.AZURE_CREDENTIALS }} | |
- name: Notify twd_tv_dev channel on ${{ env.ENVIRONMENT }} deployment failure | |
if: steps.deploy_app_to_env.conclusion != 'success' | |
uses: rtCamp/[email protected] | |
env: | |
SLACK_CHANNEL: twd_tv_dev | |
SLACK_USERNAME: CI Deployment | |
SLACK_TITLE: Deployment failure | |
SLACK_MESSAGE: 'Deployment of Docker image ${{ env.DOCKER_IMAGE_TAG }} to ${{ env.ENVIRONMENT }} - unsuccessful <!channel>' | |
SLACK_WEBHOOK: ${{env.SLACK_WEBHOOK}} | |
- name: Exit whole workflow if ${{ env.ENVIRONMENT }} deployment was not successful | |
if: steps.deploy_app_to_env.conclusion != 'success' | |
run: exit 1 | |
- name: Trigger Smoke Test action | |
id: smoke-test | |
uses: ./.github/actions/smoke-test/ | |
with: | |
aks_environment: ${{ env.ENVIRONMENT }} | |
event_name: ${{ github.event_name }} | |
http_basic_user: ${{ secrets.HTTP_BASIC_USER }} | |
http_basic_password: ${{ secrets.HTTP_BASIC_PASSWORD }} | |
- name: Exit whole workflow if ${{ env.ENVIRONMENT }} smoke test was not successful | |
if: steps.smoke-test.conclusion != 'success' | |
run: exit 1 | |
- name: Post sticky pull request comment | |
if: github.event_name == 'pull_request' | |
uses: marocchino/sticky-pull-request-comment@v2 | |
with: | |
message: | | |
Review app deployed to <https://teaching-vacancies-${{ env.ENVIRONMENT }}.test.teacherservices.cloud> on AKS | |
- name: Send job status message to twd_tv_dev channel | |
if: failure() | |
uses: rtCamp/[email protected] | |
env: | |
SLACK_CHANNEL: twd_tv_dev | |
SLACK_USERNAME: CI Deployment | |
SLACK_TITLE: Deployment ${{ job.status }} | |
SLACK_MESSAGE: | | |
Deployment of Docker image ${{ env.DOCKER_IMAGE_TAG }} to ${{matrix.environment}} - ${{ job.status }} | |
See: <${{ env.LINK_TO_RUN }}|Workflow run> | |
SLACK_WEBHOOK: ${{env.SLACK_WEBHOOK}} | |
SLACK_COLOR: failure | |
post_deployment: | |
if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
name: Post deployment steps | |
needs: [build, deploy] | |
runs-on: ubuntu-20.04 | |
steps: | |
- uses: actions/checkout@v4 | |
name: Checkout Code | |
- name: Set environment variables from build output | |
run: | | |
echo "DOCKER_IMAGE_TAG=${{ needs.build.outputs.docker_image_tag }}" >> $GITHUB_ENV | |
echo "LINK_TO_RUN=${{ needs.build.outputs.LINK_TO_RUN}}" >> $GITHUB_ENV | |
- 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: eu-west-2 | |
role-to-assume: Deployments | |
role-duration-seconds: 3600 | |
role-skip-session-tagging: true | |
- name: Get secrets from AWS ParameterStore | |
uses: dkershner6/aws-ssm-getparameters-action@v2 | |
with: | |
parameterPairs: "/teaching-vacancies/github_action/infra/slack_webhook = SLACK_WEBHOOK" | |
- name: Download and extract Gov.UK frontend archive | |
run: bin/regenerate-offline | |
- name: Sync offline S3 bucket | |
run: bin/sync-offline | |
- name: Send job status message to twd_tv_dev channel | |
if: always() | |
uses: rtCamp/[email protected] | |
env: | |
SLACK_CHANNEL: twd_tv_dev | |
SLACK_USERNAME: CI Deployment | |
SLACK_TITLE: Deployment ${{ job.status }} | |
SLACK_MESSAGE: | | |
Deployment of Docker tag ${{ env.DOCKER_IMAGE_TAG }} - ${{ job.status }} | |
See: <${{ env.LINK_TO_RUN }}|Workflow run> | |
SLACK_WEBHOOK: ${{env.SLACK_WEBHOOK}} | |
SLACK_COLOR: ${{ job.status }} |