filabel - rule-based labeling of GitHub pull requests

Indices and tables

What’s it for?

filabel updates labels of a GitHub pull request based on files that have been changed in the PR.

Labels are assigned and removed based on labeling rules. Each rule is a mapping from label name to a list of filename patterns (in fnmatch.fnmatch() format).

filabel can operate in one of these modes: CLI tool and Webhook server. Also you can embed filabel functionality into your own application.

Installation

You can install filabel using pip:

pip install -i https://test.pypi.org/simple/ filabel-kroilvia

Main filabel routine

Main filabel routine loads the list of changed files for a particular pull request. Sets of matched and mismatched labels are calculated, basing on the provided label rules and this list.

Then matched labels that are not currently present in the PR are added. Optionally, labels that are currently present in the PR but have been mismatched are removed.

filabel as CLI tool

filabel can be invoked from a terminal. It requires a list of repositories, label configuration and GitHub credentials configuration. For each pull request in these repositories, the main filabel routine is performed. Additionally, pull requests can be filtered by open state and base branch.

Example

Basic invocation example:

python3 -m filabel -a auth.cfg -l label.cfg metopa/filabel_test

This would invoke filabel CLI with auth data in auth.cfg file and label description in label.cfg file and perform filabel routine for the github.com/metopa/filabel_test repository.

More advanced example:

python3 -m filabel -a auth.cfg -l label.cfg -b master -s open -d \
    metopa/filabel_test1 metopa/filabel_test2

This would process all open PRs (-s open) against master branch (-b master) in github.com/metopa/filabel_test1 and github.com/metopa/filabel_test2.

Configuration

filabel requires 2 configuration files for its operation. These files are defined using .ini syntax.

Auth configuration

Auth configuration is required to contain [github] section, that defines token key. Example:

[github]
token = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

Label configuration

Label configuration is required to contain [labels] section, where each entry defines a label and its corresponding rules.

The following example defines 3 labels (frontend, backend and docs) and wildcard patterns for them:

[labels]
frontend=
   */templates/*
   static/*
backend=logic/*
docs=
   *.md
   *.rst
   *.adoc
   LICENSE
   docs/*

GitHub OAuth token

OAuth token must be provided in order to access GitHub API. Information on how to obtain one: https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/

Important

Treat your tokens like passwords and keep them secret. Don’t expose your configuration files to a third-party. Don’t accidentally upload them online.

filabel as Webhook server

The second filabel mode is webhook server.

It is Flask application. When launched as a server with a public IP address, it can be set up for a repository as a GitHub webhook target. These webhooks can be used to trigger filabel routine automatically.

Example

This sequence of commands launches filabel as a web server:

export FILABEL_CONFIG="`pwd`/auth.cfg:`pwd`/label.cfg"
export FLASK_APP=filabel
python3 -m flask run

Configuration

Configuration of this mode slightly differs from the previous one.

Configuration file should also contain a secret field - arbitrary string that will be later pasted into a GitHub webhook configuration.

Example:

[github]
token = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
secret = HRQt4EQTud

The configuration files are passed to the server as an environment variable FILABEL_CONFIG. Multiple values are delimited with : or ;.

Example:

export FILABEL_CONFIG="`pwd`/auth.cfg:`pwd`/label.cfg"

The application is launched using Flask module. It searches the web application using FLASK_APP environment variable. You should set it to filabel:

export FLASK_APP=filabel

GitHub Webhook

Every GitHub repository has the option to post an HTTP request to a web server whenever an pull request changes its state.

Steps to setup new webhook:

  1. Sign in, then select the related repository you own.
  2. Click on “Settings” on the right panel.
  3. Then click on “Webhooks & Services” on the left panel.
  4. Click on the “Add WebHook” Button.
  5. Type the URL of your filabel server in the URL form field.
  6. Paste the application secret from the configuration file into Secret form field.
  7. Select “application/json” as the content type.
  8. Select “Let me select individual events” and check “Pull requests”.
  9. Leave the “Active” checkbox checked.
  10. Click on “Add webhook” to save the webhook.

filabel as library

You can embed filabel in your own application. You can use it to achieve this functionality:

  • GitHub API interaction
  • Manual PR labeling
  • Automatic PR labeling

GitHub API Wrapper

filabel provides a GitHubAPI wrapper over these API function:

  • Get information about currently logged-in user
  • Get a list of pull request in a repository
  • Get information about a pull request

This following code prints out the username of the currently logged-in user. Note, that token must be a valid GitHub token as defined in GitHub OAuth token.

from filabel.github_api import GitHubAPI

gh = GitHubAPI(token)  # GitHub OAuth token
user = gh.user_get_info()

# This prints the name of the currently logged-in user
print('current user: {}'.format(user["login"]))

# This prints URL to the Pull Request #2
pr = gh.repo_get_pr("metopa/filabel-testrepo1", 2)
print(pr["html_url"])
current user: ...
https://github.com/metopa/filabel-testrepo1/pull/2

Manual PR labeling

GitHubAPI can be used in order to add or remove PR labels:

from filabel.github_api import GitHubAPI

gh = GitHubAPI(token)  # GitHub OAuth token
pr = gh.repo_get_pr("metopa/filabel-testrepo1", 2)

# This adds 2 labels to the pull request
gh.pr_add_labels(pr, ["custom1", "custom2"])

# This undoes the previous operation
gh.pr_remove_labels(pr, ["custom1", "custom2"])

Automatic PR labeling

You can execute Main filabel routine directly from your code by invoking filabel.core.process_pull_request():

from filabel.github_api import GitHubAPI
from filabel.core import process_pull_request

gh = GitHubAPI(token)  # GitHub OAuth token
pr = gh.repo_get_pr("metopa/filabel-testrepo1", 2)

patterns = {'file': ['file*'],
            'file9': ['file9'],
            'web': ['*.html', '*.css']}

r = process_pull_request(gh, pr, patterns, False)
print(r)

The following output means that 2 of 3 labels have been added basing on the patterns:

[('file', '+'), ('file9', '+')]