-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e905ab5
commit 0182d61
Showing
13 changed files
with
784 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
include LICENSE | ||
include config/auth.example.cfg | ||
include config/rules.example.cfg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
ghia | ||
==== | ||
|
||
GitHub Issue Assigner | ||
|
||
Installation and usage | ||
---------------------- | ||
|
||
:: | ||
|
||
$ python setup.py install | ||
$ ghia --help | ||
|
||
Or for the web app (GitHub webhook service): | ||
|
||
:: | ||
|
||
$ python setup.py install | ||
$ export FLASK_APP=ghia | ||
$ flask run | ||
|
||
Then visit the web application on displayed address. | ||
|
||
Strategies | ||
~~~~~~~~~~ | ||
|
||
- ``append`` = add additional matching assignees | ||
- ``set`` = set matching assignees only if issue is not assigned yet | ||
- ``change`` = keep only matching assignees (remove existing | ||
non-matching assignees) | ||
|
||
Configuration | ||
~~~~~~~~~~~~~ | ||
|
||
Authentication | ||
^^^^^^^^^^^^^^ | ||
|
||
You need a GitHub `personal access token`_ to run this application. It | ||
has to be specified in the configuration file as follows: | ||
|
||
.. code:: ini | ||
[github] | ||
token=<YOUR_PERSONAL_ACCESS_TOKEN> | ||
Rules | ||
^^^^^ | ||
|
||
Rules configuration consists of two parts: | ||
|
||
- **Patterns** which define what username will be matched against what | ||
regex pattern. Each pattern starts with information with what part of | ||
issue it will be matched (``title``, ``text``, ``label``, or | ||
``any``). | ||
- (optional) **Fallback** part describes just a label to be set for | ||
issue that has no assignee after running the assigner. | ||
|
||
.. code:: ini | ||
[patterns] | ||
MarekSuchanek= | ||
title:network | ||
text:protocol | ||
text:http[s]{0,1}://localhost:[0-9]{2,5} | ||
label:^(network|networking)$ | ||
hroncok=any:Python | ||
[fallback] | ||
label=Need assignment | ||
License | ||
------- | ||
|
||
This project is licensed under the MIT License - see the `LICENSE`_ file | ||
for more details. | ||
|
||
.. _personal access token: https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line | ||
.. _LICENSE: LICENSE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[github] | ||
token=TOKEN |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[patterns] | ||
MarekSuchanek= | ||
title:network | ||
text:protocol | ||
text:http[s]{0,1}://localhost:[0-9]{2,5} | ||
label:^(network|networking)$ | ||
hroncok=any:Python | ||
|
||
[fallback] | ||
label=Need assignment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from ghia.cli import cli | ||
from ghia.web import create_app | ||
|
||
__all__ = ['cli', 'create_app'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from ghia.cli import cli | ||
|
||
cli(prog_name='ghia') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import click | ||
import configparser | ||
|
||
from ghia.logic import GHIA, parse_rules | ||
|
||
|
||
class PrinterObserver: | ||
|
||
@staticmethod | ||
def issue(owner, repo, issue): | ||
number, url = issue['number'], issue['html_url'] | ||
identifier = click.style(f'{owner}/{repo}#{number}', bold=True) | ||
click.echo(f'-> {identifier} ({url})') | ||
|
||
@staticmethod | ||
def assignees(old, new): | ||
mi = click.style('-', fg='red', bold=True) | ||
pl = click.style('+', fg='green', bold=True) | ||
eq = click.style('=', fg='blue', bold=True) | ||
assignees = list(set(old).union(set(new))) | ||
assignees.sort(key=lambda a: a.lower()) | ||
for assignee in assignees: | ||
sign = eq | ||
if assignee not in old: | ||
sign = pl | ||
elif assignee not in new: | ||
sign = mi | ||
click.echo(f' {sign} {assignee}') | ||
|
||
@staticmethod | ||
def fallbacked(label, added=True): | ||
prefix = click.style('FALLBACK', fg='yellow', bold=True) | ||
click.echo(' ', nl=False) | ||
message = 'added label' if added else 'already has label' | ||
click.echo(f'{prefix}: {message} "{label}"') | ||
|
||
@staticmethod | ||
def error(message, of_issue=False): | ||
prefix = click.style('ERROR', bold=True, fg='red') | ||
if of_issue: | ||
click.echo(' ', nl=False, err=True) | ||
click.echo(f'{prefix}: {message}', err=True) | ||
|
||
|
||
|
||
def get_rules(ctx, param, config_rules): | ||
""" | ||
Extract labels from labels config and do the checks | ||
config_rules: ConfigParser with loaded configuration of labels | ||
""" | ||
try: | ||
cfg_rules = configparser.ConfigParser() | ||
cfg_rules.optionxform = str | ||
cfg_rules.read_file(config_rules) | ||
return parse_rules(cfg_rules) | ||
except Exception: | ||
raise click.BadParameter('incorrect configuration format') | ||
|
||
|
||
def get_token(ctx, param, config_auth): | ||
""" | ||
Extract token from auth config and do the checks | ||
config_auth: ConfigParser with loaded configuration of auth | ||
""" | ||
try: | ||
cfg_auth = configparser.ConfigParser() | ||
cfg_auth.read_file(config_auth) | ||
return cfg_auth.get('github', 'token') | ||
except Exception: | ||
raise click.BadParameter('incorrect configuration format') | ||
|
||
|
||
def parse_reposlug(ctx, param, reposlug): | ||
try: | ||
owner, repo = reposlug.split('/') | ||
return owner, repo | ||
except ValueError: | ||
raise click.BadParameter('not in owner/repository format') | ||
|
||
|
||
@click.command(name='ghia') | ||
@click.argument('reposlug', type=click.STRING, callback=parse_reposlug) | ||
@click.option('-s', '--strategy', default=GHIA.DEFAULT_STRATEGY, | ||
show_default=True, type=click.Choice(GHIA.STRATEGIES.keys()), | ||
envvar=GHIA.ENVVAR_STRATEGY, | ||
help='How to handle assignment collisions.') | ||
@click.option('--dry-run', '-d', is_flag=True, envvar=GHIA.ENVVAR_DRYRUN, | ||
help='Run without making any changes.') | ||
@click.option('-a', '--config-auth', type=click.File('r'), callback=get_token, | ||
help='File with authorization configuration.', required=True) | ||
@click.option('-r', '--config-rules', type=click.File('r'), callback=get_rules, | ||
help='File with assignment rules configuration.', required=True) | ||
def cli(reposlug, strategy, dry_run, config_auth, config_rules): | ||
"""CLI tool for automatic issue assigning of GitHub issues""" | ||
token = config_auth | ||
rules, fallback_label = config_rules | ||
owner, repo = reposlug | ||
ghia = GHIA(token, rules, fallback_label, dry_run, strategy) | ||
ghia.add_observer('printer', PrinterObserver) | ||
ghia.run(owner, repo) |
Oops, something went wrong.