Production · GitHub Actions · cheat sheet

Game-day pipeline checklist

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.

Download the PDFAll cheat sheets

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