Skip to content

GitHub Actions

Selective detects GitHub Actions automatically. The one thing it can’t infer is which parallel node it is on, so the setup action passes that in along with the API key.

Add the secret SELECTIVE_API_KEY to the repository, then in the job that runs tests:

- name: Setup Selective
uses: selectiveci/setup-selective@v1
with:
api-key: ${{ secrets.SELECTIVE_API_KEY }}
runner-id: ${{ matrix.ci_node_index }}
- name: Run tests
run: bundle exec selective rspec
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ci_node_index: [0, 1, 2, 3]
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Setup Selective
uses: selectiveci/setup-selective@v1
with:
api-key: ${{ secrets.SELECTIVE_API_KEY }}
runner-id: ${{ matrix.ci_node_index }}
- name: Run tests
run: bundle exec selective rspec

Four matrix entries means four nodes pulling from the same queue. Change the list to change the node count; nothing else needs to move.

A working example lives in the selective-ruby-rspec workflow and the selective-ruby-minitest workflow.

The run, attempt, branch, commit, base commit (from the pull request event when there is one), repository slug and actor all come from the GitHub Actions environment. fail-fast: false is worth keeping so one node’s infrastructure hiccup doesn’t cancel the others mid-run.

Test selection needs a fresh map of which files each test executes. Add a daily schedule to the workflow and set SELECTIVE_TEST_MAP_RECORD only for scheduled runs, which GitHub runs on the default branch:

on:
pull_request:
push:
branches: [main]
schedule:
- cron: "0 6 * * *"
jobs:
test:
env:
SELECTIVE_TEST_MAP_RECORD: ${{ github.event_name == 'schedule' && '1' || '' }}

The scheduled run prints Test selection: running all tests (recording requested). Recording a test map. See keeping the map fresh.

With test selection on, a separate job tells Selective about the run as it starts, so the commit’s file tree, the map and the semantic decision are ready by the time the test nodes connect. Without it, selection still works; it takes longer to apply once the nodes are up. See warm-up.

jobs:
selective-warmup:
runs-on: ubuntu-latest
steps:
- name: Warm up Selective
continue-on-error: true
env:
SELECTIVE_API_KEY: ${{ secrets.SELECTIVE_API_KEY }}
BODY: >-
{"sha": "${{ github.sha }}",
"git_repo_full_name": "${{ github.repository }}",
"base_sha": "${{ github.event.pull_request.base.sha || github.event.before }}",
"target_branch": "${{ github.base_ref }}",
"branch": "${{ github.head_ref || github.ref_name }}"}
run: |
curl -sS --max-time 20 -X POST https://app.selective.ci/warmup \
-H "authorization: $SELECTIVE_API_KEY" -H "content-type: application/json" -d "$BODY"

The test job doesn’t need it (no needs:), so the two run side by side. These are the values the runner reports: GITHUB_SHA (on pull_request events that is the merge commit, not the branch head), the pull request’s base commit or a push’s before, and GITHUB_BASE_REF. Use one warm-up step per suite, each with that suite’s key.