The repocribro’s documentation

Welcome in the repocribro documentation. Continue by choosing the desired topic from the list of contents. You can also visit the repository repocribro@GitHub.

Contents

Introduction

repocribro logo

repocribro is Python powered web application allowing users to register their GitHub repositories so they can be managed, searched, browsed, tested, etc. (depends on used extensions) within the app. Main idea is to provide simple but powerful modular tool for building groups of GitHub repositories which are developed by different users and organizations with some common goal.

Cribro means sieve in Italian language (origins in Latin word cribrum). This project provides tool for intelligent sifting repositories, information about them and its contents.

This project has been created as final semester work for subject MI-PYT, CTU in Prague (more in Credits).

Project is open-source (under MIT license) published @GitHub. Basically you just need to always include the copyright and permission notice with name of author. But it would be great if you let us know that you are using repocribro in any way!!!

Installation

Installation options

This application can be installed via standard setuptools, for more information read Python docs - Installing Python Module. Check the Requirements before installation.

PyPi

You can use pip tool to install the package repocribro from PyPi:

$ pip install repocribro
setup.py

Or download the repository from GitHub and run:

$ python3 setup.py install
Check installation

After the successful installation you should be able to run:

$ repocribro --version
repocribro v0.1
Become an admin

After first start you should login into web app via GitHub and then you can use assign-role command to become an admin.

$ repocribro assign-role --login MarekSuchanek --role admin
Loaded extensions: core
Role admin not in DB... adding
Role admin added to MarekSuchanek

Database

In order to create and maintain the database, you can use migrations by Flask-Migrate:

$ repocribro db --help

Or you can use standard SQLAlchemy procedure db.create_all() via:

$ repocribro create-db

Both will try to create tables into database specified in the Configuration.

Configuration

You can see example configuration files at:

  • config/app.example.cfg

  • config/auth.example.cfg

  • config/db.example.cfg

    !!! If you are going to publish your configuration somewhere make sure, that it does not contain any secret information like passwords or API tokens!

Syntax of configuration files is standard INI, parsed by ConfigParser. Names of variables are case insensitive. Configuration can be in separate configuration files but if there are same variables within same sections there will overriding depending on the order of files.

Default config file can be also specified with environment variable:

