Welcome to kwalitee’s documentation!

Contents:

Introduction

Kwalitee is a tool that runs static analysis checks on invenio and invenio-related repositories. It can be used as a web service using the Github API or as a git hook from the command line.

It aims at slowly, but steadily enforce good practices regarding commit message formatting, code layout (PEP8), documentation (PEP257) and help the integrators doing their job without having to worry about recurrent mistakes.

It relies on and thanks the following softwares and libraries:

Installation

Versions

We recommend you to use the stable version unless you want to contribute.

Stable version

kwalitee is on PyPI so all you need is:

$ pip install --user kwalitee

Development version

$ git clone https://github.com/jirikuncar/kwalitee
$ cd kwalitee
$ pip install --user -r requirements.txt

Installation of the command-line interface

Kwalitee can be used as a Command-line interface, which has some handy features like the githooks and the Messages checks.

By default the messages checks will try to use GitPython but we are recommending you to install and use pygit2. As, it has not stable version yet, the installation requires some work.

Ubuntu

$ sudo apt-add-repository ppa:dennis/python
$ sudo apt-get update
$ sudo apt-get install python-dev libffi-dev libgit2
$ pip install cffi pygit2

If you don’t find a suitable version using ppa:dennis/python, you can always install it manually via cmake.

OSX

The important detail here is to use the same version for libgit2 and pygit2. Homebrew is a way to get it working.

$ brew update
$ brew install libgit2 # currently 0.21.0 (2014-07-28)
$ pip install pygit2

Deployment of the web server

kwalitee is composed of a WSGI server and a worker to handle the long tasks asynchronously.

Requirements

  • A WSGI web server, we recommend nginx + uWSGI but anything may do. Apache + mod_wsgi is working as well.
  • A Redis server.

Configuration

There are not many things you have to configure on a fresh installation, here are the few you should be aware of.

ACCESS_TOKEN

Is the API token for your user on Github. You need it in order to be able to publish comments and statuses.

It can be defined per account as well. See: Command-line interface and kwalitee.models.Account.

AUTO_CREATE

Unless AUTO_CREATE is set to true, you’ll have to enable the repositories individually to authorize events from Github.

$ kwalitee repository add invenio/test
invenio/test is now allowed to webhook kwalitee!

WSGI application

The web application can be served using nginx + uWSGI or gunicorn.

Development server

Using Flask Script’s Server, you can run it without any external servers or libraries.

$ kwalitee runserver
uWSGI

This configuration file will serve the applicatino on port 8000.

; uwsgi.ini
[uwsgi]

http = 0.0.0.0:8000
master = true

processes = 4
die-on-term = true
vaccum = true
max-requests = 100

chdir = <VIRTUALENV>/opt/kwalitee
virtualenv = <VIRTUALENV>
module = kwalitee.wsgi:application
touch-reload = uwsgi.ini

enable-threads = true

And start it this way.

$ uwsgi --init uwsgi.ini

See more on uWSGI documentation.

nginx + uWSGI

TODO

Worker

A simple way to run the worker is the following. It works well for development and/or debug purposes. Consider relying on a deamon supervisor like: upstart, systemd, runit or supervisord.

$ python -m kwalitee.worker
Upstart (Ubuntu)

The worker can also be handled using upstart. Here is the configuration for it. VirtualEnv is a clean way to set everything up and is recommended.

# /etc/init/<myservice>.conf
description "Kwalitee RQ worker"

respawn
respawn limit 15 5
console log
setuid <USER>
setgid <GROUP>

exec /usr/bin/python -m kwalitee.worker
# Or if you've set it up in a virtualenv
#exec <VIRTUALENV>/bin/python -m kwalitee.worker

Then, you can manage it using upstart like anything else.

$ sudo start <myservice>
$ sudo stop <myservice>

Command-line interface

kwalitee comes with a command-line tool that goes by the name of kwalitee. If you’ve installed it using the --user option, you’ll have to add ~/.local/bin to your path. Otherwise, you should be able to call it without any trouble.

$ export PATH+=:~/.local/bin

Help

The command line tool is able to give you direct little help.

$ kwalitee --help

check

Utility to run various kwalitee checks in your repository.

Messages

message

Runs the checks on the existing commits.

