4.4 KiB
4.4 KiB
Contributing to Fester
Thanks for your interest in improving Fester! This document covers the basics.
🚀 Quick Start for Contributors
# 1. Fork + clone
git clone https://git.dcos.net/dcosnet/fester.git
cd fester
# 2. Bootstrap dev environment (creates venv, installs deps + dev tools)
./bootstrap.sh --dev
# 3. Run the backend in dev mode (auto-reload on changes)
./run.sh --dev
# 4. Run tests (when we have them)
pytest
# 5. Lint + format
ruff check .
ruff format .
🏗️ Architecture Overview
Read README.md first — it has the full architecture diagram and project layout.
The key insight: Fester has a strict separation between:
- EventBus — the singleton message bus (all events flow through it)
- Subscribers — bus listeners that index/journal/broadcast events (TimelineStore, cause_graph, FailurePropagator, the WS broadcaster)
- Routers — FastAPI APIRouters under
backend/api/that expose REST endpoints - UI — vanilla HTML/JS pages under
ui/that subscribe to the WS stream and call REST endpoints
When you add a new feature, ask:
- Does this emit events? → Use
bus.emit(EventType.X, ...)frombackend/events/schema.py - Does this need persistence? → Add a method to
backend/storage/sqlite_db.py:Storage - Does this need a UI? → Add a page under
ui/and a nav entry inui/app.js:Fester.mountShell() - Does this need a CLI command? → Add a subcommand to
cli/fester.py
📝 Coding Standards
Python
- Python 3.12+ — use modern syntax (match statements, type hints, etc.)
- Type hints — add them to new code; don't worry about retrofitting old code
- Imports — use
from backend.X.Y import Z(not barefrom X.Y import Z) - EventBus — always emit events via
bus.emit(), never mutate state directly from a request handler - Pydantic — use
BaseModelfor request bodies in routers - Async — use
async deffor endpoints that touch the DB or do I/O
JavaScript (UI)
- Vanilla JS — no frameworks (React, Vue, etc.). Keep it dependency-free.
- Shared shell — every page calls
Fester.mountShell('page-id')to get the topbar + WS connection - API calls — use
Fester.api(path, opts)(returns parsed JSON) - Toasts — use
Fester.toast(msg, kind)for user notifications - No build step — pages load directly via
<script src="/ui/app.js">
CSS
- Design tokens — use
var(--token)(defined instyle.css). Don't hardcode colors. - Dark theme only — no light mode. Tokens are already dark.
🧪 Testing
# Run all tests
pytest
# Run a specific test file
pytest tests/test_pipeline.py
# Run with coverage
pytest --cov=backend --cov-report=html
# Run only fast tests
pytest -m "not slow"
Tests live in tests/ (we don't have many yet — contributions welcome!).
🔍 Code Quality
# Lint
ruff check .
# Format
ruff format .
# Type check
mypy backend/
# Check for syntax errors in inline <script> blocks
node scripts/check_syntax.js ui/*.html index.html
📦 Commit Conventions
Use Conventional Commits:
feat: add tmux output viewer to sessions page
fix: pass real cwd to execute_action instead of empty dict
docs: add quickstart guide
chore: update dependencies
refactor: split BuildRunner from PipelineEngine
test: add tests for failure_propagation
🐛 Bug Reports
When filing an issue, include:
- Fester version (
fester healthoutput) - Python version (
python3 --version) - OS + distro
- Steps to reproduce
- Expected vs actual behavior
- Relevant log output (
/tmp/fester_backend.log) - Screenshots if UI-related
✨ Pull Requests
- Fork the repo + create a branch:
git checkout -b feat/my-feature - Make your changes
- Run
ruff check . && ruff format .before committing - Write a clear commit message (Conventional Commits)
- Open a PR with:
- What changed + why
- Screenshots (if UI changes)
- Test results
- Any breaking changes
🆘 Getting Help
- Read CHEATSHEET.md for the operator survival guide
- Read quickstart.md for getting started
- Browse the API docs at runtime
- Check existing issues: https://git.dcos.net/dcosnet/fester/issues
📜 License
By contributing, you agree that your contributions will be licensed under the AGPL-3.0 — see LICENSE.