$ export REPOCRIBRO_CONFIG_FILE='/path/to/config.cfg'
$ python
Python 3.5.2 (default, Oct 14 2016, 12:54:53)
[GCC 6.2.1 20160916 (Red Hat 6.2.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from repocribro.app import app
>>> app.run()
Application

You can specify any of the Flask (or extensions) configuration variables that is supposed to be placed to app.config. Just use same name (it can be also lowercase). These configurations must be done in [flask] section. Mandatory attribute is SECRET_KEY used for the session signing, this key is of course private.

For example:

[flask]
# something is wrong, I want to debug
DEBUG = true
# random secret key (use os.urandom())
SECRET_KEY = VeryPseudoRandomSuchSecret
Database

Next you need to specify configuration of your database. Flask extension Flask-SQLAlchemy is used so again configuration needs to be done within section [flask].

For example:

[flask]
# SQLite is enough, just testing
SQLALCHEMY_DATABASE_URI = sqlite:////tmp/test.db
GitHub

For communication with GitHub OAuth you are going to need Client ID and Client secret. Also for working with webhooks secret key must be set-up so every incoming message can be verified. Specify those in [github] section of config.

For example:

[github]
# Client ID & secret is obtained by creating OAuth app
CLIENT_ID = myAppClientIdFromGitHub
CLIENT_SECRET = myAppClientSecretFromGitHub
# Webhook secret for signing should be randomly generated
WEBHOOKS_SECRET = someRandomSecretKeyForWebhooks

Requirements

Usage

Usage basics

First you need to have prepared config file(s) with at least minimal mandatory configuration and repocribro successfully installed(see Installation and Configuration).

$ repocribro --config <config_file> [command] [command options]
$ repocribro -c <config_file> [command] [command options]
$ repocribro -c <config_file_1> -c <config_file_2> [command] [command options]

For all commands you can specify configuration file(s) of repocribro app, order of arguments matters only if you are overriding same configuration variable in those files. If no config files are specified those from default path will be used.

Commands

After supplying configuration files you can use various commands. Full list of commands with details are described within CLI commands.

For starting the web application (server) use:

$ repocribro runserver
Common options

You can also use standard -?, --help and --version:

$ repocribro --help
usage: repocribro [-c CFG_FILES] [-v] [-?] {runserver,db,shell,repocheck} ...

positional arguments:
  {runserver,db,shell,repocheck}
    runserver           Runs the Flask development server i.e. app.run()
    db                  Perform database migrations
    shell               Runs a Python shell inside Flask application context.
    repocheck           Perform check procedure of repository events

optional arguments:
  -c CFG_FILES, --config CFG_FILES
  -v, --version         show program's version number and exit
  -?, --help            show this help message and exit

$ repocribro --version
repocribro v0.0

CLI commands

There are various command for the app management some are provided by Flask extensions, some by repocribro. You can use option --help to get more information.

assign-role

Main purpose for this command is to set the initial admin of the app without touching DB directly. Others can be then set within administration zone of web interface.

$ repocribro assign-role --login MarekSuchanek --role admin
Loaded extensions: core
Role admin not in DB... adding
Role admin added to MarekSuchanek

$ repocribro assign-role --login MarekSuchanek --role admin
Loaded extensions: core
User MarekSuchanek already has role admin

For more information:

$ repocribro assign-role --help
db (database)

Command supplied by Flask-Migrate extension provides tool to work with database migrations (init, migrate, downgrade, upgrade, etc.).

For more information:

$ repocribro db --help
repocheck

Not implemented yet!

This command will provide simple checking of one or all repositories if there are some uncaught events within specified time. Main idea is to get the missed events (from webhooks) due to app outage.

runserver

Runs the web application (app.run()), but also some settings can be overriden like hostname, port, debugging, ...

For more information:

$ repocribro runserver --help
shell

Runs the Python shell inside the Flask app context. That can be useful for some debugging by hand.

For more information:

$ repocribro shell --help

Web application

Public usage

Anonymous (unauthenticated) used can browse public content of the web application which includes:

  • landing with basic info
  • search
  • user/organization profiles
  • public repositories with their releases and updates
Authentication

User can authenticate via GitHub OAuth with scope:

  • repo = read and manage user repositories (with private)
  • user = read user information (with private)
  • admin:webhook = add/remove webhooks
User management

Every activate (not banned) user can manage which of his/her repositories should be listed within application as:

  • public = everyone can see them
  • hidden = only people with secret URL can see them
  • private = only owner or administrator can see them

Information about user account can be synchronized as well as the repository information. When activating the repository webhook is added. Because webhook can be deleted at GitHub by hand, user can recreate the webhook again (he can’t do it by hand because doesn’t know the webhooks secret).

Administration

Managing user accounts, roles and repositories (not owned) can be done in administration zone. Same principles as in user management zone.

REST API

There is also REST API (only GET) for all GitHub entities, but it will be reworked soon (because the repo privacy & compatibility issues).

The actual is done by Flask-Restless with collections:

  • user
  • org
  • repo
  • push
  • commit
  • release

Credits

This project was created as final semester work for the awesome subject MI-PYT (Advanced Python) taught at the Faculty of Information Technology, Czech Technical University in Prague (FIT CTU) by @hroncok and @encukou.

Thanks goes to the Python community, to developers, contributors and other people around projects that are used within repocribro:

Also many thanks to GitHub, Travis CI, coveralls.io, readthedocs.org, requires.io and PyPi for being here for all of us.

Testing

This project uses the most fabulous testing tools for Python:

Run tests

Run tests simply by:

python setup.py test

or (if you have installed dependencies):

python -m pytest [options]
pytest [options]

You can also see the tests logs at Travis CI.

Betamax cassettes

Betamax cassettes are stored in tests/fixtures/cassettes directory. If you are not connected to theInternet, GitHub API is not working and/or you don’t want to create own GitHub token you will use (replay) them in order to test API client.

If you want to run your own cassettes, you need to setup system variable GITHUB_TOKEN which will contain the GitHub personal token (must have privileges to create/delete webhooks). You also must change variables within tests/test_github.py specifying some of your existing repository and also non-existing repository. Token can be created at:

Your test command then might look like:

$ GITHUB_TOKEN=<YOUR_TOKEN> python setup.py test

or use export and unset:

$ export GITHUB_TOKEN=<YOUR_TOKEN>
$ python setup.py test
...
$ unset GITHUB_TOKEN

For more information, enjoy reading Betamax documentation.

Writing extensions

Hooks for extension

Extension hooks
Name Description Return type
get_gh_event_processors Get GitHub events processors dict of str: list of function
get_gh_webhook_processors Get GitHub webhook processors dict of str: list of function
init_business Init business layer of the extension None
init_blueprints Init Flask blueprints (register them) None
init_container Put whatever you need into DI container of the app None
init_filters Init Jinja2 filters for views (register them) None
init_models Init models (data) layer of the extension array
introduce Introduce yourself (just name) for the list of extensions str
view_admin_extensions Return view object of extension for the admin list ExtensionView
view_admin_index_tabs Add/edit tabs for admin index page dict of str:ViewTab
view_core_search_tabs Add/edit tabs for search results page dict of str:ViewTab
view_core_user_detail_tabs Add/edit tabs for public user page dict of str:ViewTab
view_core_org_detail_tabs Add/edit tabs for public organization page dict of str:ViewTab
view_core_repo_detail_tabs Add/edit tabs for repository detail page dict of str:ViewTab
view_manage_dashboard_tabs Add/edit tabs for user management zone dashboard dict of str: `ViewTab

You can write your own repocribro extension. It’s very simple, all you need is extend the Extension class from repocribro.extending, make function returning instance of this class and direct entrypoint in the group [repocribro.ext] on that function. Extending is done via implementing actions on Hooks for extension which can return something.

While writing new plugin use please the same model, so even your extension is also easily extensible. Big part of core repocribro is extension itself see the module repocribro.ext_core.

my_ext.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 from repocribro.extending import Extension


 class MyNewExtension(Extension):
    ...


 def make_my_new_extension():
    ...
    return MyNewExtension()

setup.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
 from setuptools import setup

 ...
 setup(
     ...
     entry_points={
         'repocribro.ext': [
             'repocribro-my_ext = my_ext:make_my_new_extension'
         ]
     },
     ...
 )
 ...

API

repocribro consists of following package(s) and it’s modules:

repocribro.api

repocribro.api.create_api(app, db)

Create REST API (with GET) for resources in DB

Parameters:
  • app (flask.Flask) – Actual web application
  • db – Actual database with stored resources
Returns:

API manager extension

Return type:

flask_restless.APIManager

Todo:

Implement own or go into bigger detail (privacy, usernames, etc.)

repocribro.commands

AssignRoleCommand
class repocribro.commands.AssignRoleCommand(func=None)

Bases: flask_script.commands.Command

Assign desired role to desired user

option_list = (<flask_script.commands.Option object at 0x7fc37790ff28>, <flask_script.commands.Option object at 0x7fc37790ff60>)

CLI command options for assign-role

run(login, role_name)

Run the assign-role command with given options in order to assign role to user

Parameters:
  • login (str) – Login name of desired user
  • role_name (str) – Name of desired role
Raises:

SystemExit – If user does not exists or already had the role

DbCreateCommand
class repocribro.commands.DbCreateCommand(func=None)

Bases: flask_script.commands.Command

Perform procedure create all tables

run()

Run the db-create command to create all tables and constraints

RepocheckCommand
class repocribro.commands.RepocheckCommand(func=None)

Bases: flask_script.commands.Command

Perform check procedure of repository events

_do_check(repo)

Perform single repository check for new events

Parameters:repo (repocribro.models.Repository) – Repository to be checked
Todo:Handle pagination of GitHub events
Raises:SystemExit – if GitHub API request fails
_process_event(repo, event)

Process potentially new event for repository

Parameters:
  • repo (repocribro.models.Repository) – Repository related to event
  • event (dict) – GitHub event data
Returns:

If the event was new or already registered before

Return type:

bool

event2webhook = {'ReleaseEvent': 'release', 'PushEvent': 'push', 'RepositoryEvent': 'repository'}
option_list = (<flask_script.commands.Option object at 0x7fc3779122b0>,)

CLI command options for repocheck

run(full_name=None)

Run the repocheck command to check repo(s) new events

Obviously this procedure can check events only on public repositories. If name of repository is not specified, then procedure will be called on all registered public repositories in DB.

Parameters:full_name (str) – Name of repository to be checked (if None -> all)
Raises:SystemExit – If repository with given full_name does not exist

repocribro.controllers

repocribro.controllers.admin
repocribro.controllers.admin.account_ban(login)

Ban (make inactive) account (POST handler)

repocribro.controllers.admin.account_delete(login)

Delete account (POST handler)

repocribro.controllers.admin.account_detail(login)

Account administration (GET handler)

repocribro.controllers.admin.admin = <flask.blueprints.Blueprint object>

Admin controller blueprint

repocribro.controllers.admin.index()

Administration zone dashboard (GET handler)

repocribro.controllers.admin.repo_delete(login, reponame)

Delete repository (POST handler)

repocribro.controllers.admin.repo_detail(login, reponame)

Repository administration (GET handler)

repocribro.controllers.admin.repo_visibility(login, reponame)

Change repository visibility (POST handler)

repocribro.controllers.admin.role_assignment_add(name)

Assign role to user (POST handler)

repocribro.controllers.admin.role_assignment_remove(name)

Remove assignment of role to user (POST handler)

repocribro.controllers.admin.role_create()

Create new role (POST handler)

repocribro.controllers.admin.role_delete(name)

Delete role (POST handler)

repocribro.controllers.admin.role_detail(name)

Role administration (GET handler)

repocribro.controllers.admin.role_edit(name)

Edit role (POST handler)

repocribro.controllers.auth
repocribro.controllers.auth.auth = <flask.blueprints.Blueprint object>

Auth controller blueprint

repocribro.controllers.auth.github()

Redirect to GitHub OAuth gate (GET handler)

repocribro.controllers.auth.github_callback()

Callback gate for GitHub OAUTH (GET handler)

repocribro.controllers.auth.github_callback_get_account(db, gh_api)

Processing GitHub callback action

Parameters:
  • db (flask_sqlalchemy.SQLAlchemy) – Database for storing GitHub user info
  • gh_api (repocribro.github.GitHubAPI) – GitHub API client ready for the communication
Returns:

User account and flag if it’s new one

Return type:

tuple of repocribro.models.UserAccount, bool

repocribro.controllers.auth.logout()

Logout currently logged user (GET handler)

repocribro.controllers.core
repocribro.controllers.core.core = <flask.blueprints.Blueprint object>

Core controller blueprint

repocribro.controllers.core.index()

Landing page (GET handler)

repocribro.controllers.core.org_detail(login)

Organization detail (GET handler)

Todo:implement 410 (org deleted/archived/renamed)
repocribro.controllers.core.repo_detail(login, reponame)

Repo detail (GET handler)

repocribro.controllers.core.repo_detail_common(db, ext_master, repo, has_secret=False)

Repo detail (for GET handlers)

Todo:implement 410 (repo deleted/archived/renamed)
repocribro.controllers.core.repo_detail_hidden(secret)

Hidden repo detail (GET handler)

repocribro.controllers.core.repo_redir(login)
repocribro.controllers.core.search(query='')

Search page (GET handler)

Todo:more attrs, limits & pages
repocribro.controllers.core.user_detail(login)

User detail (GET handler)

Todo:implement 410 (user deleted/archived/renamed)
repocribro.controllers.errors
repocribro.controllers.errors.err_forbidden(error)

Error handler for HTTP 403 - Unauthorized

repocribro.controllers.errors.err_gone(error)

Error handler for HTTP 410 - Gone

repocribro.controllers.errors.err_internal(error)

Error handler for HTTP 501 - Not Implemented

repocribro.controllers.errors.err_not_found(error)

Error handler for HTTP 403 - Not Found

repocribro.controllers.errors.errors = <flask.blueprints.Blueprint object>

Errors controller blueprint

repocribro.controllers.manage
repocribro.controllers.manage.dashboard()

Management zone dashboard (GET handler)

repocribro.controllers.manage.has_good_webhook(gh_api, repo)

Check webhook at GitHub for repo

Parameters:
  • gh_api (repocribro.github.GitHubAPI) – GitHub API client for communication
  • repo (repocribro.models.Repository) – Repository which webhook should be checked
Returns:

If webhook is already in good shape

Return type:

bool

Todo:

move somewhere else, check registered events

repocribro.controllers.manage.manage = <flask.blueprints.Blueprint object>

Manage controller blueprint

repocribro.controllers.manage.organizations()

List user organizations from GitHub (GET handler)

repocribro.controllers.manage.repo_activate(reponame)

Activate repo in app from GitHub (POST handler)

Todo:protect from activating too often
repocribro.controllers.manage.repo_deactivate(reponame)

Deactivate repo in app from GitHub (POST handler)

repocribro.controllers.manage.repo_delete()

Delete repo (in app) from GitHub (POST handler)

repocribro.controllers.manage.repo_detail(reponame)

Repository detail (GET handler)

repocribro.controllers.manage.repo_update(reponame)

Update repo info from GitHub (GET handler)

Todo:protect from updating too often
repocribro.controllers.manage.repositories()

List user repositories from GitHub (GET handler)

repocribro.controllers.manage.update_profile()

Update user info from GitHub (GET handler)

Todo:protect from updating too often
repocribro.controllers.manage.update_webhook(gh_api, repo)

Update webhook at GitHub for repo if needed

Parameters:
  • gh_api (repocribro.github.GitHubAPI) – GitHub API client for communication
  • repo (repocribro.models.Repository) – Repository which webhook should be updated
Returns:

If webhook is now in good shape

Return type:

bool

Todo:

move somewhere else

repocribro.controllers.webhooks
repocribro.controllers.webhooks.gh_webhook()

Point for GitHub webhook msgs (POST handler)

repocribro.ext_core

CoreExtension
class repocribro.ext_core.CoreExtension(master, app, db)

Bases: repocribro.extending.extension.Extension

ADMIN_URL = None
AUTHOR = 'Marek Suchánek'

Author of core extension

CATEGORY = 'basic'

Category of core extension

GH_URL = 'https://github.com/MarekSuchanek/repocribro'

GitHub URL of core extension

HOME_URL = None
NAME = 'core'

Name of core extension

__init__(master, app, db)
call(hook_name, default, *args, **kwargs)

Call the operation via hook name

Parameters:
  • hook_name (str) – Name of hook to be called
  • default – Default return value if hook operation not found
  • args – Positional args to be passed to the hook operation
  • kwargs – Keywords args to be passed to the hook operation
Returns:

Result of the operation on the requested hook

static get_gh_event_processors()

Get all GitHub events processors

static get_gh_webhook_processors()

Get all GitHub webhooks processory

init_blueprints()

Hook operation for initiating the blueprints and registering them within repocribro Flask app

init_business()

Init business layer (other extensions, what is needed)

init_container()

Init service DI container of the app

init_filters()

Hook operation for initiating the Jinja filters and registering them within Jinja env of repocribro Flask app

init_models()

Hook operation for initiating the models and registering them within db

introduce()

Hook operation for getting short introduction of extension (mostly for debug/log purpose)

Returns:Name of the extension
Return type:str
static provide_blueprints()
static provide_filters()
static provide_models()
register_blueprints_from_list(blueprints)

Registering Flask blueprints to the app

Parameters:blueprints (list of flask.blueprint) – List of Flask blueprints to be registered
register_filters_from_dict(filters)

Registering functions as Jinja filters

Parameters:filters (dict of str: function) – Dictionary where key is name of filter and value is the function serving as filter
view_admin_extensions()

Hook operation for getting view model of the extension in order to show it in the administration of app

Returns:Extensions view for this extension
Return type:repocribro.extending.helpers.ExtensionView
view_admin_index_tabs(tabs_dict)

Prepare tabs for index view of admin controller

Parameters:tabs_dict (dict of str: repocribro.extending.helpers.ViewTab) – Target dictionary for tabs
view_core_org_detail_tabs(org, tabs_dict)

Prepare tabs for org detail view of core controller

Parameters:
  • org (repocribro.models.Organization) – Organization which details should be shown
  • tabs_dict (dict of str: repocribro.extending.helpers.ViewTab) – Target dictionary for tabs
view_core_repo_detail_tabs(repo, tabs_dict)

Prepare tabs for repo detail view of core controller

Parameters:
  • repo (repocribro.models.Repository) – Repository which details should be shown
  • tabs_dict (dict of str: repocribro.extending.helpers.ViewTab) – Target dictionary for tabs
view_core_search_tabs(query, tabs_dict)

Prepare tabs for search view of core controller

Parameters:
  • query (str) – Fulltext query for the search
  • tabs_dict (dict of str: repocribro.extending.helpers.ViewTab) – Target dictionary for tabs
view_core_user_detail_tabs(user, tabs_dict)

Prepare tabs for user detail view of core controller

Parameters:
  • user (repocribro.models.User) – User which details should be shown
  • tabs_dict (dict of str: repocribro.extending.helpers.ViewTab) – Target dictionary for tabs
view_manage_dashboard_tabs(tabs_dict)

Prepare tabs for dashboard view of manage controller

Parameters:tabs_dict (dict of str: repocribro.extending.helpers.ViewTab) – Target dictionary for tabs
make_extension
repocribro.ext_core.make_extension(*args, **kwargs)

Alias for instantiating the extension

Actually not needed, just example that here can be something more complex to do before creating the extension.

repocribro.extending

Extension
class repocribro.extending.Extension(master, app, db)

Bases: object

Generic repocribro extension class

It serves as base extension which does nothing but has prepared all the attributes and methods needed. Particular real extensions can override those attributes and methods to make so behavior and extend repocribro. It also provides some useful methods to those subclasses.

ADMIN_URL = None

Administration URL within site (best via url_for)

AUTHOR = ''

Author(s) of extension

CATEGORY = ''

Category of extension (basic, security, data, ...)

GH_URL = None

GitHub url of extension project

HOME_URL = None

Homepage url of extension (rtd, pocoo, ...)

NAME = 'unknown'

Name of extension

__init__(master, app, db)

Inits the basic two parts of repocribro - flask app and DB

Parameters:
  • master (ExtensionsMaster) – Master for this extension
  • app (flask.Flask) – Flask application of repocribro
  • db (flask_sqlalchemy.SQLAlchemy) – SQLAlchemy database of repocribro
  • args – not used
  • kwargs – not used
call(hook_name, default, *args, **kwargs)

Call the operation via hook name

Parameters:
  • hook_name (str) – Name of hook to be called
  • default – Default return value if hook operation not found
  • args – Positional args to be passed to the hook operation
  • kwargs – Keywords args to be passed to the hook operation
Returns:

Result of the operation on the requested hook

init_blueprints()

Hook operation for initiating the blueprints and registering them within repocribro Flask app

init_filters()

Hook operation for initiating the Jinja filters and registering them within Jinja env of repocribro Flask app

init_models()

Hook operation for initiating the models and registering them within db

introduce()

Hook operation for getting short introduction of extension (mostly for debug/log purpose)

Returns:Name of the extension
Return type:str
static provide_blueprints()

Extension can provide Flask blueprints to the app by this method

Returns:List of Flask blueprints provided by extension
Return type:list of flask.blueprint
static provide_filters()

Extension can provide Jinja filters to the app by this method

Returns:Dictionary with name + function/filter pairs
Return type:dict of str: function
static provide_models()

Extension can provide (DB) models to the app by this method

Returns:List of models provided by extension
Return type:list of db.Model
register_blueprints_from_list(blueprints)

Registering Flask blueprints to the app

Parameters:blueprints (list of flask.blueprint) – List of Flask blueprints to be registered
register_filters_from_dict(filters)

Registering functions as Jinja filters

Parameters:filters (dict of str: function) – Dictionary where key is name of filter and value is the function serving as filter
view_admin_extensions()

Hook operation for getting view model of the extension in order to show it in the administration of app

Returns:Extensions view for this extension
Return type:repocribro.extending.helpers.ExtensionView
ExtensionsMaster
class repocribro.extending.ExtensionsMaster(*args, **kwargs)

Bases: object

Collector & master of Extensions

Extension master finds and holds all the repocribro extensions and is used for calling operations on them and collecting the results.

ENTRYPOINT_GROUP = 'repocribro.ext'

String used for looking up the extensions

LOAD_ERROR_MSG = 'Extension "{}" ({}) is not making an Extension (sub)class instance. It will be ignored!'

Error message mask for extension load error

__init__(*args, **kwargs)

Collects all the extensions to be mantained by this object

Parameters:
  • args – positional args to be passed to extensions
  • kwargs – keywords args to be passed to extensions
Todo:

there might be some problem with ordering of extensions

classmethod _collect_extensions(name=None)

Method for selecting extensions within ENTRYPOINT_GROUP

Parameters:name (str) – Can be used to select single entrypoint/extension
Returns:Generator of selected entry points
Return type:pkg_resources.WorkingSet.iter_entry_points
call(hook_name, default=None, *args, **kwargs)

Call the hook on all extensions registered

Parameters:
  • hook_name (str) – Name of hook to be called
  • default – Default return value if hook operation not found
  • args – Positional args to be passed to the hook operation
  • kwargs – Keywords args to be passed to the hook operation
Returns:

Result of the operation on the requested hook

repocribro.extending.helpers.views
repocribro.extending.helpers.views.ViewTab
class repocribro.extending.helpers.views.ViewTab(id, name, priority=100, content='', octicon=None, badge=None)

Bases: object

Tab for the tabbed view at pages

__init__(id, name, priority=100, content='', octicon=None, badge=None)
__lt__(other)
repocribro.extending.helpers.views.Badge
class repocribro.extending.helpers.views.Badge(content)

Bases: object

Simple Twitter Bootstrap badge representation

__init__(content)
repocribro.extending.helpers.views.ExtensionView
class repocribro.extending.helpers.views.ExtensionView(name, category, author, admin_url=None, home_url=None, gh_url=None)

Bases: object

View object for extensions

__init__(name, category, author, admin_url=None, home_url=None, gh_url=None)
static from_class()

Make view from Extension class

repocribro.manage

repocribro.manage.run()

Run the CLI manager for the web application

Todo:allow extension add options & commands, separate create and run part of function

repocribro.models

Mixins
Anonymous
class repocribro.models.Anonymous

Bases: flask_login.mixins.AnonymousUserMixin

Anonymous (not logged) user representation

has_role(role)

Check whether has the role

Parameters:role (repocribro.models.RoleMixin) – Role to be checked
Returns:False, anonymous has no roles
Return type:bool
is_active

Check whether is user active

Returns:False, anonymous is not active
Return type:bool
owns_repo(repo)

Check if user owns the repository

Parameters:repo (repocribro.models.Repository) – Repository which shoudl be tested
Returns:False, anonymous can not own repository
Return type:bool
rolenames

Get names of all roles of that user

Returns:Empty list, anonymous has no roles
Return type:list of str
sees_repo(repo, has_secret=False)

Check if user is allowed to see the repo

Anonymous can see only public repos

Parameters:
  • repo (repocribro.models.Repository) – Repository which user want to see
  • has_secret (bool) – If current user knows the secret URL
Returns:

If user can see repo

Return type:

bool

RoleMixin
class repocribro.models.RoleMixin

Bases: object

Mixin for models representing roles

__eq__(other)

Equality of roles is based on names

Parameters:other (repocribro.models.RoleMixin or str) – Role or its name to be compared with
Returns:If names are equal
Return type:bool
__hash__()

Standard hashing via name

Returns:Hash of role
Return type:int
__ne__(other)

Inequality of roles is based on names

Parameters:other (repocribro.models.RoleMixin or str) – Role or its name to be compared with
Returns:If names are not equal
Return type:bool
SearchableMixin
class repocribro.models.SearchableMixin

Bases: object

Mixin for models that support fulltext query

classmethod fulltext_query(query_str, db_query)

Add fulltext filter to the DB query

Parameters:
  • query_str (str) – String to be queried
  • db_query (sqlalchemy.orm.query.Query) – Database query object
Returns:

Query with fulltext filter added

Return type:

sqlalchemy.orm.query.Query

UserMixin
class repocribro.models.UserMixin

Bases: flask_login.mixins.UserMixin

has_role(role)

Check whether has the role

Parameters:role (str) – Role to be checked
Returns:If user has a role
Return type:bool
is_active

Check whether is user active

Returns:If user is active (can login)
Return type:bool
owns_repo(repo)

Check if user owns the repository

Parameters:repo (repocribro.models.Repository) – Repository which shoudl be tested
Returns:If user owns repo
Return type:bool
rolenames

Get names of all roles of that user

Returns:List of names of roles of user
Return type:list of str
sees_repo(repo, has_secret=False)

Check if user is allowed to see the repo

Must be admin or owner to see not public repo

Parameters:
  • repo (repocribro.models.Repository) – Repository which user want to see
  • has_secret (bool) – If current user knows the secret URL
Returns:

If user can see repo

Return type:

bool

Models
Commit
class repocribro.models.Commit(sha, message, author_name, author_email, distinct, push)

Bases: flask_sqlalchemy.Model, repocribro.models.SearchableMixin

Commit from GitHub

__init__(sha, message, author_name, author_email, distinct, push)
__repr__()

Standard string representation of DB object

Returns:Unique string representation
Return type:str
_sa_class_manager = <ClassManager of <class 'repocribro.models.Commit'> at 7fc37756f188>
author_email

The git author’s email address.

author_name

The git author’s name.

static create_from_dict(commit_dict, push)

Create new commit from GitHub and additional data

Parameters:
  • commit_dict (dict) – GitHub data containing commit
  • push (repocribro.models.Push) – Push where this commit belongs
Returns:

Created new commit

Return type:

repocribro.models.Commit

Todo:

verify, there are some conflict in GitHub docs

distinct

Whether this commit is distinct from any that have been pushed before.

id

Unique identifier of the commit

message

The commit message.

push

Push where the commit belongs to

push_id

ID of push where the commit belongs to

sha

The SHA of the commit.

Organization
class repocribro.models.Organization(github_id, login, email, name, company, location, description, blog_url, avatar_url)

Bases: repocribro.models.RepositoryOwner, repocribro.models.SearchableMixin

Organization from GitHub

__init__(github_id, login, email, name, company, location, description, blog_url, avatar_url)
__repr__()

Standard string representation of DB object

Returns:Unique string representation
Return type:str
_sa_class_manager = <ClassManager of <class 'repocribro.models.Organization'> at 7fc377613138>
avatar_url
blog_url
company
static create_from_dict(org_dict)

Create new organization from GitHub data

Parameters:org_dict (dict) – GitHub data containing organization
Returns:Created new organization
Return type:repocribro.models.Organization
description
email
github_id
id
location
login
name
repositories
type
Push
class repocribro.models.Push(github_id, ref, after, before, size, distinct_size, timestamp, sender_login, sender_id, repository)

Bases: flask_sqlalchemy.Model, repocribro.models.SearchableMixin

Push from GitHub

__init__(github_id, ref, after, before, size, distinct_size, timestamp, sender_login, sender_id, repository)
__repr__()

Standard string representation of DB object

Returns:Unique string representation
Return type:str
_sa_class_manager = <ClassManager of <class 'repocribro.models.Push'> at 7fc377613bd8>
after

The SHA of the most recent commit on ref after the push. (HEAD)

before

The SHA of the most recent commit on ref before the push.

commits

Commits within this push

static create_from_dict(push_dict, sender_dict, repo, timestamp=None)

Create new push from GitHub and additional data

This also creates commits of this push

Parameters:
  • push_dict (dict) – GitHub data containing push
  • sender_dict (dict) – GitHub data containing sender
  • repo (repocribro.models.Repository) – Repository where this push belongs
Returns:

Created new push

Return type:

repocribro.models.Push

distinct_size

The number of distinct commits in the push.

github_id

GitHub Push ID

id

Unique identifier of the push

ref

The full Git ref that was pushed.

repository

Repository where push belongs to

repository_id

ID of the repository where push belongs to

sender_id

ID of the sender

sender_login

Login of the sender

size

The number of commits in the push.

timestamp

Timestamp of push (when it was registered)

Role
class repocribro.models.Role(name, description)

Bases: flask_sqlalchemy.Model, repocribro.models.RoleMixin

User account role in the application

__init__(name, description)
__repr__()

Standard string representation of DB object

Returns:Unique string representation
Return type:str
_sa_class_manager = <ClassManager of <class 'repocribro.models.Role'> at 7fc3775fd228>
description

Description (purpose, notes, ...) of the role

id

Unique identifier of the role

name

Unique name of the role

user_accounts

User accounts assigned to the role

Release
class repocribro.models.Release(github_id, tag_name, created_at, published_at, url, prerelease, draft, name, body, author_id, author_login, sender_login, sender_id, repository)

Bases: flask_sqlalchemy.Model, repocribro.models.SearchableMixin

Release from GitHub

__init__(github_id, tag_name, created_at, published_at, url, prerelease, draft, name, body, author_id, author_login, sender_login, sender_id, repository)
__repr__()

Standard string representation of DB object

Returns:Unique string representation
Return type:str
_sa_class_manager = <ClassManager of <class 'repocribro.models.Release'> at 7fc37756f6d8>
author_id

ID of author

author_login

Login of author

body

Body with some description

static create_from_dict(release_dict, sender_dict, repo)

Create new release from GitHub and additional data

Parameters:
  • release_dict (dict) – GitHub data containing release
  • sender_dict (dict) – GitHub data containing sender
  • repo (repocribro.models.Repository) – Repository where this release belongs
Returns:

Created new release

Return type:

repocribro.models.Release

created_at

Timestamp when the release was created

draft

Flag if it’s just a draft

github_id

GitHub unique identifier

id

Unique identifier of the release

name

Name

prerelease

Flag if it’s just a prerelease

published_at

Timestamp when the release was published

repository

Repository where release belongs to

repository_id

ID of the repository where release belongs to

sender_id

ID of sender

sender_login

Login of sender

tag_name

Tag of the release

url

URL to release page

Repository
class repocribro.models.Repository(github_id, fork_of, full_name, name, languages, url, description, private, webhook_id, owner, visibility_type, secret=None)

Bases: flask_sqlalchemy.Model, repocribro.models.SearchableMixin

Repository from GitHub

VISIBILITY_HIDDEN = 2

Constant representing hidden visibility within app

VISIBILITY_PRIVATE = 1

Constant representing private visibility within app

VISIBILITY_PUBLIC = 0

Constant representing public visibility within app

__init__(github_id, fork_of, full_name, name, languages, url, description, private, webhook_id, owner, visibility_type, secret=None)
__repr__()

Standard string representation of DB object

Returns:Unique string representation
Return type:str
_sa_class_manager = <ClassManager of <class 'repocribro.models.Repository'> at 7fc377613818>
static create_from_dict(repo_dict, owner, webhook_id=None, visibility_type=0, secret=None)

Create new repository from GitHub and additional data

Parameters:
  • repo_dict (dict) – GitHub data containing repository
  • owner (repocribro.model.RepositoryOwner) – Owner of this repository
  • webhook_id (int) – ID of registered webhook (if available)
  • visibility_type (int) – Visibility type within app (default: public)
  • secret (str) – Secret for hidden URL (if available)
Returns:

Created new repository

Return type:

repocribro.models.Repository

Todo:

work with fork_of somehow

description
events_updated()

Set that now was performed last events update of repo

Todo:How about some past events before adding to app?
fork_of

GitHub id of repository which this is fork of

full_name

Full name (owner login + repository name)

generate_secret()

Generate new unique secret code for repository

github_id

GitHub unique identifier

id

Unique identifier of the repository

is_hidden

Check if repository is hidden within app

is_private

Check if repository is private within app

is_public

Check if repository is public within app

languages
last_event
static make_full_name(login, reponame)

Create full name from owner login name and repository name

Parameters:
  • login (str) – Owner login
  • reponame (str) – Name of repository (without owner login)
Returns:

Full name of repository

Return type:

str

name
owner

Owner of repository

owner_id
owner_login

Get owner login from full name of repository

Returns:Owner login
Return type:str
private
pushes

Registered pushes to repository

releases

Registered releases for repository

secret
update_from_dict(repo_dict)

Update repository attributes from GitHub data dict

Parameters:repo_dict (dict) – GitHub data containing repository
url
visibility_type
webhook_id
User
class repocribro.models.User(github_id, login, email, name, company, location, bio, blog_url, avatar_url, hireable, user_account)

Bases: repocribro.models.RepositoryOwner, repocribro.models.SearchableMixin

User from GitHub

__init__(github_id, login, email, name, company, location, bio, blog_url, avatar_url, hireable, user_account)
__repr__()

Standard string representation of DB object

Returns:Unique string representation
Return type:str
_sa_class_manager = <ClassManager of <class 'repocribro.models.User'> at 7fc3775fdb88>
avatar_url
blog_url
company
static create_from_dict(user_dict, user_account)

Create new user from GitHub data and related user account

Parameters:
  • user_dict (dict) – GitHub data containing user
  • user_account (repocribro.models.UserAccount) – User account in app for GH user
Returns:

Created new user

Return type:

repocribro.models.User

description
email
github_id
hireable

Flag whether is user hireable

id
location
login
name
repositories
type
update_from_dict(user_dict)

Update user from GitHub data

Parameters:user_dict (dict) – GitHub data containing user
user_account

User’s account within app

user_account_id

ID of user’s account within app

UserAccount
class repocribro.models.UserAccount(**kwargs)

Bases: flask_sqlalchemy.Model, repocribro.models.UserMixin, repocribro.models.SearchableMixin

UserAccount in the repocribro app

__init__(**kwargs)

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

__repr__()

Standard string representation of DB object

Returns:Unique string representation
Return type:str
_sa_class_manager = <ClassManager of <class 'repocribro.models.UserAccount'> at 7fc37765cdb8>
active

Flag if the account is active or banned

created_at

Timestamp where account was created

github_user

Relation to the GitHub user connected to account

id

Unique identifier of the user account

login

Get login name for user account from related GH user

Returns:Login name
Return type:str
roles

Roles assigned to the user account

repocribro.repocribro

repocribro.repocribro.AUTHOR = 'Marek Suchánek'

Author of the application

repocribro.repocribro.DEFAULT_CONFIG_FILES = ['config/app.cfg', 'config/auth.cfg', 'config/db.cfg']

Paths to default configuration files

class repocribro.repocribro.DI_Container

Simple container of services for web app

Variables:
  • factories – Factories of services
  • singletons – Singletons (shared objects) of services
__init__()

Prepare dict for storing services and factories

get(what, *args, **kwargs)

Retrieve service from the container

Parameters:
  • what (str) – Name of the service to get
  • args – Positional arguments passed to factory
  • kwargs – Keyword arguments passed to factory
Returns:

The service or None

set_factory(name, factory)

Set service factory (callable for creating instances)

Parameters:
  • name (str) – Name of the service
  • factory (callable) – Function or callable object creating service instance
set_singleton(name, singleton)

Set service as singleton (shared object)

Parameters:
  • name (str) – Name of the service
  • singleton (object) – The object to be shared as singleton
repocribro.repocribro.PROG_NAME = 'repocribro'

Name of the application

repocribro.repocribro.RELEASE = '0.1'

Actual release tag

class repocribro.repocribro.Repocribro

Repocribro is Flask web application

Variables:container – Service container for the app
__init__()

Setup Flask app and prepare service container

repocribro.repocribro.VERSION = '0.1'

Actual version

repocribro.repocribro.create_app(cfg_files='DEFAULT')

Factory for making the web Flask application

Parameters:cfg_files – Single or more config file(s)
Returns:Constructed web application
Return type:repocribro.repocribro.Repocribro

repocribro.security

class repocribro.security.Permissions

Class for prividing various permissions

Todo:allow extensions provide permissions to others
__dict__ = mappingproxy({'__module__': 'repocribro.security', 'admin_role': <Permission needs={Need(method='role', value='admin')} excludes=set()>, '__weakref__': <attribute '__weakref__' of 'Permissions' objects>, '__doc__': ' Class for prividing various permissions\n\n :todo: allow extensions provide permissions to others\n ', '__dict__': <attribute '__dict__' of 'Permissions' objects>})
__module__ = 'repocribro.security'
__weakref__

list of weak references to the object (if defined)

admin_role = <Permission needs={Need(method='role', value='admin')} excludes=set()>

Administrator role permission

repocribro.security.clear_session(*args)

Simple helper for clearing variables from session

Parameters:args – names of session variables to remove
repocribro.security.init_login_manager(db)

Init security extensions (login manager and principal)

Parameters:db (flask_sqlalchemy.SQLAlchemy) – Database which stores user accounts and roles
Returns:Login manager and principal extensions
Return type:(flask_login.LoginManager, flask_principal.Principal
repocribro.security.login(user_account)

Login desired user into the app

Parameters:user_account (repocribro.models.UserAccount) – User account to be logged in
repocribro.security.logout()

Logout the current user from the app

repocribro.security.on_identity_loaded(sender, identity)

Principal helper for loading the identity of logged user

Parameters:
  • sender – Sender of the signal
  • identity (flask_principal.Identity) – Identity container
repocribro.security.permissions = <repocribro.security.Permissions object>

All permissions in the app

Indices and tables