$ kwalitee check message master..

githooks

This tool can install or uninstall some hooks into the current git repository.

Hooks

pre-commit

Runs the checks on the files about to be commited.

prepare-commit-msg

Based on the state of the commit create a commit message to be filled in.

post-commit

Verifies that the commit message passes the checks.

Installation

$ kwalitee install

Uninstallation

$ kwalitee uninstall

account

Utililty to manage to user account that have registred.

Listing

$ kwalitee account list

Creation and modification

Creation and modification are using the add command. You can alter the user’s email and its GitHub API token. Any user with a token will have the comments posted on his repository made using the token’s account instead of the default one.

$ kwalitee account add <ACCOUNT>

$ kwalitee account add <ACCOUNT> --email <EMAIL> --token <TOKEN>

Deletion

Deletion is permanent and it deletes everything belonging to the given account.

$ kwalitee account remove <ACCOUNT>

repository

Utility to manage to user’s repositories.

Listing

$ kwalitee repository list

Creation

$ kwalitee repository add <ACCOUNT>/<REPOSITORY>

Deletion

Deletion is permanent and it deletes everything belonging to the given repository.

$ kwalitee repository remove <ACCOUNT>/<REPOSITORY>

Testing

Running the tests are as simple as:

$ python setup.py test

The code coverage can be output by passing some arguments to py.test.

$ python setup.py test -a "tests --cov kwalitee --cov-config .coveragerc"
# html report
$ python setup.py test -a "tests --cov kwalitee --cov-report html"

Ditto for running only one test or debugging with pdb.

$ python setup.py test -a tests/tests_ping.py
$ python setup.py test -a tests/tests_ping.py::test_ping
$ python setup.py test -a "tests --pdb"

Writing tests

The tests are using PyHamcrest for its richness and the nice default output provided. To be consistent, avoid using unittest or bare assert.

Fixtures

Fixtures are provided by the very powerful py.test. Take a look at the fixtures defined in the conftest.py files.

Other tools

HTTPretty

HTTPretty is a HTTP client mock library which lets you define your own custom answers and status code as well as testing which calls have been made.

mock

mock is used to mock file opening (open()) and inspect the content that was written in it without having to create temporary files with tempfile.

Changelog

This file describes the set of features of each version as well as the incompatibilities.

Release 0.2.0: The next big thing®

This version uses a database (SQLite) for persistence.

  • Support for Docker. (Jiří)
  • Support for .kwalitee.yml configuration per repository. (Haris)
  • Cli for checking changed files kwalitee check files. (Jiří)
  • Cli for checking commit messages kwalitee check message. (Jiří)
  • Support of push events. (Yoan)
  • Support for multiple repositories. (Yoan)
  • Support for multiple users. (Yoan)
  • Alembic setup for upcoming migrations (Yoan)
  • New Sphinx documentation. (Yoan)
  • Fixes double commenting bug. (Yoan)

Incompatibilities

  • The commit statuses are still accessible but are not migrated to the database.
  • Previously created git hooks will have to be uninstalled and re-installed as the Flask application is not always created.

Release 0.1.0: The playground

Initial version. It supports pull request events on one repository and will perform checks on the commit message and files.

  • Commit message checks. (Jiří)
  • Git hooks. (Lars)
  • PEP8 checks. (Yoan)
  • PEP257 checks. (Yoan)
  • PyFlakes checks. (Yoan)
  • License checks. (Yoan)
  • Asynchronous checks using RQ. (Yoan)
  • New unit tests. (Yoan)
  • Auto labelling of the pull requests. (Yoan)
  • Skip work in progress (wip) pull requests. (Yoan)

API

kwalitee package

Subpackages

kwalitee.cli package
Submodules
kwalitee.cli.account module

Command-line tools for managing accounts.

kwalitee.cli.account.add(account, email=None, token=None)[source]

Add/modify an account.

kwalitee.cli.account.list()[source]

List all the repositories.

kwalitee.cli.account.remove(account)[source]

Remove an account (and its repositories).

kwalitee.cli.githooks module

Command-line tools for the git hooks.

kwalitee.cli.githooks.install(force=False)[source]

Install git hooks.

kwalitee.cli.githooks.uninstall()[source]

