4.4 KiB
CI/CD Primer for Stegasoo
What is CI/CD?
CI = Continuous Integration CD = Continuous Deployment
Think of it as a robot assistant that automatically:
- Tests your code every time you push
- Checks formatting so code stays consistent
- Publishes releases when you tag a version
You push code → GitHub runs workflows → You get ✓ or ✗
How It Works
The Trigger
When you git push or create a Pull Request, GitHub looks for workflow files in:
.github/workflows/*.yml
Each .yml file defines a workflow - a series of steps to run.
The Runners
GitHub provides free Linux/Mac/Windows VMs that:
- Clone your repo
- Set up Python
- Run your commands
- Report success/failure
You don't manage servers - GitHub does.
Your Workflows
1. test.yml - Run Tests on Every Push
When it runs: Every push, every PR
What it does:
1. Spins up Ubuntu VM
2. Installs Python 3.10, 3.11, 3.12
3. Installs your package + dependencies
4. Runs pytest
5. Reports pass/fail
You'll see: Green ✓ or red ✗ on your commits
2. lint.yml - Check Code Style
When it runs: Every push, every PR
What it does:
1. Runs ruff (fast Python linter)
2. Checks black formatting
3. Fails if code isn't formatted
Why: Keeps code consistent, catches common bugs
3. release.yml - Publish to PyPI
When it runs: Only when you create a version tag
What it does:
1. Builds the package (wheel + sdist)
2. Uploads to PyPI
You trigger it by:
git tag v2.2.0
git push origin v2.2.0
Day-to-Day Usage
Normal Development
# Make changes
git add .
git commit -m "Add new feature"
git push
Then check GitHub → Actions tab → See if tests pass.
If Tests Fail
- Click the failed workflow
- Click the failed job
- Read the error log
- Fix locally, push again
Making a Release
# 1. Update version in pyproject.toml and constants.py
# 2. Commit the version bump
git add .
git commit -m "Bump version to 2.2.1"
git push
# 3. Create and push a tag
git tag v2.2.1
git push origin v2.2.1
# 4. GitHub automatically publishes to PyPI
Reading the GitHub UI
Actions Tab
Repository → Actions → [List of workflow runs]
Each run shows:
- ✓ Green checkmark = passed
- ✗ Red X = failed
- 🟡 Yellow dot = running
Pull Request Checks
When you open a PR, you'll see:
┌─────────────────────────────────────────┐
│ All checks have passed │
│ ✓ test (3.10) — 45s │
│ ✓ test (3.11) — 42s │
│ ✓ test (3.12) — 44s │
│ ✓ lint — 12s │
└─────────────────────────────────────────┘
Setting Up PyPI Publishing
For release.yml to work, you need to add a PyPI API token:
One-Time Setup
-
Create PyPI account at https://pypi.org/account/register/
-
Generate API token:
- PyPI → Account Settings → API tokens
- Create token (scope: entire account or just stegasoo)
- Copy the token (starts with
pypi-)
-
Add to GitHub:
- GitHub repo → Settings → Secrets and variables → Actions
- New repository secret
- Name:
PYPI_API_TOKEN - Value: paste the token
Now release.yml can publish automatically.
Common Scenarios
"Tests pass locally but fail in CI"
Usually means:
- Missing dependency in
pyproject.toml - Hardcoded path that doesn't exist in CI
- Test relies on local file
"Lint is failing"
Run locally to see/fix:
# Check issues
ruff check src/
# Auto-fix what's possible
ruff check --fix src/
# Format code
black src/
"I want to skip CI for a commit"
Add [skip ci] to commit message:
git commit -m "Update README [skip ci]"
Costs
GitHub Actions is free for public repos.
For private repos: 2,000 minutes/month free, then paid.
Summary
| Action | What Happens |
|---|---|
git push |
Tests + lint run automatically |
| Open PR | Tests must pass before merge |
git tag v* |
Publishes to PyPI |
| Check results | GitHub → Actions tab |
That's it! Push code, check for green checkmarks.