This document contains detailed guidelines for contributing to the DevOps Demo project. It covers the development process, code standards, testing, code review process, and best practices for maintaining high code quality.
- Getting Started
- Linting and Testing
- Backend Linting
- Frontend Linting
- Infrastructure Linting
- Pre-commit Setup
- Code Style
- Testing
- CI/CD
- Reference
Install all necessary tools and set up the development environment. Detailed instructions are available in Local setup.
Minimum requirements:
- Python 3.12
- Node.js >= 20
- Docker and Docker Compose
- Make (recommended)
- Git
After setting up the environment, you can start making changes to the code. Make sure you understand the project structure and follow established code standards.
Main directories:
backend/app/- Backend code (FastAPI)frontend/src/- Frontend code (React)backend/tests/- Backend testsfrontend/src/*.test.jsx- Frontend testsobservability/- Observability stack configuration
Commit messages should follow the Conventional Commits style.
Format: <type>(<scope>): <subject>
Examples:
fix(backend): resolve database connection pool issuefeat(frontend): add dark mode toggledocs: update local setup instructionstest(backend): add integration tests for items APIrefactor(api): simplify error handling logicchore: update dependencies
Most important types:
fix:- Bug fixes (SemVer patch)feat:- New features (SemVer minor)feat!:,fix!:,refactor!:- Breaking changes (SemVer major)docs:- Documentation changestest:- Adding or changing testsrefactor:- Code refactoring without changing functionalitychore:- Maintenance tasks (dependency updates, configuration)
Scope (optional):
backend- Changes in backend codefrontend- Changes in frontend codeapi- Changes in API endpointsdb- Changes in migrations or database modelsinfra- Changes in infrastructure
After making changes and committing, create a Pull Request with a detailed description of changes. Make sure all tests pass and code meets quality standards.
Project maintainer will review your Pull Request and leave comments if needed. It's better to add additional commits instead of amending and force-pushing, as this complicates tracking changes during review.
Commits will be squashed into one commit when merging.
All code quality checks are performed automatically via [pre-commit] hooks and can be run manually via Make commands.
# Run all linting checks
make lint
# Run all tests
make test
# Format code
make format
# Run pre-commit hooks manually
make pre-commit-runIt's recommended to run these commands before each commit to avoid failed CI/CD checks.
Python code is checked via [ruff] for linting and [mypy] for type checking.
Linting check:
# Check code for errors
cd backend
.venv/bin/ruff check .
# Automatically fix possible errors
.venv/bin/ruff check . --fix
# Check only specific file
.venv/bin/ruff check app/main.pyCode formatting:
# Format code
cd backend
.venv/bin/ruff format .
# Check formatting without changes
.venv/bin/ruff format --check .Via Make:
make lint-backend # Linting check
make format-backend # Code formattingRuff configuration:
- Configuration is located in
backend/.ruff.toml - Ruff automatically ignores
.venv/,__pycache__/, andalembic/versions/directories - Maximum line length: 160 characters
- Use double quotes for strings
Type checking:
cd backend
.venv/bin/mypy appVia Make:
make type-checkMypy configuration:
- Configuration is located in
backend/pyproject.tomlin[tool.mypy]section - Mypy checks only code in
app/directory - Strict mode is used for better type checking
Common errors and solutions:
Missing type annotation- Add type hints to functions and variablesIncompatible types- Check argument and return value typesUnused "type: ignore" comment- Remove unnecessary ignore comments
Frontend code is checked via [ESLint] for linting and [Prettier] for formatting.
Linting check:
cd frontend
npm run lint
# Automatically fix possible errors
npm run lint:fixVia Make:
make lint-frontendESLint configuration:
- Configuration is located in
frontend/eslint.config.js - Recommended rules for React are used
- Additional rules for better code quality
Code formatting:
cd frontend
npm run format
# Check formatting without changes
npm run format:checkVia Make:
make format-frontendPrettier configuration:
- Configuration is located in
frontend/.prettierrc.json - Prettier is integrated with ESLint via
eslint-config-prettier
Infrastructure files (YAML, Dockerfiles, GitHub Actions workflows) are checked via [yamllint] and [hadolint].
# Check all infrastructure files
make lint-infraThis command checks:
- YAML files (docker-compose, observability configs)
- GitHub Actions workflows (
.github/workflows/*.yml) - Dependabot configuration (
.github/dependabot.yml) - Docker Compose validation
- Dockerfiles via hadolint
Individual checks:
YAML linting:
# Install yamllint if not already installed
pip install yamllint
# Check specific file
yamllint -c .yamllint.yml docker-compose.ymlDocker Compose validation:
# Check docker-compose.yml syntax
docker compose config --quietDockerfile linting:
# Install hadolint if not already installed
# macOS: brew install hadolint
# Linux: https://github.com/hadolint/hadolint#install
# Check Dockerfile
hadolint --config .hadolint.yaml backend/DockerfilePre-commit hooks automatically run linting and formatting checks before each Git commit.
# Install pre-commit hooks
make pre-commit-installOr manually:
cd backend
.venv/bin/pip install pre-commit
.venv/bin/pre-commit install# Run on all files
make pre-commit-run
# Or manually
cd backend
.venv/bin/pre-commit run --all-filesBackend:
ruff- Python linting and automatic fixingruff-format- Python code formattingmypy- Type checkingbandit- Security linting (security check)detect-secrets- Secret detection in code
Frontend:
eslint- JavaScript/React lintingprettier- Code formatting
Infrastructure:
yamllint- YAML lintinghadolint- Dockerfile lintingdocker-compose-validate- Docker Compose validationmakefile-check- Makefile syntax check
General:
trailing-whitespace- Remove trailing whitespace at end of linesend-of-file-fixer- Add newline at end of filescheck-yaml- YAML syntax validationcheck-json- JSON syntax validationcheck-toml- TOML syntax validation
# Update hooks to latest versions
make pre-commit-update
# Or manually
cd backend
.venv/bin/pre-commit autoupdateMain principles:
- Follow PEP 8 style guide
- Use type hints where possible
- Maximum line length: 160 characters (configured in ruff)
- Use double quotes for strings
- Follow naming conventions (snake_case for functions and variables, PascalCase for classes)
Examples:
# Good
def get_user_by_id(user_id: int) -> User | None:
"""Get user by ID."""
return db.query(User).filter(User.id == user_id).first()
# Bad
def getUser(id):
return db.query(User).filter(User.id==id).first()Type hints:
# Required type hints for functions
async def create_item(item_data: ItemCreate, db: AsyncSession) -> Item:
"""Create new item."""
db_item = Item(**item_data.model_dump())
db.add(db_item)
await db.commit()
await db.refresh(db_item)
return db_itemDocstrings:
def complex_function(param1: str, param2: int) -> bool:
"""
Short function description.
Detailed description of what the function does and what parameters it takes.
Args:
param1: Parameter 1 description
param2: Parameter 2 description
Returns:
Return value description
Raises:
ValueError: When parameters are invalid
"""
passMain principles:
- Follow ESLint recommended rules
- Use functional components with hooks
- Prefer named exports
- Use Prettier for formatting
- Follow naming conventions (camelCase for functions and variables, PascalCase for components)
Examples:
// Good
import { useState, useEffect } from 'react';
export function ItemList() {
const [items, setItems] = useState([]);
useEffect(() => {
fetchItems().then(setItems);
}, []);
return <div>{/* ... */}</div>;
}
// Bad
import React from 'react';
export default class ItemList extends React.Component {
// ...
}Hooks:
// Use hooks instead of class components
function MyComponent() {
const [state, setState] = useState(initialValue);
useEffect(() => {
// Side effects
return () => {
// Cleanup
};
}, [dependencies]);
const handleClick = useCallback(() => {
// Event handler
}, [dependencies]);
return <div onClick={handleClick}>Content</div>;
}Main principles:
- Use 2 spaces for indentation
- Follow yamllint configuration
- Use quotes for values containing special characters
- Add comments to explain complex configurations
Examples:
# Good
services:
api:
image: python:3.12
environment:
- DATABASE_URL=postgresql://localhost/db
ports:
- "8000:8000"
# Bad
services:
api:
image:python:3.12
environment:-DATABASE_URL=postgresql://localhost/dbBackend tests:
- Place tests in
backend/tests/directory - Use pytest fixtures for test environment setup
- Tests should be independent and not depend on execution order
- Use descriptive test names
- Tests should clean up after themselves
Frontend tests:
- Place tests next to components (
.test.jsxfiles) - Use React Testing Library for component testing
- Test behavior, not implementation
- Use user-event for simulating user interaction
Examples:
Backend:
async def test_create_item(db: AsyncSession):
"""Test creating new item."""
item_data = ItemCreate(name="Test Item")
item = await create_item(item_data, db)
assert item.id is not None
assert item.name == "Test Item"Frontend:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { App } from './App';
test('creates new item', async () => {
render(<App />);
const input = screen.getByLabelText(/item name/i);
await userEvent.type(input, 'New Item');
const button = screen.getByRole('button', { name: /create/i });
await userEvent.click(button);
expect(screen.getByText('New Item')).toBeInTheDocument();
});- All new features should include tests
- Tests should be independent and not depend on execution order
- Use descriptive test names
- Tests should clean up after themselves (don't leave "garbage" in database)
- Code coverage should be sufficient for critical functionality
Detailed information about running tests is available in Running tests.
All Pull Requests are automatically checked via GitHub Actions:
Backend checks:
- Linting (ruff, mypy)
- Testing (pytest)
Frontend checks:
- Linting (ESLint)
- Testing (Vitest)
Infrastructure checks:
- YAML validation (yamllint)
- Docker Compose validation
- Dockerfile linting (hadolint)
Make sure all CI checks pass before requesting review.
- pre-commit - Pre-commit hooks configuration
- ruff - Ruff configuration
- mypy - Mypy configuration
- ESLint - ESLint configuration
- Prettier - Prettier configuration
- yamllint - yamllint configuration
- hadolint - hadolint configuration
- Conventional Commits - Conventional Commits specification
- pre-commit - pre-commit documentation
- Ruff - Ruff documentation
- Mypy - Mypy documentation
- ESLint - ESLint documentation
- Prettier - Prettier documentation
- yamllint - yamllint documentation
- hadolint - hadolint documentation
- Local setup - Local environment setup
- Running tests - Running tests
- Prerequisites - Required knowledge and skills