Uninstall git hooks.

kwalitee.cli.repository module

Command-line tools for managing repositories.

kwalitee.cli.repository.add(repository)[source]

Add a repository to the list of authorized ones.

kwalitee.cli.repository.list()[source]

List all the repositories.

kwalitee.cli.repository.remove(repository)[source]

Remove a repository from the list of authorized ones.

Module contents

Command line interfaces entrypoints.

kwalitee.cli.main()[source]

Running the manager.

Submodules

kwalitee.config module

kwalitee base configuration.

To change it, put a config.py into your instance.

kwalitee.config.CONTEXT

Context for Github.

kwalitee.config.COMPONENTS

List of supported components.

kwalitee.config.ACCESS_TOKEN

Github access token. Used to post statuses and comments. It MUST be set.

kwalitee.config.AUTO_CREATE

Allow anyone to add its repository by setting up the webhook on Github.

Default: False

kwalitee.config.CHECK_COMMIT_MESSAGES

Enable the commit message checks.

Default: True

kwalitee.config.CHECK_WIP

Enable the work-in-progress pull requests checks. Disabled by default.

Default: False

kwalitee.config.CHECK_LICENSE

Enable the license checks.

Default: True

kwalitee.config.CHECK_PEP8

Enable the PEP8 checks.

Default: True

kwalitee.config.CHECK_PEP257

Enable the PEP257 checks.

Default: True

kwalitee.config.CHECK_PYFLAKES

Enable the PyFlakes checks. PEP8 checks are required.

Default: True

kwalitee.config.IGNORE

Error codes to ignore.

Default: ['E123', 'E226', 'E24', 'E501', 'E265']

kwalitee.config.SELECT

Error codes to specially enable.

Default: []

kwalitee.config.WORKER_TIMEOUT

Background worker job time window.

Any job taking longer than that will be killed.

RQ default timeout is 180 seconds

kwalitee.config.MIN_REVIEWERS

Minimum number of reviewers for py:func:message check <.kwalitee.check_message>.

Default: 3

kwalitee.config.LABEL_WIP

Label to apply for a work-in-progress pull request.

Default: "in_work"

kwalitee.config.LABEL_REVIEW

Label to apply for a pull request that needs more reviewers.

Default: "in_review"

kwalitee.config.LABEL_READY

Label to apply for a pull request that passes all the checks.

Default: "in_integration"

kwalitee.config.ALT_SIGNATURES = ('Reported-by',)

Alternative signatures recognized but not counted as reviewers.

kwalitee.config.COMMIT_MSG_TEMPLATE = '{component}: description (max 50 chars, using nouns)\n\n* Detailed description formatted as a bullet list (using present tense).\n\nSigned-off-by: {author}\n{extra}'

Template used to generate the commit message from the git hook.

kwalitee.config.GITHUB = 'https://github.com/'

Github base URL.

kwalitee.config.GITHUB_REPO = 'https://github.com/{account}/{repository}/'

Github repository URL template.

kwalitee.config.HOOK_TEMPLATE = '#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport sys\nfrom kwalitee import create_app\nfrom kwalitee.hooks import {hook}\n\nif __name__ == "__main__":\n with create_app().app_context():\n sys.exit({hook}(sys.argv))\n'

Template used to generate the git hooks, customize at will.

kwalitee.config.PEP257_MATCH = '(?!test_).*\\.py'

Files checked for PEP257 conformance.

kwalitee.config.PEP257_MATCH_DIR = '[^\\.].*'

Directories checkes for PEP257 conformance.

kwalitee.config.SIGNATURES = ('Signed-off-by', 'Co-authored-by', 'Tested-by', 'Reviewed-by', 'Acked-by')

Authors and reviewers signatures.

kwalitee.config.TRUSTED_DEVELOPERS = []

Super developers who’s code never fail.

kwalitee.factory module

kwalitee factory for Flask application.

class kwalitee.factory.ShaConverter(map)[source]

Bases: werkzeug.routing.BaseConverter

Werkzeug routing converter for sha-1 (truncated or full).

regex = u'(?!/)(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{7})'
weight = 150
kwalitee.factory.create_app(name=None, config=None)[source]

Create the Flask application.

kwalitee.hooks module

Git hooks.

