CI/CD Pipeline¶
This document describes the automated CI/CD pipeline for save-gcp-local.
Overview¶
Feature branch ──PR──> master ──merge──> Deploy to PyPI + GitHub Release
│ │ │
└── CI checks ──────┘ └── Docs rebuild (GitHub Pages)
| Trigger | Workflow | What it does |
|---|---|---|
Pull request to master |
CI (ci.yml) |
Lint, test (Python 3.8–3.12), build wheel |
Push/merge to master |
Deploy (deploy.yml) |
Test, build, publish to PyPI, create GitHub Release |
Push to master (docs changed) |
Docs (docs.yml) |
Rebuild and deploy MkDocs site to GitHub Pages |
Workflows in detail¶
1. CI — runs on every pull request¶
File: .github/workflows/ci.yml
Steps:
- Lint — checks code formatting and style with
ruff - Test — runs
pytestacross Python 3.8, 3.9, 3.10, 3.11, 3.12 - Build — builds the wheel, installs it in a clean venv, and verifies the CLI works
All three must pass before a PR can be merged (enforced by branch protection rules).
2. Deploy — runs on merge to master¶
File: .github/workflows/deploy.yml
Steps:
- Test — runs the test suite on Python 3.8, 3.11, and 3.12 as a safety net
- Version check — reads the version from
pyproject.tomland checks if a git tag already exists - Build — builds sdist + wheel, checks with
twine - Publish — pushes to PyPI via trusted publishing (no API tokens needed)
- Release — creates a GitHub Release with auto-generated release notes
The deploy is idempotent: if the version in pyproject.toml hasn't changed since the last release, the publish and release steps are skipped. This means routine documentation or CI-only changes won't trigger a new PyPI release.
3. Docs — runs when documentation changes¶
File: .github/workflows/docs.yml
Rebuilds the MkDocs site and deploys to GitHub Pages whenever markdown files or mkdocs.yml change on master.
How to release a new version¶
- Create a feature branch from
master - Make your changes (code, tests, docs)
- Bump the version in
pyproject.toml - Update
CHANGELOG.mdwith the new version and changes - Open a pull request to
master - Wait for CI — lint, tests, and build must all pass
- Get a review and merge — the merge to
mastertriggers the deploy workflow - Done — PyPI package and GitHub Release are created automatically
# Example: releasing v0.2.1
git checkout -b release/0.2.1
# Edit pyproject.toml: version = "0.2.1"
# Edit CHANGELOG.md: add ## [0.2.1] section
git add pyproject.toml CHANGELOG.md
git commit -m "Bump version to 0.2.1"
git push -u origin release/0.2.1
# Open PR, wait for CI, merge -> auto-deploys to PyPI
Branch protection¶
Direct pushes to master are not allowed. All changes must go through a pull request with passing CI checks.
See the Branch Protection Setup section below for how to configure this.
Branch protection setup¶
This must be configured in GitHub Settings (one-time, by a repo admin):
- Go to Settings > Branches in your GitHub repo
- Click Add branch protection rule
- Set Branch name pattern to
master - Enable:
- Require a pull request before merging
- Require status checks to pass before merging
- Add these required checks:
lint,test,build - Do not allow bypassing the above settings (optional, even for admins)
- Click Create
PyPI trusted publishing setup¶
The deploy workflow uses PyPI's trusted publishing — no API tokens to manage. One-time setup:
- Go to pypi.org and log in
- Navigate to your project save-gcp-local > Settings > Publishing
- Add a new GitHub publisher:
- Owner:
EshwarCVS - Repository:
save-gcp-local - Workflow name:
deploy.yml - Environment name:
pypi - In your GitHub repo, go to Settings > Environments
- Create an environment named
pypi(if it doesn't exist)
GitHub Pages setup (for documentation site)¶
- Go to Settings > Pages in your GitHub repo
- Under Source, select Deploy from a branch
- Set branch to
gh-pagesand folder to/ (root) - Click Save
- The docs site will be live at
https://eshwarcvs.github.io/save-gcp-local