Shotgun uses GitHub Actions for continuous integration and continuous deployment. This document explains the automated workflows and checks.
GitHub Actions automatically run on:
- Pull requests to main branch
- Pushes to main branch
- Tags for releases
When you open a pull request, the following checks run automatically:
- Ruff Linting - Checks Python code for style and potential bugs
- Ruff Format - Verifies code is properly formatted
- Mypy - Static type checking for type safety
- Pytest - Runs full test suite
- Coverage - Ensures 70%+ code coverage (excluding cli/tui directories)
- Trufflehog - Scans for secrets and credentials
- Actionlint - Validates GitHub Actions workflow files
- Conventional Commits - Ensures PR title follows conventional commit format
Tests run on:
- Python 3.11 (minimum supported version)
- Python 3.13 (recommended version)
Tests run on:
- Ubuntu Latest (Linux)
- macOS Latest (macOS)
- Windows Latest (Windows)
Before a PR can be merged, all of these must pass:
- ✅ All tests passing
- ✅ Code coverage ≥ 70%
- ✅ Linting passes (ruff)
- ✅ Formatting correct (ruff format)
- ✅ Type checking passes (mypy)
- ✅ No secrets detected (trufflehog)
- ✅ Conventional commit title format
- ✅ All GitHub Actions workflows valid
Runs on pull requests:
- Installs dependencies with
uv - Runs all code quality checks
- Executes test suite with coverage
- Validates commit messages
- Scans for secrets
Runs on version tags (e.g., v0.1.0):
- Builds Python package
- Publishes to PyPI
- Creates GitHub release
- Builds and pushes Docker image
Runs on main branch pushes and tags:
- Builds Docker image
- Pushes to GitHub Container Registry
- Tags with version and
latest
Runs daily to verify installation methods work:
- Tests
uvx shotgun-sh@latestinstallation - Tests
uv tool install shotgun-sh - Ensures package is installable from PyPI
Runs when new issues are created:
- Auto-assigns issues to configured user (via
AUTO_ASSIGN_TO_USERsecret) - Sends Slack notification with issue details
Before pushing, run all checks locally:
# Run pre-commit hooks (includes most checks)
uv run lefthook run pre-commit
# Run tests with coverage
uv run pytest --cov=src --cov-report=term-missing --cov-report=html
# Verify coverage meets threshold
uv run pytest --cov=src --cov-fail-under=70# Linting
uv run ruff check .
# Formatting
uv run ruff format --check .
# Type checking
uv run mypy src/
# Run tests
uv run pytest
# Coverage report
uv run pytest --cov=src --cov-report=html
open htmlcov/index.html
# Secret scanning
trufflehog git file://. --since-commit HEAD --exclude-globs=uv.lock
# Validate workflows
actionlint .github/workflows/*.ymlPRs must maintain 70% code coverage or higher.
The following directories are excluded from coverage requirements:
src/shotgun/cli/- Command-line interfacesrc/shotgun/tui/- Terminal user interface
These are excluded because:
- UI code is difficult to test programmatically
- They are thin wrappers around core functionality
- Core functionality (which has tests) is what matters
After running tests with coverage:
# Terminal report
uv run pytest --cov=src --cov-report=term-missing
# HTML report
uv run pytest --cov=src --cov-report=html
open htmlcov/index.htmlThe HTML report shows:
- Overall coverage percentage
- File-by-file breakdown
- Line-by-line highlighting
- Missing coverage areas
Automated on version tags:
-
Create and push a version tag:
git tag v0.1.0 git push origin v0.1.0
-
GitHub Actions automatically:
- Builds the package with
hatch - Embeds telemetry keys at build time
- Publishes to PyPI
- Creates GitHub release
- Builds the package with
Automated on main branch pushes and tags:
-
On push to main:
- Builds Docker image
- Tags as
:dev - Pushes to ghcr.io
-
On version tag:
- Builds Docker image
- Tags as
:latestand:v0.1.0 - Pushes to ghcr.io
The following secrets must be configured in GitHub repository settings:
PYPI_API_TOKEN- For PyPI publishingSHOTGUN_LOGFIRE_TOKEN- Logfire logging (embedded at build time)POSTHOG_API_KEY- PostHog analytics and exception tracking (embedded at build time)POSTHOG_PROJECT_ID- PostHog project ID (embedded at build time)SHOTGUN_ALPHA_WEBHOOK- Slack webhook URL for notifications (deployments, issues, test failures)AUTO_ASSIGN_TO_USER- GitHub username to auto-assign new issues to (optional)
Telemetry secrets are embedded at build time via Hatch build hooks:
- Only included in production builds (PyPI, Docker)
- Not present in source code
- Read from environment variables during build
- Cannot be changed after build
If ruff check fails:
# Auto-fix issues
uv run ruff check --fix .
# Check remaining issues
uv run ruff check .If ruff format fails:
# Auto-format code
uv run ruff format .If mypy fails:
# Run mypy locally
uv run mypy src/
# Check specific file
uv run mypy src/shotgun/specific_file.pyAdd type hints or use # type: ignore comments for legitimate issues.
If pytest fails:
# Run tests locally
uv run pytest
# Run specific test
uv run pytest test/unit/test_specific.py
# Run with verbose output
uv run pytest -v
# Show stdout/stderr
uv run pytest -sIf coverage is below 70%:
# Generate coverage report
uv run pytest --cov=src --cov-report=html
# Open report to see missing coverage
open htmlcov/index.html
# Add tests for uncovered codeIf trufflehog detects a secret:
- Verify it's a real secret (not a false positive)
- Remove the secret from the code
- Rotate the secret if it was committed
- Use environment variables for secrets
- Never commit credentials to the repository
If it's a false positive, update .trufflehog-exclude.txt or hook configuration.
If commit message validation fails:
PR title must follow conventional commits format:
# Valid formats
feat: add new feature
fix: resolve bug
docs: update documentation
refactor: restructure code
test: add tests
ci: update workflows
chore: update dependencies
# With scope
feat(auth): add OAuth support
fix(api): handle null valuesSome workflows can be triggered manually:
# Trigger workflow from GitHub UI
# 1. Go to Actions tab
# 2. Select workflow
# 3. Click "Run workflow"
# 4. Choose branch and parametersGitHub Actions caches:
- Python dependencies (via uv)
- pytest cache
- mypy cache
- ruff cache
This speeds up subsequent runs significantly.
Tests run in parallel across:
- Different Python versions
- Different operating systems
- Different test suites
This provides fast feedback while ensuring compatibility.
If you encounter CI/CD issues:
- Check workflow logs in GitHub Actions tab
- Review error messages carefully
- Test locally first with same commands
- Ask in Discord community
- Open an issue if it's a CI/CD bug