Last active
December 23, 2015 10:09
-
-
Save skitazaki/6619967 to your computer and use it in GitHub Desktop.
Get updated issues of Redmine by each day.
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
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
"""Get updated issues of Redmine by each day. | |
Setup & Usage | |
------------- | |
Python 2.7, ``virtualenv``, and ``pip`` are required. | |
Prepare Python virtual environment for this script. :: | |
$ PYVENV_DIR=~/pyvenv/redmine-daily | |
$ virtualenv --distribute $PYVENV_DIR | |
$ source $PYVENV_DIR/bin/activate | |
Install dependant libraries:: | |
$ cat <<EOF >requirements.txt | |
pyredmine | |
clitool | |
pyyaml | |
jinja2 | |
python-dateutil==1.5 # "pyredmine" requires internally | |
EOF | |
$ pip install -r requirements.txt | |
Example configuration file is: | |
development: | |
url: "http://localhost:8080" | |
staging: | |
url: "http://test.example.com/redmine" | |
username: "skitazaki" | |
password: "secret" | |
production: | |
url: "http://ci.example.com/redmine" | |
username: "skitazaki" | |
password: "super-secret" | |
After saving above as ``config.yaml``, run as following. | |
:: | |
$ ./redmine-daily.py -c config.yaml --environment test --project demo | |
If ``--project`` options is omitted, crawl all projects. | |
""" | |
import datetime | |
from functools import partial | |
from redmine import Redmine | |
from jinja2 import Template | |
from clitool.cli import parse_arguments, cliconfig | |
NOW = datetime.datetime.now() | |
TEMPLATE = Template(u''' | |
[{{ identifier }}] {{ name }} | |
------------------------------------------------------------------------------ | |
{%- for r in rs %} | |
Updated on: {{ r.updated.strftime('%Y-%m-%d (%A)') }} | |
{% for issue in r.issues %} | |
#{{ issue.id }} {{ issue.subject }} | |
{{ issue.url }} | |
[{{ issue.status }}] by {{ issue.assigned_to }} until {{ issue.due_date }} | |
{% endfor %} | |
{%- endfor %} | |
'''.rstrip()) | |
def ticket_url(baseurl, ticket_number): | |
return '{}/issues/{}'.format(baseurl, ticket_number) | |
def writer(output, encoding, text): | |
output.write(text.encode(encoding)) | |
def main(): | |
args = parse_arguments( | |
environment=dict(flags='--environment', required=True), | |
project=dict(flags='--project', help="commna separated value"), | |
term=dict(flags='--term', type=int, default=7)) | |
cfg = cliconfig(args.config, args.environment) | |
if cfg is None: | |
raise SystemExit('Key is not found for "{}" in "{}"'.format( | |
args.environment, args.config.name)) | |
redmine = Redmine(cfg['url'], | |
username=cfg.get('username'), password=cfg.get('password')) | |
# Collect specified projects or all projects if nothing specified | |
projects = {} | |
if args.project: | |
for p in args.project.split(','): | |
projects[p] = redmine.projects[p] | |
else: | |
for proj in redmine.projects: | |
projects[proj.name] = proj | |
url = partial(ticket_url, cfg['url']) | |
write = partial(writer, args.output, args.output_encoding) | |
for proj in projects.values(): | |
rs = [] | |
for i in range(args.term): | |
d = NOW - datetime.timedelta(days=i) | |
issues = [] | |
for issue in proj.issues(updated_on=d.strftime('%Y-%m-%d')): | |
try: | |
assigned_to = 'User#{}'.format(issue.assigned_to.id) | |
except AttributeError: | |
assigned_to = 'NOT DETERMINED YET' | |
try: | |
due_date = issue.due_date | |
except AttributeError: | |
due_date = 'NOT DETERMINED YET' | |
issues.append({ | |
'id': issue.id, 'subject': issue.subject, | |
'url': url(issue.id), 'status': issue.status, | |
'assigned_to': assigned_to, 'due_date': due_date}) | |
if len(issues) > 0: | |
rs.append({'updated': d, 'issues': issues}) | |
write(TEMPLATE.render( | |
identifier=proj.identifier, name=proj.name, rs=rs)) | |
if __name__ == '__main__': | |
main() | |
# vim: set et ts=4 sw=4 cindent fileencoding=utf-8 : |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment