.circleci/config.yml
version: 2.1
orbs:
codecov: codecov/codecov@3.2.5
executors:
node:
docker:
- image: cimg/node:18.17.0
working_directory: ~/repo
resource_class: large
ruby_with_postgres:
parameters:
collects_rails_coverage:
type: boolean
default: false
docker:
- image: cimg/ruby:3.0.6-browsers
environment:
PG_HOST: localhost
PG_USER: ubuntu
RAILS_ENV: test
BUNDLE_APP_CONFIG: ~/repo/.bundle
DATABASE_URL: "postgres://ubuntu@localhost:5432/coursemology_test"
COLLECT_COVERAGE: << parameters.collects_rails_coverage >>
- image: cimg/postgres:14.5
environment:
POSTGRES_USER: ubuntu
POSTGRES_DB: coursemology_test
- image: cimg/redis:7.2.3
working_directory: ~/repo
resource_class: large
commands:
checkout_with_submodules:
steps:
- checkout
- run:
name: Checkout submodules
command: git submodule update --init --recursive
rehydrate_ruby_deps:
steps:
- restore_cache:
name: Restore Ruby dependencies cache
keys:
- v3.0.6-ruby-{{ checksum "Gemfile.lock" }}
- v3.0.6-ruby-
- run:
name: Install Bundler
command: gem install bundler:2.2.33
- run:
name: Install Ruby dependencies
command: bundle install --jobs=4 --retry=3 --path vendor/bundle --without development:production --deployment
- save_cache:
paths:
- ./vendor/bundle
- ./.bundle
key: v3.0.6-ruby-{{ checksum "Gemfile.lock" }}
rehydrate_node_deps:
steps:
- restore_cache:
name: Restore client Yarn dependencies cache
keys:
- v18.17.0-node-{{ checksum "client/yarn.lock" }}-{{ checksum "client/vendor/recorderjs/package.json" }}
- v18.17.0-node-
- run:
name: Install client Yarn dependencies
working_directory: client
command: yarn install
- save_cache:
paths:
- ./client/node_modules
- ./client/vendor/recorderjs/node_modules
key: v18.17.0-node-{{ checksum "client/yarn.lock" }}-{{ checksum "client/vendor/recorderjs/package.json" }}
restore_client_cache:
steps:
- restore_cache:
name: Restore client cache
keys:
- v1-yarn-build-{{ .Revision }}
build_and_cache_client:
steps:
- restore_client_cache
- run:
name: Add env file to client folder
working_directory: client
command: |
touch .env
echo GOOGLE_RECAPTCHA_SITE_KEY="${GOOGLE_RECAPTCHA_SITE_KEY}" >> .env
echo ROLLBAR_POST_CLIENT_ITEM_KEY="${ROLLBAR_POST_CLIENT_ITEM_KEY}" >> .env
echo SUPPORT_EMAIL="${SUPPORT_EMAIL}" >> .env
echo DEFAULT_LOCALE="${DEFAULT_LOCALE}" >> .env
echo DEFAULT_TIME_ZONE="${DEFAULT_TIME_ZONE}" >> .env
- run:
name: Build client
working_directory: client
command: yarn build:test
environment:
AVAILABLE_CPUS: 4
- save_cache:
paths:
- ./client/build
key: v1-yarn-build-{{ .Revision }}
setup_db:
steps:
- run:
name: Set up test database
command: bundle exec rake db:setup
environment:
COLLECT_COVERAGE: false
serve_static_site:
steps:
- run:
name: Download dirt-cheap-rocket
command: curl https://github.com/Coursemology/dirt-cheap-rocket/releases/latest/download/dirt-cheap-rocket.cjs -o dirt-cheap-rocket.cjs -L
- run:
name: Serve static site
command: node dirt-cheap-rocket.cjs
background: true
environment:
DCR_CLIENT_PORT: 3200
DCR_SERVER_PORT: 7979
DCR_PUBLIC_PATH: /static
DCR_ASSETS_DIR: client/build
serve_rails_server:
steps:
- run:
name: Serve Rails server
command: bundle exec rails s -p 7979
background: true
- run:
name: Wait for Rails server
command: curl -s --retry 1000 --retry-delay 1 --retry-connrefused http://lvh.me:7979
terminate_rails_and_wait_for_coverage_results:
steps:
- run:
name: Terminate Rails server
command: pkill -SIGTERM -f puma
- run:
name: Wait for Rails coverage results
no_output_timeout: 5m
command: until [ -f coverage/codecov-result.json ]; do sleep 1; done
setup_docker_layer_cache:
steps:
- setup_remote_docker:
docker_layer_caching: true
# Install Ghostscript so `identify` in ImageMagick works with PDF files.
# To remove PDF security policy for ImageMagick (Ubuntu 20.04), see https://stackoverflow.com/questions/52998331/imagemagick-security-policy-pdf-blocking-conversion
# This is currently not used as CircleCI would fail to install occasionally.
install_ghostscript_and_imagemagick:
steps:
- run:
name: Install Ghostscript and ImageMagick
command: |
sudo apt update
sudo apt install imagemagick
sudo apt install ghostscript
sudo sed -i '/disable ghostscript format types/,+6d' /etc/ImageMagick-6/policy.xml
jobs:
build_client:
executor: node
steps:
- checkout_with_submodules
- rehydrate_node_deps
- build_and_cache_client
test_playwright:
executor:
name: ruby_with_postgres
collects_rails_coverage: true
parallelism: 10
steps:
- checkout_with_submodules
- setup_docker_layer_cache
- rehydrate_ruby_deps
- restore_client_cache
- setup_db
- serve_static_site
- serve_rails_server
- run:
name: Install Playwright dependencies
working_directory: tests
command: yarn install; yarn prepare
- run:
name: Run Playwright tests
working_directory: tests
command: |
SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npx playwright test --shard=${SHARD}/${CIRCLE_NODE_TOTAL} --reporter=junit
environment:
PLAYWRIGHT_JUNIT_OUTPUT_NAME: results.xml
- run:
name: Generate code coverage
working_directory: tests
command: yarn coverage
- terminate_rails_and_wait_for_coverage_results
- run:
name: Zip test results
when: always
working_directory: tests
command: |
zip -r test-results.zip test-results
# - codecov/upload:
# upload_name: playwright-client
# file: tests/coverage/lcov.info
- codecov/upload:
upload_name: playwright-rails
file: coverage/codecov-result.json
- store_test_results:
path: ~/repo/tests/results.xml
- store_artifacts:
path: ~/repo/tests/results.xml
- store_artifacts:
path: ~/repo/tests/test-results.zip
test_rspec:
executor:
name: ruby_with_postgres
collects_rails_coverage: true
parallelism: 30
steps:
- checkout_with_submodules
- setup_docker_layer_cache
- rehydrate_ruby_deps
- restore_client_cache
- setup_db
- serve_static_site
- run:
name: Run RSpec tests
no_output_timeout: 10m
command: |
mkdir ~/rspec
circleci tests glob "spec/**/*_spec.rb" | circleci tests run --command="xargs bundle exec rspec --format progress --format RspecJunitFormatter -o ~/rspec/rspec.xml" --verbose --split-by=timings
- store_test_results:
path: ~/rspec
factorybot_lint:
executor: ruby_with_postgres
steps:
- checkout
- rehydrate_ruby_deps
- setup_db
- run:
name: Run FactoryBot lint
command: bundle exec rake factory_bot:lint
jslint:
executor: node
steps:
- checkout_with_submodules
- rehydrate_node_deps
- run:
name: Run ESLint and Prettier checks
working_directory: client
command: yarn lint
jstest:
executor: node
steps:
- checkout_with_submodules
- rehydrate_node_deps
- run:
name: Build translations
working_directory: client
command: yarn run build:translations
- run:
name: Run Jest tests
working_directory: client
command: yarn testci
i18n_en:
executor: ruby_with_postgres
steps:
- checkout
- rehydrate_ruby_deps
- setup_db
- run:
name: Check for unused translations (English)
command: bundle exec i18n-tasks unused --locales en
- run:
name: Check for missing translations (English)
command: bundle exec i18n-tasks missing --locales en
i18n_zh:
executor: ruby_with_postgres
steps:
- checkout
- rehydrate_ruby_deps
- setup_db
- run:
name: Check for unused translations (Mandarin)
command: bundle exec i18n-tasks unused --locales zh
- run:
name: Check for missing translations (Mandarin)
command: bundle exec i18n-tasks missing --locales zh
workflows:
build_and_test_and_lint:
jobs:
- jslint
- jstest
- build_client
- i18n_en
- i18n_zh
- factorybot_lint
- test_rspec:
requires:
- build_client
- factorybot_lint
- test_playwright:
requires:
- build_client