Usually our code lives on GitLab, therefore our documentation for CI testing is extensive in this environment. If you are tied to GitHub e.g. because your customer uses it, you may use the following GitHub Actions template for the CI integration. It includes jobs for rspec
(parallelized using knapsack, unit + feature specs), rubocop
, eslint
, coverage
and license_finder
.
Note that GitHub does not allow the use of YAML anchors and aliases. You can instead use
composite actions
Show archive.org snapshot
to extract and re-use partials between multiple jobs. This template uses two such custom actions: setup-node
and setup-ruby
.github/workflows/integration-testing.yml
name: Integration Testing
on:
push:
branches: [ main, production ]
pull_request:
branches: [ main, production ]
# Display "Run Workflow" button on the web UI
workflow_dispatch:
branches: [ main, production ]
# Cancel existing CI jobs on the same PR when a new commit is being pushed
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
# Run all unit and integration tests
run_tests:
name: Run Tests (Partition ${{ matrix.partition }})
runs-on: ubuntu-latest # NOTE: this image ships with a recent version of chrome!
services:
postgres:
image: postgres:17
env:
POSTGRES_DB: test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PGTZ: "Europe/Berlin"
options: >- # Set health checks to wait until postgres has started
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports: [ '5432:5432' ]
env:
DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL: 'true'
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test
PGTZ: 'Europe/Berlin'
RAILS_ENV: test
TZ: 'Europe/Berlin'
strategy:
matrix:
partition: [ 0, 1, 2, 3 ] # Keep in sync with CI_NODE_TOTAL below
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node
- uses: ./.github/actions/setup-ruby
- name: Setup database schema
run: bundle exec rails db:create db:schema:load
- name: Precompile assets
run: bundle exec rails assets:precompile
- name: Run parallel tests
id: rspec
run: |
CI_NODE_TOTAL=4 CI_NODE_INDEX=${{ matrix.partition }} \
bundle exec rails "knapsack:rspec"
- name: Upload Capybara screenshots
if: ${{ failure() && steps.rspec.conclusion == 'failure' }} # this should only be done when the previous step fails
uses: actions/upload-artifact@v4
with:
name: capybara-screenshots-${{ matrix.partition }}
path: tmp/artifacts/capybara
- name: Upload coverage results
uses: actions/upload-artifact@v4
with:
name: coverage-report-${{ matrix.partition }}
include-hidden-files: true
path: tmp/coverage/**/*
rubocop:
name: Lint Ruby Code
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-ruby
- name: Run RuboCop
run: bundle exec rubocop --color
eslint:
name: Lint JavaScript Code
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node
- name: Run EsLint
run: yarn run linter
# Ensure only permitted licenses are used in the code
license_finder:
name: License Finder
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node
- uses: ./.github/actions/setup-ruby
- name: Run License Finder
run: bundle exec license_finder action_items
# Run static code analysis checks against the code base
brakeman:
name: Brakeman Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-ruby
- name: Run brakeman
run: bundle exec brakeman --color
# Combine coverage results from the test runners to a single report
coverage:
name: Merge Coverage Reports
runs-on: ubuntu-latest
needs: [ run_tests ]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-ruby
- uses: actions/download-artifact@v4
with:
pattern: coverage-report-*
merge-multiple: true
path: tmp/coverage
- name: Run coverage merger
run: bundle exec rake merge_coverage_reports --trace
env:
RAILS_ENV: test
TZ: 'Europe/Berlin'
- name: Upload coverage results
uses: actions/upload-artifact@v4
with:
name: combined_coverage_report
path: tmp/coverage
.github/actions/setup-node/action.yml
name: Setup Node
description: "Install Node, package manager, and npm packages"
runs:
using: composite
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Install node modules with yarn
run: yarn --frozen-lockfile --immutable
shell: bash
- name: Verify Node and Yarn versions
run: |
node -v
yarn -v
shell: bash
.github/actions/setup-ruby/action.yml
name: "Setup Ruby"
description: "Install Ruby and gems with essential system deps for our rails app"
runs:
using: "composite"
steps:
- name: Install system deps
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends --no-install-suggests -y \
build-essential \
libffi-dev \
libxml2-dev \
pkg-config \
libxslt1-dev \
libpq-dev \
postgresql-client
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
shell: bash
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ".ruby-version"
bundler-cache: true
cache-version: 1
- name: Verify Ruby and Bundler versions
run: |
ruby -v
bundle -v
shell: bash
- name: Test postgres connection
run: "psql $DATABASE_URL -c 'SELECT 1;'"
shell: bash
Posted by Michael Leimstädtner to makandra dev (2024-02-05 11:10)