2. Contribution Guide

First, make sure you’ve read the Getting Started guide – this contribution guide assumes you have Git properly setup and the repository cloned.

2.1. Repository Guidelines

Git’s entire goal is to keep a working record of all changes to the code. Developers should strive to keep this record clean and easy to understand.

1. Commit messages should be descriptive and contain both a title and body unless the content of the commit is very minimal. Avoid using $ git commit -m. Instead, use $ git commit to write a succinct and detailed message. For example,

Fix export CLI --csv bug

The bug was caused because in Python 3.x, filter() and map() return
iterators (well, filter/map objects that are essentially iterators)
instead of the evaluated list.

2. Follow the Git Branching Workflow. The master branch is reserved for production-ready code; any code ready to be tested should be merged into dev branch. dev is pushed to the staging server and master is pushed to the production server, as necessary. Any features, bug fixes, or other work should be done separately in an appropriately named branch. These branches are generally prefixed with dev (such as dev/api-refactor).

3. Try to commit small changes frequently. For example, do not have “batch” commits where you introduce multiple new features or bug fixes at once. Each commit should be focused on a specific feature, bug fix, or concept. You should never use $ git commit -a; review all files being added to ensure that each commit is coherent.

4. Do not force push ($ git push -f or $ git push --force) to any upstream branch.

5. Do not add derived/generated files (i.e. compilation results, be those from JSX, SCSS, or any other language) to the repository. In general, only commit source code; anything that results from a build tool should not be committed. However, certain auto-generated files (such as Django’s migrations) should be committed if they are considered source.

2.1.1. Status Checks

Status checks must pass before merging into a protected branch (i.e. master). To do so, you can only push master after pushing your current branch (and waiting for status checks to pass). In addition, you should never commit to master directly, as GitHub will reject those commits.

For example, this is the expected workflow:

$ git checkout -b dev-docs     # checkout new branch for development
$ emacs quizzera/settings.py   # edit files
$ git diff                     # review changges
$ git add quizzera/settings.py # decide on files to commit
$ git commit                   # commit with proper title and description
$ git push origin dev-docs     # push current branch first, wait for status
                               # checks to pass on GitHub
$ git checkout master          # merge with master and then push
$ git merge dev-docs
$ git push
note:It is vital that you do not commit to master directly. If you do, a push to master will be rejected and you will need to reset your master branch to the prior commit.

2.2. Style Guidelines

In general, follow the style of the file you are working on. This should be (and remain) consistent across all files of the project.

In particular, every function and class should document its parameters and expected types, return value and type, and any errors or warnings raised. Example usage for non-intuitive functions are also useful.

Furthermore, each file should contain a header with the file name, project, authors, creation date, and description:

# cli/tests/test_admin.py
# Quizzera
# Author: Rushy Panchal
# Date: December 29th, 2016
# Description: Test admin CLI.

For Python code, follow PEP8 as much as possible.

note:Quizzera deviates from PEP8 at times. For example, tabs are generally used over spaces.

2.3. Project Standards

Quizzera maintains a high standard for code quality. It is a project that is meticulously engineered to be easily used, maintained, and deployed. As such, these considerations should always be in mind when working on the project. While there is a lot of literature on software engineering, which should be read, here are a few principles we strive to maintain:

  1. Always document code. This primarily includes documenting assumptions made and requirements of specific modules. In particular, classes and functions, should have adequate headers (often within docstrings).
  2. Structure code for readability and maintainability. Split apart features and functionality into the smallest composable blocks, and then compose those together as needed. This aids both in testing and in understanding what the code itself does.
  3. Properly test every line of code. While this may be difficult to do and often requires more time than the original implementation itself, it will be incredibly rewarding. Tests allow us to measure proper functionality across long periods of time and ensure for stability. Small changes can have drastic effects which can be caught when the tests are run as opposed to when a user runs into a bug.
  4. Maintain invariants. Invariants are assumptions that should never change. As such, it is important to maintain these and to never deviate from them.