Production · GitHub Actions · cheat sheet
A scheduled pipeline runs without you, so everything it needs is written down: when it runs, what it reads, what it refuses, what it produces, and who hears when it fails.
Pythonpipeline.py: read, check, publish. Exits non-zero on bad data, so the failure path fires.
import json
import sys
import pandas as pd
games = pd.read_csv("data/game_log.csv")
missing = [c for c in ["game", "runs_scored", "runs_allowed"] if games[c].isna().any()]
if missing or games.game.duplicated().any():
sys.exit(f"refusing to publish: missing {missing} or duplicated games")
last15 = games.tail(15).assign(diff=lambda d: d.runs_scored - d.runs_allowed)
report = {"games": int(len(games)), "last15_run_diff": round(float(last15["diff"].mean()), 2)}
with open("report.json", "w") as f:
json.dump(report, f)
print(json.dumps(report))Ran when this sheet was built. Output:
{"games": 162, "last15_run_diff": 0.8}YAML.github/workflows/game-day.yml: the schedule, the secret, the artifact and the failure message. Parsed and checked at build.
name: game-day
on:
schedule:
- cron: "0 13 * * *" # 09:00 Eastern in summer, before the staff meeting
workflow_dispatch: {}
jobs:
run:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install pandas
- run: python pipeline.py
env:
FEED_TOKEN: ${{ secrets.FEED_TOKEN }}
- uses: actions/upload-artifact@v4
with:
name: report
path: report.json
- if: failure()
run: >
curl -fsS -X POST -H 'content-type: application/json'
-d '{"text":"game-day pipeline failed"}' "$SLACK_WEBHOOK"
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}Ran when this sheet was built. Output:
valid YAML: 6 steps, cron 0 13 * * *, a failure step present