Shared Github Actions
Cleans up after test runs by uploading screenshots and dumping system information to stdout.
Inputs:
artifact-prefix*: A string prefix to name the uploaded log file. Artifact name will be named${artifact-prefix}-logs
Example:
- name: Cleanup
uses: RoleModel/actions/test-cleanup@v3
with:
artifact-prefix: rspec-systemPosts the runtime of the longest test files. This is important because the most granular parallel_tests goes is at the file level, so when running in parallel, the entire suite can never be quicker than the slowest file.
Inputs:
test-output-path*: Path to the test output file that hold runtimestop-count: Number of slowest tests to show. Default: 10
Example:
- name: Analyze test runtimes
uses: RoleModel/actions/test-runtime-analyzer@v3
with:
test-output-path: tmp/turbo_rspec_runtime.logUse this action to maintain a staging branch with the changes from all open PRs labeled Staging. This is recommended to be used with a workflow that auto-deploys the staging branch.
If a PR cannot be merged cleanly, the action comments on the PR with conflict details and removes the Staging label.
This action assumes the repository has already been cloned with ref: staging and fetch-depth: 0 set. Commits/pushes made using the default GitHub Actions access key do not trigger other actions, so make sure to generate a personal access token or SSH key so that staging auto-deploys can work.
Inputs:
github-token: GitHub token used to list/update pull requests. Default:${{ github.token }}primary-branch: Branch used as the reset base before staged merges. Default:main
Example:
name: Maintain staging branch
on:
pull_request:
types:
- labeled
- unlabeled
- closed
- synchronize
jobs:
maintain_staging:
if: (contains(github.event.pull_request.labels[*].name, 'Staging')) || (github.event.action == 'closed' && github.event.pull_request.merged) || (github.event.label.name == 'Staging')
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- name: Check out repository
uses: actions/checkout@v7
with:
ref: staging
fetch-depth: 0
ssh-key: ${{ secrets.AUTOMATED_COMMITS_KEY }} # IMPORTANT: Use a custom key to allow triggering other workflows
- name: Rebuild staging branch
uses: RoleModel/actions/staging-auto-merge@v3.github/workflows/rails-ci.yml is a workflow_call reusable workflow that runs an entire Rails app's CI — linting, Brakeman, dependency audit, asset compilation/caching, and parallel_rspec — as a single job. It supersedes the composite actions below: use it for new projects, and prefer migrating an existing ci.yml to it over adding to the composite-action setup, since it schedules the independent setup steps (Ruby/gems, apt packages, Node/Yarn, asset cache, Brakeman, Rubocop, ESLint, dependency audit, Project Stats) to overlap with background:/wait:/parallel: step syntax instead of running them sequentially across multiple jobs.
apt_packages: Space-separated apt packages to install alongside setup (e.g. "libvips")brakeman_version: Brakeman gem version to run via reviewdog (omit to skip, e.g. "8.0.5")dependency_audit_command: Dependency audit command to run (omit to skip)extra_env: Additional non-secret environment variables, one KEY=VALUE per line (same format as a .env file). Use this for anything the app requires that isn't already covered by an existing input. For real secret values, use theextra_secretssecret instead —secrets.*can't be referenced here since this is awith:input, evaluated before the caller's secrets are in scope.failure-screenshot-dir: the directory where your test runner saves screenshots on failure. Default:tmp/capybarajs_lint_command: JS linting command to run (omit to skip)playwright: Install the Playwright Chromium browser (for apps using capybara-playwright-driver). Default:falsepostgres_version: Postgres Docker image version tag. Default:"17"project-stats: Runbin/rails statsand post the results to the job summary. Default:truerubocop_command: Rubocop command to run (omit to skip)runner: Runner to use. Default:blacksmith-8vcpu-ubuntu-2404timeout: Job timeout in minutes. Default:20
RAILS_MASTER_KEY: Rails master key for decrypting credentialsBUNDLE_RUBYGEMS__PKG__GITHUB__COM: Credential for the RoleModel RubyGems package registryextra_secrets: Additional secret environment variables, one KEY=VALUE per line (same shape asextra_env). Pass real secret values through here, referencing the caller's own secrets context on the right-hand side of each line.
extra_env and extra_secrets exist for the same reason (app-specific env vars the workflow doesn't already name), but land differently: extra_env is a with: input, evaluated before the caller's secrets: context is in scope, so it can only carry non-secret KEY=VALUE lines. extra_secrets is a real secrets: value, so it's the one to use for anything sensitive — reference the caller's own secrets on the right-hand side, e.g. STRIPE_PRIVATE_KEY=${{ secrets.STRIPE_PRIVATE_KEY }}.
project-stats is a built-in input (default true) that publishes its own "Project Stats" GitHub check as part of the job. Callers of rails-ci.yml get this for free and don't need the separate standalone project-stats job shown in the composite-action example below.
jobs:
ci:
uses: RoleModel/actions/.github/workflows/rails-ci.yml@v3
with:
rubocop_command: bundle exec rubocop --format github
dependency_audit_command: bin/bundler-audit && bin/brakeman --quiet --no-pager --exit-on-warn --exit-on-error
failure-screenshot-dir: tmp/screenshots
secrets: inheritjobs:
ci:
uses: RoleModel/actions/.github/workflows/rails-ci.yml@v3
with:
apt_packages: libvips
playwright: true
rubocop_command: bundle exec rubocop --format github
js_lint_command: yarn lint
dependency_audit_command: bin/bundler-audit
brakeman_version: "8.0.5"
failure-screenshot-dir: tmp/screenshots
extra_env: |
STRIPE_PUBLISHABLE_KEY=pk_test_placeholder
secrets:
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
BUNDLE_RUBYGEMS__PKG__GITHUB__COM: ${{ secrets.BUNDLE_RUBYGEMS__PKG__GITHUB__COM }}
extra_secrets: |
STRIPE_PRIVATE_KEY=${{ secrets.STRIPE_PRIVATE_KEY }}This is a combination of multiple composite actions that can be used to run your entire CI flow for a rails app using parallel_tests. Each action allow you to customize the machine, environment variables, and any custom install steps that are needed. It does require you to check out the code yourself, since some install steps might happen after that.
linting-and-non-system-tests:linting_step_required- Whether linting is required
- Optional, default is
false
linting_step_command- Command for linting (e.g., "bundle exec rubocop")
- Optional, default is
''
needs-compiled-assets- Whether to retrieve the Rails asset cache (set to false if your workflow does not depend on the compile-assets workflow)
- Optional, default is
true
system-tests:web-driver- Supported values are 'selenium' and 'playwright'
- Optional, default is
selenium
failure-screenshot-dir- the directory where your test runner saves screenshots on failure
- Optional, default is
tmp/capybara
name: CI
on:
push:
branches: [ main, master ]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}-${{ github.event.ref }}
cancel-in-progress: true
env:
CI: true
RAILS_ENV: test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
SECRET_KEY_BASE: 123 # If you are using encrypted credentials, you'll need to extract this into a GitHub secret.
# Otherwise, the only thing that matters is that the value is not nil.
jobs:
compile-assets:
name: Compile Assets
runs-on: blacksmith-4vcpu-ubuntu-2204
timeout-minutes: 5
steps:
- name: Checkout Code
uses: actions/checkout@v7
- uses: RoleModel/actions/compile-assets@v3
id: check-asset-cache
non-system-test:
name: Linting & Ruby Non-System Tests
runs-on: blacksmith-8vcpu-ubuntu-2204
timeout-minutes: 5
# If you have non-system tests that touch the browser, you may need to uncomment the following line.
# needs: compile-assets
services:
postgres:
image: postgres:17
ports:
- "5432:5432"
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
steps:
- name: Checkout Code
uses: actions/checkout@v7
- uses: RoleModel/actions/linting-and-non-system-tests@v3
with:
linting_step_required: true
linting_step_command: bundle exec rubocop --fail-level warning --display-only-fail-level-offenses --format github
needs-compiled-assets: false # Remove this input if you uncommented `needs: compile-assets` above.
system-test:
name: Ruby System Tests
runs-on: blacksmith-16vcpu-ubuntu-2204
timeout-minutes: 10
needs: compile-assets
services:
postgres:
image: postgres:17
ports:
- "5432:5432"
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
steps:
- name: Checkout Code
uses: actions/checkout@v7
# Custom install steps may be added between checkout & test run if needed. e.g.
# If your application processes ActiveStorage::Variant records you probably need the following step:
- run: |
sudo apt-get update
sudo apt-get install -y libvips
- uses: RoleModel/actions/system-tests@v3
with:
failure-screenshot-dir: tmp/screenshots # if you've configured capybara to be compatible with the tmp:clear task
web-driver: playwright # remove this input to use the default value (selenium)
# completely optional job (for Rails projects only) - outputs a stats table in your workflow's summary page
project-stats:
name: Project Stats
runs-on: blacksmith-4vcpu-ubuntu-2204
timeout-minutes: 5
steps:
- name: Checkout Code
uses: actions/checkout@v7
- name: Capture Project Stats
uses: RoleModel/actions/project-statsThis is using anothrNick/github-tag-action to automatically
post version tags when a commit is merged to master. Unless you include #patch or #major in your commit message,
it will automatically create a new tag a minor version higher. #none will skip tagging altogether.