GitHub Actions for ML Workflows
The churn repo lives on GitHub, so the easiest robot to hire is GitHub Actions. You write a YAML file describing when to run and what to run, and every pull request gets a fresh machine that installs, fetches data, tests and trains — then shows a green tick or a red cross.
The rule
Event triggers, runner starts, steps run in order, any failure stops.
A workflow is a file in .github/workflows/:
name: churn-ci
on:
pull_request:
branches: [main]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install -r requirements.txt
- run: dvc pull
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- run: pytest tests/
- run: dvc reproRead it top to bottom:
onis the event: here, any pull request targetingmain. Others includepush, aschedulewith a cron expression (useful for continuous training), orworkflow_dispatchfor a manual button.jobsholds one or more jobs; each gets its own runner, a fresh virtual machine.runs-onpicks it.stepsrun in order.uses:pulls in a ready-made action (checkout the code, install Python);run:executes a shell command.secretsare encrypted values stored in the repository settings. The storage keys reachdvc pullas environment variables and are masked in logs. They never appear in the YAML.
If any step exits with an error, later steps are skipped and the check turns red. With branch protection on main, red means the pull request cannot merge.
GitLab CI (.gitlab-ci.yml) and Jenkins (a Jenkinsfile) express the same ideas — triggers, stages, steps, secrets — with different syntax.
The shortcut
Read any workflow as four answers: When? Where? What, in order? With which secrets?
When?
on: pull_requesttomain: every proposed change.
Drills
Answer fast — trust the rule.
Which on: value would retrain the churn model every Sunday even with no code change?
Where should the AWS keys used by dvc pull come from?
dvc pull fails because the bucket is unreachable. What happens to pytest and dvc repro?
Why is a fresh runner for every job useful for ML checks?
Remember
- Event triggers, runner starts, steps run in order, any failure stops.
- Read any workflow as: when, where, what in order, which secrets.
- Trap: credentials in the YAML; always use repository secrets.
