Development Workflow & CI/CD Guide
This document describes GraphForge’s development workflow, CI/CD pipeline, and best practices for contributors.
Table of Contents
Section titled “Table of Contents”- Development Setup
- Branch Strategy
- Pull Request Workflow
- CI/CD Pipeline
- Code Quality Tools
- GitHub Integrations
- Release Process
Development Setup
Section titled “Development Setup”Prerequisites
Section titled “Prerequisites”- Python 3.10 or higher
- uv package manager
- Git
- pre-commit (optional but recommended)
Initial Setup
Section titled “Initial Setup”# Clone the repositorygit clone https://github.com/CurateLabs/graphforge-legecy.gitcd graphforge
# Install uv (if not already installed)curl -LsSf https://astral.sh/uv/install.sh | sh
# Install dependenciesuv sync --all-extras
# Install pre-commit hooks (recommended)uv run pre-commit install
# Run tests to verify setupuv run pytestPre-commit Hooks
Section titled “Pre-commit Hooks”Pre-commit hooks run automatically before each commit to catch issues early:
# Install hooksuv run pre-commit install
# Run hooks manually on all filesuv run pre-commit run --all-files
# Run specific hookuv run pre-commit run ruff --all-files
# Update hook versionsuv run pre-commit autoupdateHooks configured:
- ruff: Code formatting and linting with auto-fix
- mypy: Type checking
- trailing-whitespace: Remove trailing whitespace
- end-of-file-fixer: Ensure files end with newline
- check-yaml/toml/json: Validate config files
- bandit: Security vulnerability scanning
- markdownlint: Markdown formatting
Branch Strategy
Section titled “Branch Strategy”GraphForge follows a Git Flow inspired branching strategy:
Branch Types
Section titled “Branch Types”| Branch | Purpose | Protected | Base | Merge Into |
|---|---|---|---|---|
main |
Production-ready code | ✅ Yes | - | - |
rust-core |
v0.5.0 Rust core staging | ✅ Yes | main |
main (after merge gates) |
develop |
Integration branch | ✅ Yes | main |
main |
feature/* |
New features | ❌ No | develop |
develop |
fix/* |
Bug fixes | ❌ No | develop |
develop |
hotfix/* |
Urgent production fixes | ❌ No | main |
main + develop |
docs/* |
Documentation updates | ❌ No | develop |
develop |
refactor/* |
Code refactoring | ❌ No | develop |
develop |
Branch Naming Conventions
Section titled “Branch Naming Conventions”# Featuresfeature/with-clause-implementationfeature/optional-match-support
# Bug fixesfix/integration-test-aliasingfix/null-handling-in-aggregation
# Hotfixeshotfix/security-vulnerability-cve-2026-1234
# Documentationdocs/update-api-referencedocs/add-performance-guide
# Refactoringrefactor/simplify-executor-logicrefactor/extract-pattern-matcherCreating a Feature Branch
Section titled “Creating a Feature Branch”# Update develop branchgit checkout developgit pull origin develop
# Create feature branchgit checkout -b feature/my-new-feature
# Make changes, commit, pushgit add .git commit -m "Add my new feature"git push -u origin feature/my-new-featureKeeping Branch Up-to-Date
Section titled “Keeping Branch Up-to-Date”# Rebase on develop to incorporate latest changesgit fetch origingit rebase origin/develop
# Or merge if you prefer (less clean history)git merge origin/developPull Request Workflow
Section titled “Pull Request Workflow”PR Best Practices
Section titled “PR Best Practices”Keep PRs Small and Focused
Section titled “Keep PRs Small and Focused”CI/CD tools work best with small, reviewable PRs.
Large PRs (1,000+ lines, 20+ files) are:
- ❌ Difficult for humans to review thoroughly
- ❌ Overwhelming for CI/CD tools (CodeRabbit, GitHub Actions)
- ❌ More likely to introduce bugs
- ❌ Slower to get merged
- ❌ Harder to debug if issues arise
Optimal PR size:
- ✅ 50-300 lines of code changed
- ✅ 1-5 files modified
- ✅ Single focused change (one feature, one bug fix)
- ✅ Reviewable in < 30 minutes
How to break down large changes:
# ❌ BAD: One massive PRfeature/add-with-clause (2,000 lines, 25 files) - Parser changes - AST nodes - Planner logic - Executor implementation - Integration tests - Documentation
# ✅ GOOD: Multiple focused PRsfeature/with-clause-parser (200 lines, 3 files) → PR merged
feature/with-clause-planner (180 lines, 2 files) → PR merged
feature/with-clause-executor (220 lines, 2 files) → PR merged
feature/with-clause-tests (150 lines, 2 files) → PR mergedTips for keeping PRs small:
- Use feature flags for incomplete features
- Submit infrastructure changes separately from features
- Refactor in one PR, add features in another
- Break features into vertical slices (parser → planner → executor)
Fix Problems Properly (No Bandaids)
Section titled “Fix Problems Properly (No Bandaids)”When you encounter an issue, fix the root cause.
❌ Bandaid fixes to avoid:
# Hiding errorstry: result = function()except: # Catch everything and hope pass
# Ignoring type issues without understandingvalue = get_value() # type: ignore
# Commenting out failing tests# def test_feature():# assert feature_works() # TODO: fix later
# Skipping CI checkspytest -k "not test_that_fails"✅ Proper fixes:
# Handle errors explicitlytry: result = process_data(input)except ValidationError as e: logger.error(f"Invalid input: {e}") return None # Explicit null case
# Fix type issues properlyvalue: str | None = get_value() # Proper type annotationif value is None: return default_value
# Fix failing testsdef test_feature(): # Fixed the underlying bug in feature() assert feature_works()
# All tests must passpytest # No skips, no ignoresWhen tempted to use a bandaid, ask:
- Why is this failing?
- What’s the root cause?
- How can I fix it properly?
- What tests will prevent regression?
Common scenarios:
| Issue | ❌ Bandaid | ✅ Proper Fix |
|---|---|---|
| Type error | Add # type: ignore |
Fix type annotations |
| Failing test | Comment out test | Fix the bug or update test |
| CI failure | Skip check temporarily | Fix the underlying issue |
| Import error | Wrap in try/except | Install missing dependency |
| Flaky test | Mark as @pytest.mark.skip |
Make test deterministic |
1. Create Pull Request
Section titled “1. Create Pull Request”- Push your branch to GitHub
- Navigate to repository and click “New Pull Request”
- Fill out the PR template (auto-populated)
- Add reviewers (CODEOWNERS auto-assigned)
- Link related issues using “Fixes #
” or “Relates to “
2. PR Template Sections
Section titled “2. PR Template Sections”When creating a PR, complete these sections:
- Description: Clear summary of changes
- Type of Change: Bug fix, feature, breaking change, etc.
- Related Issues: Link to issues this addresses
- Changes Made: Bullet list of specific changes
- Testing: What tests were added/modified
- Checklist: Code quality, testing, documentation items
3. Automated Checks
Section titled “3. Automated Checks”When you open a PR, these checks run automatically:
| Check | Purpose | Required |
|---|---|---|
| Test Suite | Run all tests on 3 OS × 4 Python versions | ✅ Yes |
| Lint | Ruff formatting and linting | ✅ Yes |
| Type Check | mypy type validation | ✅ Yes |
| Security | Bandit vulnerability scanning | ✅ Yes |
| Coverage | Code coverage report (85% threshold) | ⚠️ Warning |
| CodeRabbit | AI-powered code review | ℹ️ Advisory |
4. Code Review Process
Section titled “4. Code Review Process”- Automated Review: CodeRabbit provides initial feedback
- Self-Review: Review your own changes first
- Peer Review: CODEOWNERS review and approve
- Address Feedback: Make requested changes
- Re-request Review: After making changes
5. Merging
Section titled “5. Merging”Requirements before merging:
- ✅ All CI checks pass (no exceptions)
- ✅ At least 1 approval from CODEOWNERS
- ✅ No unresolved conversations
- ✅ Branch is up-to-date with base branch
- ✅ No merge conflicts
- ✅ No bandaid fixes (all issues properly resolved)
- ✅ PR is reasonably sized (< 500 lines preferred)
- ✅ All tests passing (no skipped or commented tests)
- ✅ No temporary workarounds or TODOs introduced
Merge strategies:
- Squash and merge (preferred): Clean history, single commit per PR
- Rebase and merge: Preserve commits, linear history
- Merge commit: Keep full branch history (avoid for simple PRs)
# After PR approval, merge via GitHub UI or:git checkout developgit merge --squash feature/my-featuregit commit -m "Add my feature (#<issue-number>)"git push origin developCI/CD Pipeline
Section titled “CI/CD Pipeline”GitHub Actions Workflows
Section titled “GitHub Actions Workflows”1. Test Suite (test.yml)
Section titled “1. Test Suite (test.yml)”Runs on every push to main/develop and all PRs to main.
Jobs:
test (12 configurations: 3 OS × 4 Python versions)
# Runs unit tests with coverage# Runs integration tests# Uploads coverage to Codecov (Ubuntu 3.12 only)lint (Ubuntu, Python 3.12)
# ruff format --check .# ruff check .type-check (Ubuntu, Python 3.12)
# mypy src/graphforge --strict-optionalsecurity (Ubuntu, Python 3.12)
# bandit -c pyproject.toml -r src/coverage (Ubuntu, Python 3.12)
# pytest --cov=src --cov-report=html# Uploads HTML coverage report as artifact# Soft fail if coverage < 85%Local equivalent:
# Run full test suite locallyuv run pytest -m "not slow"
# Run with coverageuv run pytest --cov=src --cov-report=term --cov-report=html
# Lintuv run ruff format --check .uv run ruff check .
# Type checkuv run mypy src/graphforge
# Security scanuv run bandit -c pyproject.toml -r src/2. Publish (publish.yaml)
Section titled “2. Publish (publish.yaml)”Triggered on GitHub release publication.
# Builds package: uv build# Publishes to PyPI: uv publish (uses trusted publishing)Status Badges
Section titled “Status Badges”Add to README.md:
Code Quality Tools
Section titled “Code Quality Tools”Ruff (Linting & Formatting)
Section titled “Ruff (Linting & Formatting)”Configuration: pyproject.toml → [tool.ruff]
# Format codeuv run ruff format .
# Check formattinguv run ruff format --check .
# Lint with auto-fixuv run ruff check --fix .
# Lint without changesuv run ruff check .Rules enabled:
- E/W (pycodestyle)
- F (Pyflakes)
- I (isort)
- N (pep8-naming)
- UP (pyupgrade)
- B (flake8-bugbear)
- C4 (comprehensions)
- SIM (simplify)
- RET (return)
- ARG (unused-arguments)
- PTH (use-pathlib)
- PL (Pylint)
- PERF (performance)
- RUF (ruff-specific)
mypy (Type Checking)
Section titled “mypy (Type Checking)”Configuration: pyproject.toml → [tool.mypy]
# Type check entire codebaseuv run mypy src/graphforge
# Type check with verbose outputuv run mypy src/graphforge --show-error-codes --pretty
# Type check tests (looser rules)uv run mypy tests/Settings:
python_version = "3.10"check_untyped_defs = truestrict_equality = true- Gradually enabling strict mode
Bandit (Security Scanning)
Section titled “Bandit (Security Scanning)”Configuration: pyproject.toml → [tool.bandit]
# Run security scanuv run bandit -c pyproject.toml -r src/
# Generate detailed reportuv run bandit -c pyproject.toml -r src/ -f json -o bandit-report.jsonConfigured to skip:
- B101 (assert_used) in tests and internal validation
pytest (Testing)
Section titled “pytest (Testing)”Configuration: pyproject.toml → [tool.pytest.ini_options]
# Run all testsuv run pytest
# Run specific test typesuv run pytest -m unituv run pytest -m integrationuv run pytest -m tck
# Run with coverageuv run pytest --cov=src --cov-report=term --cov-report=html
# Run in paralleluv run pytest -n auto
# Run with verbose outputuv run pytest -v --tb=long --showlocalsTest markers:
unit: Fast, isolated unit testsintegration: Integration tests (may use I/O)tck: openCypher TCK compliance testsproperty: Property-based tests (hypothesis)slow: Tests taking >1s
GitHub Integrations
Section titled “GitHub Integrations”CodeRabbit AI Code Review
Section titled “CodeRabbit AI Code Review”Setup:
- Install CodeRabbit app from GitHub Marketplace
- Authorize for the CurateLabs/graphforge-legecy repository
- Configuration is in
.coderabbit.yaml
Features:
- Automatic reviews on all PRs
- Inline suggestions with explanations
- Security checks for common vulnerabilities
- Best practices enforcement
- openCypher compliance validation
Usage:
CodeRabbit automatically comments on PRs with:
- Code quality issues
- Potential bugs
- Performance concerns
- Security vulnerabilities
- Best practice violations
Commands in PR comments:
@coderabbitai review@coderabbitai help@coderabbitai explain [file:line]Configuration highlights:
- Profile:
chill(balanced feedback) - Focus: openCypher correctness, type safety, performance
- Python style: PEP 8, Google docstrings
- Thresholds: Max complexity 15, min coverage 85%
Dependabot (Dependency Updates)
Section titled “Dependabot (Dependency Updates)”Setup:
Dependabot is configured in .github/dependabot.yml and runs automatically.
Features:
- Weekly updates for Python dependencies
- Weekly updates for GitHub Actions
- Grouped updates (production vs dev dependencies)
- Auto-assignment to the maintainer
Managing Dependabot PRs:
# Dependabot PRs are labeled "dependencies"# Review changes in PR# Merge if tests pass
# To ignore a specific version:@dependabot ignore this major version@dependabot ignore this minor version@dependabot ignore this dependencyCodecov (Coverage Tracking)
Section titled “Codecov (Coverage Tracking)”Setup:
- Sign up at codecov.io
- Connect GitHub repository
- Token is auto-configured in Actions
Features:
- Coverage trends over time
- PR comments with coverage diff
- Badge for README
- Threshold enforcement (85%)
Viewing reports:
- View on codecov.io dashboard
- Download HTML report from Actions artifacts
- Local:
uv run pytest --cov=src --cov-report=html && open htmlcov/index.html
Branch Protection Rules
Section titled “Branch Protection Rules”Configuring Branch Protection
Section titled “Configuring Branch Protection”For main branch:
- Go to Settings → Branches → Add rule
- Branch name pattern:
main - Enable these settings:
Require pull request reviews:
- ✅ Require pull request before merging
- ✅ Require 1 approval
- ✅ Dismiss stale reviews when new commits pushed
- ✅ Require review from Code Owners
Require status checks:
- ✅ Require status checks to pass before merging
- ✅ Require branches to be up to date
- Required checks:
Test Python 3.10 on ubuntu-latestTest Python 3.12 on ubuntu-latestLint and Format CheckType Checking (mypy)Security Scanning
Additional settings:
- ✅ Require conversation resolution before merging
- ✅ Require signed commits (optional)
- ✅ Include administrators (enforce rules for admins)
- ✅ Restrict who can push (only maintainers)
- ❌ Allow force pushes (disabled)
- ❌ Allow deletions (disabled)
For develop branch:
Same as main but:
- Require 1 approval (can be more lenient)
- Required checks: Ubuntu tests only (faster feedback)
Bypassing Protection (Emergency)
Section titled “Bypassing Protection (Emergency)”In rare emergencies, admins can:
- Temporarily disable branch protection
- Make critical fix
- Re-enable protection immediately
Document all bypasses in commit message and notify team.
Release Process
Section titled “Release Process”Versioning Strategy
Section titled “Versioning Strategy”GraphForge follows Semantic Versioning:
MAJOR.MINOR.PATCH- MAJOR: Breaking changes (e.g., 1.0.0 → 2.0.0)
- MINOR: New features, backward compatible (e.g., 0.1.0 → 0.2.0)
- PATCH: Bug fixes, backward compatible (e.g., 0.1.1 → 0.1.2)
Release Checklist
Section titled “Release Checklist”-
Update Version
Terminal window # Update version in pyproject.tomlversion = "0.2.0" -
Update CHANGELOG.md
## [0.2.0] - 2026-02-15### Added- WITH clause for query chaining- Variable-length path support### Fixed- Integration test column aliasing### Changed- Improved error messages -
Commit and Tag
Terminal window git add pyproject.toml CHANGELOG.mdgit commit -m "chore: bump version to 0.2.0"git tag -a v0.2.0 -m "Release version 0.2.0"git push origin develop --tags -
Merge to Main
Terminal window # Create PR from develop to maingit checkout maingit merge developgit push origin main -
Create GitHub Release
- Go to Releases → Draft a new release
- Tag:
v0.2.0 - Title:
GraphForge v0.2.0 - Description: Copy from CHANGELOG.md
- Click “Publish release”
-
Automated Publish
- GitHub Action automatically builds and publishes to PyPI
- Monitor Actions tab for completion
-
Verify Release
Terminal window # Check PyPIpip install --upgrade graphforgepython -c "import graphforge; print(graphforge.__version__)"
Hotfix Process
Section titled “Hotfix Process”For critical bugs in production:
# Create hotfix branch from maingit checkout maingit checkout -b hotfix/critical-bug-fix
# Make fix, test thoroughly# ...
# Merge to maingit checkout maingit merge hotfix/critical-bug-fixgit tag -a v0.1.2 -m "Hotfix: Critical bug"git push origin main --tags
# Also merge to developgit checkout developgit merge hotfix/critical-bug-fixgit push origin develop
# Create GitHub release (triggers publish)Best Practices Summary
Section titled “Best Practices Summary”Before Committing
Section titled “Before Committing”- Run
uv run pytest(all tests pass) - Run
uv run ruff format.(code formatted) - Run
uv run ruff check.(no lint errors) - Run
uv run mypy src/graphforge(type checks pass) - Update tests for new features
- Update documentation if needed
- Write clear commit messages
Commit Message Format
Section titled “Commit Message Format”Follow Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>Types:
feat: New featurefix: Bug fixdocs: Documentation onlystyle: Formatting, no code changerefactor: Code restructuringtest: Adding testschore: Maintenance
Examples:
feat(executor): implement WITH clause for query chaining
Add support for WITH clause enabling multi-part queries.Includes projection, filtering, sorting, and pagination.
Fixes #<issue-number>fix(executor): correct column aliasing in RETURN projection
Fixed bug where RETURN aliases were ignored, causingintegration test failures.
Fixes #<issue-number>PR Best Practices
Section titled “PR Best Practices”- Small PRs: Keep PRs focused (< 500 lines changed)
- Clear titles: Use conventional commit format
- Complete template: Fill out all PR template sections
- Link issues: Use “Fixes #
” in description - Self-review: Review your own code first
- Responsive: Address review comments promptly
- Clean commits: Squash fixup commits before merging
Code Review Guidelines
Section titled “Code Review Guidelines”As a reviewer:
- ✅ Check correctness and logic
- ✅ Verify tests cover changes
- ✅ Look for security issues
- ✅ Ensure documentation updated
- ✅ Check performance implications
- ✅ Be constructive and kind
As an author:
- ✅ Accept feedback graciously
- ✅ Explain decisions clearly
- ✅ Ask questions if unclear
- ✅ Iterate until approved
- ✅ Thank reviewers
Troubleshooting
Section titled “Troubleshooting”Pre-commit Hooks Failing
Section titled “Pre-commit Hooks Failing”# Skip hooks temporarily (not recommended)git commit --no-verify
# Fix specific hook failureuv run pre-commit run <hook-name> --all-files
# Update hooks to latest versionsuv run pre-commit autoupdateCI Checks Failing
Section titled “CI Checks Failing”# Reproduce CI failures locallyuv run pytest -m "unit and integration"uv run ruff check .uv run mypy src/graphforgeuv run bandit -c pyproject.toml -r src/
# Check specific OS/Python version (use Docker)docker run -it python:3.10 bashMerge Conflicts
Section titled “Merge Conflicts”# Update branch with latest developgit fetch origingit rebase origin/develop
# Resolve conflicts# Edit conflicted filesgit add <resolved-files>git rebase --continueDependabot Issues
Section titled “Dependabot Issues”# Close unwanted Dependabot PR@dependabot ignore this dependency
# Rebase Dependabot PR@dependabot rebaseResources
Section titled “Resources”- Contributing Guide: CONTRIBUTING.md (repository root)
- Security Policy:.github/SECURITY.md (repository root)
- Issue Templates:.github/ISSUE_TEMPLATE/ (repository root)
- CI/CD Workflows:.github/workflows/ (repository root)
- Pre-commit Config:.pre-commit-config.yaml (repository root)
- CodeRabbit Config:.coderabbit.yaml (repository root)
Last Updated: January 31, 2026
For questions about the development workflow, open a discussion or create an issue.