kwalitee.hooks.commit_msg_hook(argv)[source]

Hook: for checking commit message (prevent commit).

kwalitee.hooks.post_commit_hook(argv=None)[source]

Hook: for checking commit message.

kwalitee.hooks.pre_commit_hook(argv=None)[source]

Hook: checking the staged files.

kwalitee.hooks.prepare_commit_msg_hook(argv)[source]

Hook: prepare a commit message.

kwalitee.hooks.run(command, raw_output=False)[source]

Run a command using subprocess.

Parameters:
  • command (str) – command line to be run
  • raw_output (bool) – does not attempt to convert the output as unicode
Returns:

error code, output (stdout) and error (stderr)

Return type:

tuple

kwalitee.kwalitee module

Kwalitee checks for PEP8, PEP257, PyFlakes and License.

kwalitee.kwalitee.SUPPORTED_FILES = (u'.py', u'.html', u'.tpl', u'.js', u'.jsx', u'.css', u'.less')

Supported file types.

kwalitee.kwalitee.check_file(filename, **kwargs)[source]

Perform static analysis on the given file.

Parameters:filename (str) – path of file to check.
Returns:errors sorted by line number
Return type:list
kwalitee.kwalitee.check_license(filename, **kwargs)[source]

Perform a license check on the given file.

The license format should be commented using # and live at the top of the file. Also, the year should be the current one.

Parameters:
  • filename (str) – path of file to check.
  • year (int) – default current year
  • ignore (list) – codes to ignore, e.g. ('L100', 'L101')
  • python_style (bool) – False for JavaScript or CSS files
Returns:

errors

Return type:

list

kwalitee.kwalitee.check_message(message, **kwargs)[source]

Check the message format.

Rules:

  • the first line must start by a component name
  • and a short description (52 chars),
  • then bullet points are expected
  • and finally signatures.
Parameters:
  • components (list) – compontents, e.g. ('auth', 'utils', 'misc')
  • signatures (list) – signatures, e.g. ('Signed-off-by', 'Reviewed-by')
  • alt_signatures (list) – alternative signatures, e.g. ('Tested-by',)
  • trusted (list) – optional list of reviewers, e.g. ('john.doe@foo.org',)
  • max_length (int) – optional maximum line length (by default: 72)
  • max_first_line (int) – optional maximum first line length (by default: 50)
  • allow_empty (bool) – optional way to allow empty message (by default: False)
Returns:

errors sorted by line number

Return type:

list

kwalitee.kwalitee.check_pep257(filename, **kwargs)[source]

Perform static analysis on the given file docstrings.

Parameters:
  • filename (str) – path of file to check.
  • ignore (list) – codes to ignore, e.g. (‘D400’,)
  • match (str) – regex the filename has to match to be checked
  • match_dir (str) – regex everydir in path should match to be checked
Returns:

errors

Return type:

list

kwalitee.kwalitee.check_pep8(filename, **kwargs)[source]

Perform static analysis on the given file.

Parameters:
  • filename (str) – path of file to check.
  • ignore (list) – codes to ignore, e.g. ('E111', 'E123')
  • select (list) – codes to explicitly select.
  • pyflakes (bool) – run the pyflakes checks too (default True)
Returns:

errors

Return type:

list

See also

pep8.Checker

kwalitee.kwalitee.check_whitespaces(self, definition, docstring)[source]

D290: White spaces around doctring should be trimmed.

kwalitee.kwalitee.get_options(config)[source]

Build the options from the Flask config.

kwalitee.models module

Database models to persist the data over time.

class kwalitee.models.Account(name, email=None, token=None)[source]

Bases: flask_sqlalchemy.Model

Github account.

classmethod create(name, email=None, token=None)[source]

Create and commit and new account.

created_at

Date of creation.

email

Email.

classmethod find_or_create(name, email=None, token=None)[source]

Find or create an account.

id

Identifier

name

Username.

token

API Token.

classmethod update_or_create(name, email=None, token=None)[source]

Modify or create an account.

updated_at

Date of last modification.

class kwalitee.models.BranchStatus(commit, name, url, content=None)[source]

Bases: flask_sqlalchemy.Model

Status of a pull request.

commit
commit_id
content

Get the content of the status.

