Skip to main content
Contributions to QFieldCloud are welcome! This guide covers the process for submitting changes.

Before You Start

1. Communicate Your Ideas

Before investing time in a PR, discuss your proposal with the QFieldCloud team:
  1. Create an issue: Open a GitHub issue detailing your suggestion
  2. Wait for feedback: The development team will review and provide guidance
  3. Clarify details: Engage in discussion to refine the approach
Not every idea will be accepted. Discussing first saves you time and effort on PRs that wouldn’t be merged.

2. Check Existing Issues

Search for existing issues or discussions related to your idea:

Development Workflow

1. Fork and Clone

Fork the repository and clone with submodules:
git clone --recurse-submodules [email protected]:YOUR_USERNAME/QFieldCloud.git
cd QFieldCloud

2. Create a Branch

Create a feature branch from master:
git checkout master
git pull origin master
git checkout -b feature/my-feature-name
Branch naming conventions:
  • feature/description - New features
  • fix/description - Bug fixes
  • refactor/description - Code refactoring
  • docs/description - Documentation changes
  • test/description - Test improvements

3. Make Changes

Develop your changes following the code style guidelines.

4. Commit Changes

Write clear, concise commit messages:
git add .
git commit -m "Add support for custom QGIS project thumbnails"
Commit message guidelines:
  • Use imperative mood (“Add” not “Added”)
  • First line: concise summary (50 chars or less)
  • Reference issue numbers: “Fix #123: Handle null project descriptions”
  • Explain why, not just what

5. Push and Create PR

Push your branch and create a pull request:
git push origin feature/my-feature-name
Then go to GitHub and click “Create Pull Request”.

Pull Request Guidelines

PR Title and Description

Title: Clear and descriptive
Add custom thumbnail support for QGIS projects
Description: Include:
  • Summary: What does this PR do?
  • Issue reference: Closes #123 or Related to #456
  • Changes: List of main changes
  • Screenshots: Before/after (for UI changes)
  • Testing: How to test the changes
Example:
## Summary
Adds support for custom project thumbnails uploaded by users.

## Changes
- Add `thumbnail` field to Project model
- Create API endpoint for thumbnail upload
- Add thumbnail display in project list

## Screenshots
[Before]
[After]

## Testing
1. Create a project
2. Upload a thumbnail via `/api/v1/projects/{id}/thumbnail`
3. Verify thumbnail appears in project list

Closes #123

PR Checklist

Before submitting:
  • Branch is based on latest master
  • Code follows code style guidelines
  • Tests are included for new features/fixes
  • All tests pass locally
  • Documentation is updated (if applicable)
  • Commit messages are clear and descriptive
  • PR description is complete
  • No merge conflicts

Draft PRs

If your PR is not ready for review, mark it as a draft PR. Draft PRs should:
  • Be checkable without breaking the stack
  • Have the specific feature testable (even if incomplete)

PR Review Process

  1. Automated checks: CI runs tests and linters
  2. Code review: Team members review your code
  3. Feedback: Address review comments
  4. Approval: Once approved, your PR will be merged

Code Style

QFieldCloud uses automated tools to enforce code style.

Pre-commit Hooks

Install pre-commit hooks to automatically check code before commits:
pip install pre-commit
pre-commit install
Now hooks run automatically on git commit.

Pre-commit Configuration

See .pre-commit-config.yaml for the full configuration. Key hooks:

1. Ruff (Linting and Formatting)

Ruff is used for both linting and formatting Python code:
- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: v0.13.0
  hooks:
    # Linter
    - id: ruff
      args: [ --fix ]
    # Formatter
    - id: ruff-format
Run manually:
# Lint and auto-fix
pre-commit run ruff --all-files

# Format code
pre-commit run ruff-format --all-files

2. Flake8 (Additional Linting)

- repo: https://github.com/pycqa/flake8
  rev: '7.3.0'
  hooks:
    - id: flake8
      additional_dependencies: [flake8-clean-block, flake8-if-expr]

3. mypy (Type Checking)

Static type checking with mypy:
- repo: https://github.com/pre-commit/mirrors-mypy
  rev: v1.18.1
  hooks:
    - id: mypy
      additional_dependencies: [types-*, django-stubs, ...]
Run manually:
mypy -p docker-app -p docker-qgis

