From 456372dc24238f1ea7f3dfcddfc7e455b3fffa95 Mon Sep 17 00:00:00 2001 From: Vanita Barrett Date: Mon, 11 Jan 2021 10:40:15 +0000 Subject: [PATCH 1/7] Add Github Action workflow for build and deploy --- .github/workflows/ci.yaml | 90 ++++++++++++++++++++++++++++++++++++++ manifest.yml | 3 +- views/layouts/_generic.njk | 2 +- 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000000..4898d08b76 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,90 @@ +name: CI Workflow + +on: [push, pull_request] + +jobs: + build: + name: Build & Test + runs-on: ubuntu-latest + env: + ENVIRONMENT: production + + steps: + - uses: actions/checkout@v2 + + - name: Read node version from .nvmrc + id: nvm + run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" + + - name: Setup node + uses: actions/setup-node@v1 + with: + node-version: "${{ steps.nvm.outputs.NVMRC }}" + + - name: Install dependencies + run: npm install --no-optional + + - name: Build + run: npm run build + + - name: Lint and test + run: npm test -- --runInBand + + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: build + path: deploy/** + retention-days: 1 + + deploy: + name: Deploy + runs-on: ubuntu-latest + needs: build + if: ${{ github.ref == 'refs/heads/master' }} + env: + CF_API: "https://api.cloud.service.gov.uk" + CF_ORG: "govuk-design-system" + CF_SPACE: "design-system" + + steps: + - uses: actions/checkout@v2 + + - name: Download build artifact + uses: actions/download-artifact@v2 + with: + name: build + + - name: Install the CF CLI + run: | + wget https://s3-us-west-1.amazonaws.com/v7-cf-cli-releases/releases/v7.2.0/cf7-cli-installer_7.2.0_x86-64.deb + sudo dpkg -i cf7-cli-installer_7.2.0_x86-64.deb + + - name: Authenticate + env: + # CF_USERNAME and CF_PASSWORD are used by the `cf auth` command to login + # We use an environment variable instead of passing the details as options using -u / -p to reduce the risk of them being recorded in logs + # https://cli.cloudfoundry.org/en-US/v6/auth.html + CF_USERNAME: "design-system-deploy+design-system@digital.cabinet-office.gov.uk" + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + run: | + echo "Logging into $CF_ORG/$CF_SPACE..." + cf api "${CF_API}" + cf auth + cf target -o "${CF_ORG}" -s "${CF_SPACE}" + + # Parse app name from manifest to ensure it matches up + - name: Fetch app name from manifest + run: echo "APP_NAME=$(ruby -e "require 'yaml'; config = YAML.load_file('manifest.yml'); puts config['applications'][0]['name']")" >> $GITHUB_ENV + + - name: Cancel any existing running deploys to avoid conflict + run: | + echo "Cancelling any previous deployments in progress" + cf cancel-deployment $APP_NAME || true + + - name: Deploy to PaaS + # Deploy app and set up app healthcheck https://docs.cloudfoundry.org/devguide/deploy-apps/healthchecks.html + run: | + echo "Deploying $APP_NAME to $CF_ORG/$CF_SPACE..." + cf push $APP_NAME --strategy rolling + cf logout diff --git a/manifest.yml b/manifest.yml index 2075605014..ffd63ea38b 100644 --- a/manifest.yml +++ b/manifest.yml @@ -11,8 +11,9 @@ applications: # NGINX requires 20 MB of RAM to serve static assets. Reduce RAM allocation # from the default 1 GB allocated to containers by default to 64M. memory: 64M - path: ./deploy buildpack: nginx_buildpack # Run two instances to ensure availability # https://docs.cloud.service.gov.uk/managing_apps.html#scaling instances: 2 + health-check-http-endpoint: /__canary__/ + health-check-type: http diff --git a/views/layouts/_generic.njk b/views/layouts/_generic.njk index 41586df41b..935f13c200 100644 --- a/views/layouts/_generic.njk +++ b/views/layouts/_generic.njk @@ -6,7 +6,7 @@ {% block pageTitle %}{{ title }} – GOV.UK Design System{% endblock %} {% block head %} - {% if not TRAVIS_BRANCH or TRAVIS_BRANCH != 'master' %} + {% if not ENVIRONMENT or ENVIRONMENT != 'production' %} {% endif %} From 260b82a662778dcb2601d82457102662f879a3dd Mon Sep 17 00:00:00 2001 From: Vanita Barrett Date: Mon, 11 Jan 2021 10:40:27 +0000 Subject: [PATCH 2/7] Remove Travis config --- .travis.yml | 72 ----------------------------------------------- bin/deploy-travis | 14 --------- bin/smoke-test | 10 ------- 3 files changed, 96 deletions(-) delete mode 100644 .travis.yml delete mode 100755 bin/deploy-travis delete mode 100755 bin/smoke-test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5d4e8e465c..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,72 +0,0 @@ -language: node_js - -# Override the default Travis behaviour so that rather than trying to run tests -# we instead lint the codebase and try to build the design system -# -# The lint and build tasks are defined in package.json -script: - # TravisCI is slower than our local machines, so results in intermittent timeouts - # using the `--runInBand` flag we can force it to without requiring as much - # resources (https://facebook.github.io/jest/docs/en/troubleshooting.html#tests-are-extremely-slow-on-docker-and-or-continuous-integration-ci-server) - - npm run build - - npm test -- --runInBand - -sudo: false - -env: - global: - # CloudFoundry credentials for deployment - - CF_API="https://api.cloud.service.gov.uk" - - CF_ORG="govuk-design-system" - - CF_SPACE="design-system" - - CF_USERNAME="design-system-deploy+design-system@digital.cabinet-office.gov.uk" - # CF_PASSWORD - - secure: "N1ybDZ35FJ63/oGDfO8pofzTdFicyRHqx/H6Y6vsm+0WedU9bc4mTQ2qBQydYIsjQH+V17EIW+BjomL2ozivtcrf5ZBMvVdXJFk/7U2ii2LifimAXa1j2cQNZnOoviAjJIUPn90QkkjCyZlEe8vp97RYHHhDc17NGacttAvZmzVlPJB9KlwM6PGf7L9HfID2B2vEx5q/DXZcpl6uNJUPXI0/Clnjxl5K0RdvGbyNHvN7N3/cFg97NFe0wbBT64kcxo8HeWLsWeYjMEx3TlwhOJ0z5zisjoCFTI34aUxnV8HRt1BHwU8kghistaLKXc5hpQFnCD6ZVIK23Vmzgg4WheWUvkG14D8E6RggHaKizFgNemz7N0wE9ZwUSrT6lRMUfINUQfDPhFXUPKMTTttyNTRCXmFy7gklu6wh/kG/kFNJhFEZ7SIK0+g33RMV95taolNwsZp4UuKqJwo6TageMeFcpTG0yJ3CgJI6AVxMHNvgunAT7rNdCoc7h8+gBMBMShOw9vTkcPTpdu8Z78b4LMn7GmKaW/PFDfU3EcOsQ6kdmXoayDErXePwLXr/ZYaC9vG+1cPqaTcQ7s5lFismkfwK8XPJfZBCWNamXwLftEuDqTegZz84YwJnbK26JRSjWo50SlEHmbKnM+CWGnreV2YBQGdhupJvtoHFOlYrGqg=" - -install: - - npm install --no-optional - -# Set up dependencies for deployment: -# -# - The CloudFoundry command line tools -# - The blue-green-deploy plugin for zero downtime push -before_deploy: - # Add the home directory (where we install CloudFoundry) to our $PATH - - export PATH=$HOME:$PATH - # Install CloudFoundry - - travis_retry curl -L -o $HOME/cf.tgz "https://cli.run.pivotal.io/stable?release=linux64-binary&source=github" - - tar xzvf $HOME/cf.tgz -C $HOME - # Install Blue/Green Deploy plugin for zero-downtime-push - - travis_retry cf install-plugin blue-green-deploy -f -r CF-Community - -# Deploy the Design System to production when the master branch is changed (1) -# -# Travis is not involved in deploying PR or branch previews – these are handled -# by Netlify. -# -# We use a script rather than using Travis' built in CloudFoundry provider -# because it does not support zero downtime deploys -# (https://github.com/travis-ci/dpl/pull/610) -deploy: - provider: script - script: "./bin/deploy-travis" - # We build the site as part of the build, so we want to keep it so it can be - # deployed! - skip_cleanup: true - on: - branch: master # 1 - -# Notify the developers on the team when: -# - a build was just broken or still is broken (1) -# - a previously broken build is fixed (2) -# -# Unfortunately there is currently no way to filter branches, so we get these -# notifications for any branch (but not for the pull requests themselves) -notifications: - email: - recipients: - - design-system-developers@digital.cabinet-office.gov.uk - # This is the default behaviour for email notifications, this just makes - # it explicit - on_success: change # 1 - on_failure: always # 2 diff --git a/bin/deploy-travis b/bin/deploy-travis deleted file mode 100755 index 41f9fe95e1..0000000000 --- a/bin/deploy-travis +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -e - -# Parse app name from manifest to ensure it matches up -APP_NAME=$(ruby -e "require 'yaml'; config = YAML.load_file('manifest.yml'); puts config['applications'][0]['name']") - -echo "Deploying ${APP_NAME} to ${CF_ORG}/${CF_SPACE}..." - -# $CF env variables are set by Travis and configured in ../.travis.yml -cf login -a $CF_API -u $CF_USERNAME -p $CF_PASSWORD -o $CF_ORG -s $CF_SPACE - -# Zero downtime push comes from "Blue/Green Deploy plugin" which is installed in before_deploy -# step in Travis -cf blue-green-deploy $APP_NAME -f manifest.yml --smoke-test ./bin/smoke-test diff --git a/bin/smoke-test b/bin/smoke-test deleted file mode 100755 index 93973f2583..0000000000 --- a/bin/smoke-test +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -# The first and only argument passed to the smoke test script ($1) is the fully -# qualified domain name of the newly pushed app -app_fqdn="$1" - -echo "Running smoke tests against $app_fqdn" - -# Check that the /_status/ page exists and contains the string 'Tweet tweet' -grep -q "Tweet tweet" <<< "$(curl -sL "https://$app_fqdn/__canary__/")" From 2a45e76d10d71c71b94508c7baed34271c2e1f93 Mon Sep 17 00:00:00 2001 From: Vanita Barrett Date: Mon, 11 Jan 2021 10:44:29 +0000 Subject: [PATCH 3/7] Clarify what deployment script is responsible for --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4898d08b76..f8f99319b8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,6 +37,8 @@ jobs: path: deploy/** retention-days: 1 + # Deploy the Design System to production when the master branch is changed + # Github Actions is not involved in deploying PR or branch previews – these are handled by Netlify deploy: name: Deploy runs-on: ubuntu-latest From 28ec51d4405f1d58a894f39b6322d11f61176c57 Mon Sep 17 00:00:00 2001 From: Vanita Barrett Date: Wed, 13 Jan 2021 12:04:36 +0000 Subject: [PATCH 4/7] Remove text/html in nginx charset config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When testing the new github actions for deployment, I noticed the deployment logs included the following error: duplicate MIME type "text/html" The nginx docs say that charset_types "Enables module processing in responses with the specified MIME types in addition to “text/html”", implying that text/html isn't required. --- deploy/nginx.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/nginx.conf b/deploy/nginx.conf index 3256b1d9eb..f9c3dc147d 100644 --- a/deploy/nginx.conf +++ b/deploy/nginx.conf @@ -26,7 +26,7 @@ http { default_type application/octet-stream; include nginx/mime.types; - charset_types text/html text/xml text/plain application/javascript application/rss+xml text/css; + charset_types text/xml text/plain application/javascript application/rss+xml text/css; # Enabling sendfile eliminates copying file data into buffer and sends it # directly @@ -56,7 +56,7 @@ http { # The index directive (1) used in the nginx config within the buildpack means # that we send a 301 redirect when visiting a directory without a trailing # slash (e.g. /design-system will redirect to /design-system/). - # + # # However by default nginx will use absolute URLs – including the hostname – # when redirecting, which means that users going to # design-system.service.gov.uk/components will end up being redirected to our @@ -83,7 +83,7 @@ http { # # Because images and videos are not fingerprinted we only cache them for 30 # minutes. - # + # # The epoch parameter corresponds to the absolute time # 'Thu, 01 Jan 1970 00:00:01 GMT'. From 04b6460077563503afb7488ebe8724f80be42737 Mon Sep 17 00:00:00 2001 From: Vanita Barrett Date: Wed, 13 Jan 2021 14:16:39 +0000 Subject: [PATCH 5/7] Adjust Nginx auth config for __canary__ The nginx config previously set auth_basic to 'off' for /__canary__/ with the trailing slash. This meant /__canary__ required basic auth, but /__canary__/ didn't. This is easy to miss/mix up (e.g: when changing or setting up new healthchecks). Instead, we can change the nginx config to set auth_basic to 'off' for __canary__ (minus the trailing slash) and this should apply to both __canary__ and __canary__/ http://nginx.org/en/docs/http/ngx_http_charset_module.html#charset_types --- deploy/nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/nginx.conf b/deploy/nginx.conf index f9c3dc147d..a5f972caa3 100644 --- a/deploy/nginx.conf +++ b/deploy/nginx.conf @@ -161,7 +161,7 @@ http { # Allow smoke tests without authentication - location /__canary__/ { + location /__canary__ { auth_basic off; } } From 18f5f258ccfbd5fb390b26f78a0b376d88a9f982 Mon Sep 17 00:00:00 2001 From: Vanita Barrett Date: Mon, 11 Jan 2021 10:40:34 +0000 Subject: [PATCH 6/7] Update docs --- README.md | 4 ++-- docs/deployment/production.md | 25 +++++++++++-------------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5f2b7412c8..1b206595ad 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ This is defined in the [package.json](package.json) file. ## Continuous integration -When changes are pushed to GitHub [Travis][travis] will: +When changes are pushed to GitHub, [Github Actions][github-actions] will: - run the tests - lint the Sass stylesheets in `source/stylesheets` @@ -73,7 +73,7 @@ When changes are pushed to GitHub [Travis][travis] will: If any of these fail, this will be reported in the GitHub status checks interface. -[travis]: https://travis-ci.org/alphagov/govuk-design-system +[github-actions]: https://github.com/alphagov/govuk-design-system/actions ## Deployment diff --git a/docs/deployment/production.md b/docs/deployment/production.md index 3982ab937e..f63d656271 100644 --- a/docs/deployment/production.md +++ b/docs/deployment/production.md @@ -5,34 +5,33 @@ The Design System is a static site which is generated by [Metalsmith](http://www.metalsmith.io/). -When the master branch changes, [Travis][travis] will build the static site by +When the master branch changes, [Github Actions][github-actions] will build the static site by running `npm run build`. As long as that succeeds, the contents of the deploy directory will then by uploaded to our application on [GOV.UK Platform as a Service][paas] (PaaS). GOV.UK PaaS uses the open source Cloud Foundry project and exposes parts of their API. We use nginx as a simple web server. -## Travis +## Github Actions ### Configuration -Travis is configured using the [.travis.yml](../../.travis.yml) config file. Travis -will attempt to build the Design System, run the linter and run tests for every -branch, but will only run the deploy step when on the master branch. +The Github Actions CI workflow is configured in [.github/workflows/ci.yaml](../../.github/workflows/ci.yaml). +It will attempt to build the Design System, run the linter and run tests for every branch, +but will only run the deploy step when on the master branch. -Configuration is done using [environment variables][travis-env]. Configuration -which needs to remain secure is encrypted using `travis encrypt`. +Most of the environment variables needed are set within each Github Action script. Any secrets can be viewed and changed within the Github UI (requires admin access). ### Deployment -Travis is deployed using [deploy-travis](bin/deploy-travis). +The Github Actions deployment script is detailed in [.github/workflows/ci.yaml](../../.github/workflows/ci.yaml) -We log into CloudFoundry using the configured environment variables. We then run a smoke test to make sure that the app built correctly. +We log into CloudFoundry using the configured environment variables. Before deploying, we cancel any existing deployments to prevent conflicts. When deploying, we use healthchecks to check that the /__canary__ path returns +a 200 response, which indicates that the app has been built successfully. ## Hosting on GOV.UK Platform as a Service (PaaS) -We deploy to the `govuk-design-system-origin` app using the -[blue-green-deploy][bgd] plugin. +We deploy to the `govuk-design-system-origin` app. This app exists within the `govuk-design-system` organisation and the `production` space, and is deployed by the `design-system-deploy-production@digital.cabinet-office.gov.uk` user, the @@ -115,10 +114,8 @@ trailing-slashed URLs, but decided against it because: - other parts of GOV.UK's infrastructure (such as their mirroring) make assumptions based on the lack of a trailing slash and relative URLs. -[travis]: https://travis-ci.org/alphagov/govuk-design-system -[travis-env]: https://docs.travis-ci.com/user/environment-variables/ +[github-actions]: https://github.com/alphagov/govuk-design-system/actions [paas]: https://www.cloud.service.gov.uk/ -[bgd]: https://github.com/bluemixgaragelondon/cf-blue-green-deploy [nginx-bp]: https://github.com/cloudfoundry/nginx-buildpack [govuk-dns-config]: https://github.com/alphagov/govuk-dns-config/blob/master/service.gov.uk.yaml [govuk-dns]: https://github.com/alphagov/govuk-dns From 35c3ffbb8c87ce40be51e8efff2162888184486d Mon Sep 17 00:00:00 2001 From: Vanita Barrett Date: Mon, 18 Jan 2021 14:08:27 +0000 Subject: [PATCH 7/7] Add comment explaining why we use an artifact --- .github/workflows/ci.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f8f99319b8..10f2366d72 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,6 +2,8 @@ name: CI Workflow on: [push, pull_request] +# Separate build and deploy jobs so we can build all branches and pull requests +# but only deploy from master jobs: build: name: Build & Test @@ -30,6 +32,8 @@ jobs: - name: Lint and test run: npm test -- --runInBand + # Share data between the build and deploy jobs so we don't need to run `npm run build` again on deploy + # Upload the deploy folder as an artifact so it can be downloaded and used in the deploy job - name: Upload artifact uses: actions/upload-artifact@v2 with: