.circleci/config.yml
version: 2.1
orbs:
aws-cli: circleci/aws-cli@4.0.0
browser-tools: circleci/browser-tools@1.4.8
slack: circleci/slack@3.4.1
references:
_attach-tmp-workspace: &attach-tmp-workspace
attach_workspace:
at: ~/repo/tmp
_create-tmp-dir: &create-tmp-dir
run:
name: Create workspace temporary directories
command: |
mkdir -p tmp/
mkdir -p tmp/coverage/
mkdir -p /tmp/test-results/rspec
mkdir -p /tmp/test-results/cucumber
_install-codeclimate: &install-codeclimate
run:
name: Install Code Climate test-reporter
command: |
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > tmp/cc-test-reporter
chmod +x tmp/cc-test-reporter
_persist-codeclimate: &persist-codeclimate
persist_to_workspace:
root: tmp
paths:
- cc-test-reporter
_wait-for-db: &wait-for-db
run:
name: Wait for DB
command: dockerize -wait tcp://localhost:5432 -timeout 1m
_load-db: &load-db
run:
name: Database setup
command: bin/rails db:schema:load --trace
_script-build-app-container: &script-build-app-container
run:
name: Build and push cccd docker image
command: |
.circleci/build.sh
# ------------------
# EXECUTORS
# ------------------
executors:
basic-executor:
resource_class: small
docker:
- image: cimg/base:2020.01
environment:
GITHUB_TEAM_NAME_SLUG: laa-get-paid
REPO_NAME: cccd
cloud-platform-executor:
resource_class: small
docker:
- image: ministryofjustice/cloud-platform-tools
environment:
GITHUB_TEAM_NAME_SLUG: laa-get-paid
REPO_NAME: cccd
smoke-test-executor:
resource_class: medium
working_directory: /usr/src/app
parameters:
tag:
description: Image tag to use for test
default: app-latest
type: string
docker:
- image: ${ECR_ENDPOINT}/laa-get-paid/cccd:<<parameters.tag>>
aws_auth:
oidc_role_arn: $ECR_ROLE_TO_ASSUME
environment:
BASH: true
RAILS_ENV: test
ADVOCATE_PASSWORD: just-be-present
CASE_WORKER_PASSWORD: just-be-present
ADMIN_PASSWORD: just-be-present
SECRET_KEY_BASE: just-be-present
SUPERADMIN_USERNAME: superadmin@circleci.com
SUPERADMIN_PASSWORD: just-be-present
DATABASE_URL: postgres://postgres:circleci@127.0.0.1:5432/cccd_smoke_test
TZ: Europe/London
GITHUB_TEAM_NAME_SLUG: laa-get-paid
REPO_NAME: cccd
LIVE1_DB_TASK: none
- image: cimg/postgres:13.3
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: "circleci"
POSTGRES_DB: cccd_smoke_test
test-executor:
working_directory: ~/repo
docker:
- image: cimg/ruby:3.3.5-browsers
environment:
RAILS_ENV: test
DATABASE_URL: postgres://postgres:circleci@127.0.0.1:5432/cccd_test
TZ: Europe/London
GITHUB_TEAM_NAME_SLUG: laa-get-paid
REPO_NAME: cccd
- image: cimg/postgres:13.3
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: "circleci"
POSTGRES_DB: cccd_test
# ------------------
# COMMANDS
# ------------------
commands:
aws-cli-setup:
steps:
- aws-cli/setup:
role_arn: $ECR_ROLE_TO_ASSUME
region: $ECR_REGION
install-chrome:
steps:
- browser-tools/install-chrome
- browser-tools/install-chromedriver
precompile-assets:
description: >
Precompile assets
steps:
- run:
name: Precompile assets
command: bundle exec rails assets:precompile
run-rubocop:
description: >
Run rubocop
steps:
- run:
name: Run rubocop
command: bundle exec rubocop
run-brakeman:
description: >
Run brakeman
steps:
- run:
name: Run brakeman
command: bundle exec brakeman
run-standardjs:
description: >
Run standardJS
steps:
- run:
name: Run standardJS
command: yarn run validate:js
run-stylelint:
description: >
Run stylelint
steps:
- run:
name: Run stylelint
command: yarn run validate:scss
run-jasmine:
description: >
Run jasmine tests
steps:
- install-chrome
- precompile-assets
- run:
name: Run jasmine
command: |
bundle exec rails jasmine:run
run-rspec:
description: >
Run rspec tests and store results
steps:
- *attach-tmp-workspace
- precompile-assets
- run:
name: Run rspec tests
command: |
tmp/cc-test-reporter before-build
TESTFILES=$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings --timings-type=filename)
bundle exec rspec --format progress \
--format RspecJunitFormatter \
-o /tmp/test-results/rspec/rspec.xml \
-- ${TESTFILES}
tmp/cc-test-reporter format-coverage -t simplecov -o "tmp/coverage/codeclimate.$CIRCLE_NODE_INDEX.json"
- persist_to_workspace:
root: tmp
paths:
- coverage/codeclimate.*.json
- store_artifacts:
path: tmp/coverage
- store_test_results:
path: /tmp/test-results/rspec
run-cucumber:
description: >
Run cucumber tests and store results
steps:
- precompile-assets
- run:
name: Run cucumber tests
command: |
circleci tests glob "features/**/*.feature" \
| circleci tests run --command="xargs bundle exec cucumber \
--format pretty \
--format junit,fileattribute=true \
--out /tmp/test-results/cucumber" \
--split-by=timings \
--timings-type=filename
- store_artifacts:
path: tmp/capybara
- store_test_results:
path: /tmp/test-results/cucumber
install-gem-dependencies:
description: >
Install, or restore from cache, ruby gem dependencies
steps:
- restore_cache:
keys:
- v5-dependencies-{{ checksum "Gemfile.lock" }}
# fallback to using the latest cache if no exact match is found
- v5-dependencies-
- run:
name: Install ruby gem dependencies
command: |
bundler_version=$(cat Gemfile.lock | tail -1 | tr -d " ")
gem install bundler -v $bundler_version
bundle check || bundle install --jobs=4 --retry=3 --path vendor/bundle
- save_cache:
key: v5-dependencies-{{ checksum "Gemfile.lock" }}
paths:
- vendor/bundle
install-js-dependencies:
description: >
Install, or restore from cache, javacsript package dependencies
steps:
- restore_cache:
keys:
- v2-js-dependencies-{{ checksum "yarn.lock" }}
# fallback to using the latest cache if no exact match is found
- v2-js-dependencies
- run:
name: Install javascript package dependencies
command: |
yarn install --frozen-lockfile
- save_cache:
key: v2-js-dependencies-{{ checksum "yarn.lock" }}
paths:
- node_modules
build-base:
steps:
- install-gem-dependencies
- install-js-dependencies
deploy-to:
description: >
Deploy CCCD to the specified environment
parameters:
environment:
description: destination environment
type: string
steps:
- checkout
- setup_remote_docker
- aws-cli-setup
- run:
name: deploying to << parameters.environment >> namespace
command: |
.circleci/deploy.sh << parameters.environment >>
- slack/status:
success_message: ":tada: deploy of <$CIRCLE_BUILD_URL|$CIRCLE_BRANCH> to << parameters.environment >> successful!"
failure_message: ":red_circle: deploy of <$CIRCLE_BUILD_URL|$CIRCLE_BRANCH> to << parameters.environment >> failed!"
ui-smoke-test:
description: >
Check web UI is ok
parameters:
smoke-url:
description: url of web ui to test
type: string
steps:
- run:
name: Test status OK for << parameters.smoke-url >>
command: |
STATUS=$(curl -s -o /dev/null -w "%{http_code}" << parameters.smoke-url >>)
if [ $STATUS -eq 200 ]; then
circleci-agent step halt
fi
- slack/notify:
title: ":smoke_it: UI Smoke test"
channel: laa-cccd-alerts
message: ":no_smoking: UI smoke test << parameters.smoke-url >> failed!"
color: "#FF0000"
- run:
name: UI smoke test failed
command:
exit 1
hold-notification:
description: >
Display a slack notification
parameters:
message:
description: slack message
type: string
steps:
- run:
name: Set slack notification options
command: |
if [[ $CIRCLE_BRANCH == "master" ]]; then
echo 'export CUSTOM_SLACK_COLOR="#FF8C00"' >> $BASH_ENV
else
echo 'export CUSTOM_SLACK_COLOR="#3AA3E3"' >> $BASH_ENV
fi
- slack/approval:
color: $CUSTOM_SLACK_COLOR
message: << parameters.message >>
smoke-test:
steps:
- run:
name: Persistence - prepare result storage
command: mkdir -p /tmp/smoke_test
- run:
name: Run db schema load
command: bundle exec rails db:schema:load
- run:
name: Run app server
command: bundle exec puma -p 3000
background: true
- run:
name: Run smoke test
command: |
if ./runtests.sh; then
echo 'true' > /tmp/smoke_test/success
else
echo 'false' > /tmp/smoke_test/success
fi
- persist_to_workspace:
root: /tmp/smoke_test
paths:
- success
smoke-test-notification:
steps:
- attach_workspace:
at: /tmp/smoke_test
- run:
name: Setting - determine success of smoke test
command: |
if [[ `cat /tmp/smoke_test/success` == "true" ]]; then
echo "Smoke test succeeded!";
echo 'export CUSTOM_SLACK_MESSAGE=":tada: smoke test of <$CIRCLE_BUILD_URL|$CIRCLE_BRANCH> successful!"' >> $BASH_ENV
echo 'export CUSTOM_SLACK_COLOR="#008000"' >> $BASH_ENV
exit 0
else
echo 'export CUSTOM_SLACK_MESSAGE=":no_smoking: smoke test <$CIRCLE_BUILD_URL|$CIRCLE_BRANCH> failed!"' >> $BASH_ENV
echo 'export CUSTOM_SLACK_COLOR="#FF0000"' >> $BASH_ENV
echo "Smoke test failed!";
fi
- slack/notify:
title: ":smoke_it: Smoke test"
channel: laa-claim-for-payment-development
message: $CUSTOM_SLACK_MESSAGE
color: $CUSTOM_SLACK_COLOR
# ------------------
# JOBS
# ------------------
jobs:
build-test-container:
executor: test-executor
steps:
- checkout
- setup_remote_docker
- *create-tmp-dir
- *install-codeclimate
- *persist-codeclimate
- build-base
smoke-test:
executor: smoke-test-executor
steps:
- smoke-test
smoke-test-app:
executor:
name: smoke-test-executor
tag: app-${CIRCLE_SHA1}
steps:
- smoke-test
smoke-test-notification:
executor: basic-executor
steps:
- smoke-test-notification
rspec-tests:
executor: test-executor
resource_class: large
parallelism: 6
steps:
- checkout
- build-base
- *wait-for-db
- *load-db
- run-rspec
cucumber-tests:
executor: test-executor
resource_class: small
parallelism: 6
steps:
- checkout
- run:
name: Halt if no cucumber tests to run
command: |
mkdir -p ./tmp && \
>./tmp/tests.txt && \
circleci tests glob "features/**/*.feature" | circleci tests run --command ">./tmp/tests.txt xargs echo" --split-by=timings
[ -s tmp/tests.txt ] || circleci-agent step halt
- build-base
- *wait-for-db
- *load-db
- run-cucumber
other-tests:
executor: test-executor
resource_class: medium
steps:
- checkout
- build-base
- run-rubocop
- run-brakeman
- run-jasmine
- run-standardjs
- run-stylelint
upload-coverage:
executor: test-executor
resource_class: small
steps:
- *attach-tmp-workspace
- run:
name: Upload coverage results to Code Climate
command: |
tmp/cc-test-reporter sum-coverage --output - --parts 6 tmp/coverage/codeclimate.*.json | tmp/cc-test-reporter upload-coverage --input -
build-app-container:
executor: cloud-platform-executor
steps:
- checkout
- setup_remote_docker
- aws-cli-setup
- *script-build-app-container
hold-build-notification:
executor: basic-executor
steps:
- hold-notification:
message: "Do you want to build <$CIRCLE_BUILD_URL|$CIRCLE_BRANCH>?"
hold-deploy-notification:
executor: basic-executor
steps:
- hold-notification:
message: "Deployment of <$CIRCLE_BUILD_URL|$CIRCLE_BRANCH> pending approval"
deploy-dev:
executor: cloud-platform-executor
steps:
- deploy-to:
environment: dev
deploy-dev-lgfs:
executor: cloud-platform-executor
steps:
- deploy-to:
environment: dev-lgfs
deploy-staging:
executor: cloud-platform-executor
steps:
- deploy-to:
environment: staging
deploy-api-sandbox:
executor: cloud-platform-executor
steps:
- deploy-to:
environment: api-sandbox
deploy-production:
executor: cloud-platform-executor
steps:
- deploy-to:
environment: production
auto-deploy-dev:
executor: cloud-platform-executor
steps:
- deploy-to:
environment: dev
ui-smoke-test-dev:
executor: basic-executor
steps:
- ui-smoke-test:
smoke-url: https://dev.claim-crown-court-defence.service.justice.gov.uk
# ------------------
# WORKFLOWS
# ------------------
workflows:
version: 2
test-build-deploy-master:
jobs:
- build-test-container:
filters:
branches:
only:
- master
- other-tests:
requires:
- build-test-container
- rspec-tests:
requires:
- build-test-container
- cucumber-tests:
requires:
- build-test-container
- upload-coverage:
requires:
- rspec-tests
- cucumber-tests
- other-tests
- build-app-container:
requires:
- upload-coverage
context:
- cccd-live-base
- smoke-test:
requires:
- build-app-container
context:
- cccd-live-base
- auto-deploy-dev:
requires:
- smoke-test
context:
- cccd-live-base
- cccd-live-dev
- ui-smoke-test-dev:
requires:
- auto-deploy-dev
- hold-deploy-notification:
requires:
- ui-smoke-test-dev
- hold-api-sandbox:
type: approval
requires:
- ui-smoke-test-dev
- deploy-api-sandbox:
requires:
- hold-api-sandbox
context:
- cccd-live-base
- cccd-live-api-sandbox
- hold-staging:
type: approval
requires:
- ui-smoke-test-dev
- deploy-staging:
requires:
- hold-staging
context:
- cccd-live-base
- cccd-live-staging
- hold-production:
type: approval
requires:
- ui-smoke-test-dev
- deploy-production:
requires:
- hold-production
context:
- cccd-live-base
- cccd-live-production
test-branch:
jobs:
- build-test-container:
filters:
branches:
ignore:
- master
- other-tests:
requires:
- build-test-container
- rspec-tests:
requires:
- build-test-container
- cucumber-tests:
requires:
- build-test-container
- upload-coverage:
requires:
- rspec-tests
- cucumber-tests
- other-tests
build-deploy-branch:
jobs:
- hold-build-notification:
filters:
branches:
ignore:
- master
- hold-branch-build:
type: approval
filters:
branches:
ignore:
- master
- build-app-container:
requires:
- hold-branch-build
context:
- cccd-live-base
- smoke-test-app:
requires:
- build-app-container
context:
- cccd-live-base
- hold-dev:
type: approval
requires:
- build-app-container
- hold-dev-lgfs:
type: approval
requires:
- build-app-container
- hold-staging:
type: approval
requires:
- build-app-container
- hold-api-sandbox:
type: approval
requires:
- build-app-container
- deploy-dev:
requires:
- hold-dev
context:
- cccd-live-base
- cccd-live-dev
- deploy-dev-lgfs:
requires:
- hold-dev-lgfs
context:
- cccd-live-base
- cccd-live-dev-lgfs
- deploy-staging:
requires:
- hold-staging
context:
- cccd-live-base
- cccd-live-staging
- deploy-api-sandbox:
requires:
- hold-api-sandbox
context:
- cccd-live-base
- cccd-live-api-sandbox
- ui-smoke-test-dev:
requires:
- deploy-dev
scheduled-smoke-test:
triggers:
- schedule:
cron: "5 8 * * *"
filters:
branches:
only:
- master
jobs:
- smoke-test:
context:
- cccd-live-base
- smoke-test-notification:
requires:
- smoke-test