4. django-upgrade

Automatically upgrades Django code to 4.2 standards:
- repo: https://github.com/adamchainz/django-upgrade
  rev: '1.28.0'
  hooks:
    - id: django-upgrade
      args: [--target-version, '4.2']

5. Standard Hooks

Basic code quality checks:
  • check-ast: Validate Python syntax
  • check-yaml: Validate YAML files
  • check-json: Validate JSON files
  • check-merge-conflict: Detect merge conflicts
  • end-of-file-fixer: Ensure files end with newline
  • trailing-whitespace: Remove trailing whitespace
  • mixed-line-ending: Enforce LF line endings

Run All Pre-commit Hooks

Manually run all hooks:
pre-commit run --all-files

Code Style Guidelines

Python

  • PEP 8: Follow Python style guide
  • Line length: 88 characters (Black default, used by Ruff)
  • Imports: Group into stdlib, third-party, and local
  • Docstrings: Use for public methods and classes
  • Type hints: Add where beneficial
Example:
from typing import Optional

from django.db import models
from rest_framework import serializers

from qfieldcloud.core.models import Project


class ProjectSerializer(serializers.ModelSerializer):
    """Serializer for Project model."""

    owner_username: str = serializers.CharField(source="owner.username", read_only=True)

    class Meta:
        model = Project
        fields = ["id", "name", "description", "owner_username"]

    def validate_name(self, value: str) -> str:
        """Validate project name."""
        if len(value) < 3:
            raise serializers.ValidationError("Name must be at least 3 characters")
        return value

Django

  • Use Django 4.2 features (enforced by django-upgrade)
  • Avoid deprecated patterns
  • Use ORM instead of raw SQL where possible
  • Follow Django naming conventions

Templates

  • Use Django template language best practices
  • Escape user input (auto-escape is on)
  • Keep logic minimal in templates

Testing Requirements

Write Tests

All new features and bug fixes should include tests. Example test:
from django.test import TestCase
from qfieldcloud.core.models import Project, User

class ProjectThumbnailTestCase(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(username="test")
        self.project = Project.objects.create(name="Test", owner=self.user)

    def test_upload_thumbnail(self):
        """Test uploading a project thumbnail."""
        # Test implementation
        pass

Run Tests

Ensure all tests pass before submitting:
docker compose run app python manage.py test --keepdb

Check Coverage

Maintain or improve test coverage:
docker compose exec app coverage run manage.py test --keepdb
docker compose exec app coverage report

Documentation

Update Documentation

If your changes affect:
  • API: Update API documentation or docstrings
  • Setup: Update README.md or setup docs
  • Features: Update user-facing documentation

Docstrings

Use clear docstrings for public APIs:
def upload_thumbnail(project_id: int, thumbnail_file) -> bool:
    """
    Upload a custom thumbnail for a project.

    Args:
        project_id: ID of the project
        thumbnail_file: Image file object

    Returns:
        True if upload successful, False otherwise

    Raises:
        Project.DoesNotExist: If project not found
        ValidationError: If file is invalid
    """
    # Implementation

Branching Strategy

Main Branches

  • master: Main development branch
  • Feature branches: Created from master

Branch Protection

master is protected:
  • Cannot push directly
  • PRs required
  • CI checks must pass
  • Code review required

Merge Strategy

PRs are typically merged using:
  • Squash and merge: For feature branches (clean history)
  • Merge commit: For important multi-commit PRs

Common Scenarios

Updating Your Branch

Keep your branch up-to-date with master:
git checkout master
git pull origin master
git checkout feature/my-feature
git rebase master
If there are conflicts, resolve them and continue:
git rebase --continue

Fixing Failed CI

If CI fails:
  1. Check the error in the GitHub Actions logs
  2. Fix the issue locally
  3. Commit and push:
git add .
git commit -m "Fix linting errors"
git push origin feature/my-feature

Addressing Review Comments

  1. Make the requested changes
  2. Commit with a clear message
  3. Push to update the PR
  4. Reply to comments to notify reviewers

Resources

Getting Help

  • GitHub Issues: For bugs and feature requests
  • Pull Requests: For code review questions
  • Email: [email protected] for funding features

Thank You!

Your contributions make QFieldCloud better for everyone. Thank you for taking the time to contribute!

Build docs developers (and LLMs) love