created_at
errors[source]

Get the number of errors found.

classmethod find_or_create(commit, name, url, content=None)[source]

Find or create a commit status.

get_content()[source]

Get the content of the status.

id
is_pending()[source]

Return True is the commit status hasn’t been checked yet.

name
set_content(value)[source]

Set the content of the status.

state[source]

Get the state.

updated_at
url
class kwalitee.models.CommitStatus(repository, sha, url, content=None)[source]

Bases: flask_sqlalchemy.Model

Status of a push.

content

Get the content of the status.

created_at
errors[source]

Get the number of errors found.

classmethod find_or_create(repository, sha, url)[source]

Find or create a commit status.

get_content()[source]

Get the content of the status.

id
is_pending()[source]

Return True is the commit status hasn’t been checked yet.

repository
repository_id
set_content(value)[source]

Set the content of the status.

sha
state[source]

Get the state.

updated_at
url
class kwalitee.models.Repository(owner, name)[source]

Bases: flask_sqlalchemy.Model

Github repository.

created_at
classmethod find_or_create(owner, name)[source]

Find or create a repository.

fullname[source]

Get the fullname of the repository.

id
name
owner
owner_id
updated_at
kwalitee.models.init_app(app)[source]

Initialize the Flask app with db.

kwalitee.tasks module

Tasks to run on the worker.

kwalitee.tasks.get_headers(repository, config)[source]

Get the HTTP headers for the GitHub api.

This is required to post comments on GitHub on your behalf. Please update your configuration accordingly.

ACCESS_TOKEN = "deadbeef..."

It can also be overwritten per user.

$ kwalitee account add username --token=deadbeef...
Returns:HTTP headers
Return type:dict
kwalitee.tasks.pull_request(branch_status_id, pull_request_url, status_url, config)[source]

Performing all the tests on the pull request.

Then pings back the given status_url and update the issue labels.

Parameters:
  • branch_status_id (int) – identifier of the branch status.
  • pull_request_url (str) – github api pull request
  • status_url (str) – github api status url
  • config (dict) – configuration dictionary
Returns:

status body and applied labels

Return type:

dict

kwalitee.tasks.push(commit_status_id, commit_url, status_url, config)[source]

Performing all the tests on the commit.

Parameters:
  • commit_status_id – identifier of the branch status
  • commit_url – github api commit url
  • status_url – github api status url
  • config – configuration dictionary

kwalitee.views module

Views like in MTV.

kwalitee.views.account(account)[source]

Display the repositories linked with one account.

Parameters:account – name of the account
kwalitee.views.branch(account, repository, branch)[source]

Display the statuses of a branch.

Parameters:
  • account – name of the owner
  • repository – name of the repository
  • branch – name of the branch
kwalitee.views.branch_status(account, repository, branch, sha)[source]

Display the status of a pull request.

Parameters:
  • account – name of the owner
  • repository – name of the repository
  • branch – name of the branch
  • sha – commit identifier of the commit related with the branch
kwalitee.views.commit(account, repository, sha)[source]

Display the status of a commit.

Parameters:
  • account – name of the owner
  • repository – name of the repository
  • sha – identifier of the commit
kwalitee.views.index()[source]

Homepage that lists the accounts.

kwalitee.views.payload()[source]

Handle the GitHub events.

See also

Event Types <https://developer.github.com/v3/activity/events/types/>

kwalitee.views.repository(account, repository, limit=50)[source]

Display the recents commits and branches of a repository.

Parameters:
  • account – name of the owner
  • repository – name of the repository
  • limit – size of the commit window
kwalitee.views.status(sha)[source]

Show the status of a commit.

deprecated static files aren’t used anymore. To be removed at some point.

Parameters:sha – identifier of a commit.

kwalitee.worker module

Initialize Redis and setups the RQ worker.

kwalitee.worker.init_app(app)[source]

Initialize the RQ queue.

kwalitee.wsgi module

WSGI application with debug middleware if in debug mode.

Module contents

kwalitee Flask application and git hooks.

kwalitee.create_app(name=None, config=None)

Create the Flask application.

Authors

kwalitee is developed to support developers of Invenio digital library software.

Contact us at info@invenio-software.org.

Contributors

Indices and tables