20after4 has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/390429 )
Change subject: Task Series scap plugin ...................................................................... Task Series scap plugin Change-Id: If3d375d39c976788499737ab68fb281eb13dc2c5 --- A scap/plugins/task-series.py 1 file changed, 248 insertions(+), 0 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/tools/release refs/changes/29/390429/1 diff --git a/scap/plugins/task-series.py b/scap/plugins/task-series.py new file mode 100644 index 0000000..14bd75e --- /dev/null +++ b/scap/plugins/task-series.py @@ -0,0 +1,248 @@ +# This Python file uses the following encoding: utf-8 + +from __future__ import print_function, unicode_literals + +import argparse +import calendar +import datetime +import re +import os + +from string import Template + +from calendar import Calendar +from phabricator import Phabricator +from scap import cli, log +from scap.utils import var_dump +from datetime import timedelta + + +ONEWEEK = timedelta(weeks=1) + + +def trunc(len, string, ellipsis=" …"): + return string[0:len] + ellipsis + + +def action_arg(*args, **kwargs): + kwargs['const'] = kwargs['action'] + kwargs['dest'] = 'action' + kwargs['action'] = 'store_const' + kwargs['metavar'] = 'ACTION' + return cli.argument(*args, **kwargs) + + +# function by jfs, see https://stackoverflow.com/a/8778548/1672995 +def totimestamp(dt, epoch=datetime.datetime(1970, 1, 1)): + td = dt - epoch + # return td.total_seconds() + return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6 + + +def find_mondays(year, month): + cal = Calendar() + mondays = list() + for week in cal.monthdays2calendar(year, month): + for day in week: + (monthday, weekday) = day + if (weekday == 1 and monthday > 0): + mondays.append(datetime.date(year=year, + month=month, + day=monthday)) + return mondays + + +phab = Phabricator(host='https://phabricator.wikimedia.org/api/') + + +def phab_taskid(taskid): + if not taskid.startswith("T"): + raise Exception("Invalid task id: %s", taskid) + return taskid + + +def mediawiki_version(ver): + """Validation our version number formats""" + try: + return re.match("(\d+\.\d+(\.\d+-)?wmf\.?\d+)", ver).group(0) + except: + raise argparse.ArgumentTypeError( + "Invalid wmf version '%s' expected: #.##.#-wmf.#" % ver) + + +def date_str(datestr): + formats = ['%x', '%m-%d-%Y', '%Y%m%d', '%Y-%m-%d'] + err = None + date = None + for format in formats: + try: + date = datetime.datetime.strptime(datestr, format) + except Exception as ex: + err = ex + + if date is None and err is not None: + raise err + + return date + + +def map_transactions(obj): + trns = [] + + for key, val in obj.items(): + trns.append({ + "type": key, + "value": val + }) + return trns + + +@cli.command('task-series', subcommands=True) +class ReleaseTagger(cli.Application): + """ + Create a series of phabricator tasks with content generated from a template + """ + action = None + + def _setup_loggers(self): + """Setup logging.""" + log.setup_loggers(self.config, self.arguments.loglevel + 10) + + def _process_arguments(self, args, extra_args): + # print(args,extra_args) + return args, extra_args + + @cli.argument('--count', help='Number of tasks to create, default=1', + metavar='NUM', default=1, type=int) + @cli.argument('--date', help='Date of the first release,\ + default=today\'s date', metavar='START', + type=date_str, default=datetime.datetime.utcnow()) + @cli.argument('release', help='Create tasks beginning with VERSION', + metavar='VERSION', type=mediawiki_version) + @cli.subcommand('blockers') + def blockers(self, *args): + ''' + Create Release Blockers. + + Command Usage: + + $ scap task-series blockers --count 10 --date 2017-01-01 1.30.0-wmf.1 + + Creates 10 release-blocker tasks, beginning with version 1.30.0-wmf.1 + on 2017-01-01. + ''' + v = self.arguments.release.split('-') + wmfnum = int(v[-1].split('.')[-1]) + week = self.arguments.date + weekday = week.weekday() + if weekday: + # ofset some days so that we always use monday of the given week: + week -= timedelta(days=weekday) + + for n in range(wmfnum, wmfnum + self.arguments.count): + v[-1] = 'wmf.%d' % n + vs = "-".join(v) + + ts = int(totimestamp(week)) + trns = map_transactions({ + 'title': "%s deployment blockers" % vs, + 'subtype': 'release', + 'projects.add': ["PHID-PROJ-fmcvjrkfvvzz3gxavs3a", + "PHID-PROJ-pf35un2jsnsiriivnmeo"], + 'custom.release.version': str(vs), + 'custom.release.date': str(ts), + }) + print("%s : %s, %s" % (vs, week, ts)) + var_dump(phab.maniphest.edit(transactions=trns)) + week += ONEWEEK + + @cli.argument('--project', default='PHID-PROJ-fmcvjrkfvvzz3gxavs3a', + dest='project', metavar='PHID', + help='Hashtag or PHID for project (Optional)') + def list(selfm, *args): + project_name = self.arguments.project + query = { + 'subtypes': ['release'], + 'statuses': ['open'], + 'projects': [project_name] + } + tasks = phab.maniphest.search(constraints=query, + # queryKey='hFre3CTnmGm2', + order='title') + titles = [task['fields']['name'] for task in tasks['data']] + taskmap = {task['phid']: task['fields']['name'] + for task in tasks['data']} + var_dump(titles) + var_dump(taskmap) + + @cli.argument('--project', default='PHID-PROJ-fmcvjrkfvvzz3gxavs3a', + dest='project', metavar='PROJECT', + help='Create a tasks within PROJECT') + @cli.argument('--template', default='scap/templates/blockers.tmpl', + help='template file') + @cli.argument('--mwversion', help='MediaWiki Version, e.g. 1.30.0') + @cli.argument('--previous', type=phab_taskid) + @cli.argument('-h', '--help', action='help') + @cli.subcommand("create") + def taskseries(self, *args): + ''' create a task series in phabricator ''' + project_name = self.arguments.project + if project_name.startswith("PHID"): + parent_phid = project_name + else: + query = { + 'name': project_name, + } + project = phab.maniphest.search(constraints=query) + parent_phid = project['data'][0]['phid'] + + template_path = self.arguments.template + if "/" not in template_path: + template_path = os.path.join("scap", "templates", template_path) + + with file(template_path) as template_file: + template = Template("".join(template_file.readlines())) + + tmpl_vars = {} + for key in vars(self.arguments).keys(): + val = getattr(self.arguments, key) + while(isinstance(val, list)): + val = val[0] + + if type(val) in (unicode, str): + tmpl_vars[key] = val + + var_dump(tmpl_vars) + milestone_name = self.arguments.milestone[0] + description = template.safe_substitute(tmpl_vars) + + print(description) + + if self.arguments.hashtag is None: + hashtag = project_name + '-' + milestone_name + else: + hashtag = self.arguments.hashtag + + trns = [ + { + 'type': 'milestone', + 'value': parent_phid + }, + { + 'type': 'title', + 'value': milestone_name + }, + { + 'type': 'slugs', + 'value': [hashtag] + }, + { + 'type': 'description', + 'value': description + } + ] + + var_dump(trns) + result = phab.project.edit(transactions=trns) + + var_dump(result) -- To view, visit https://gerrit.wikimedia.org/r/390429 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If3d375d39c976788499737ab68fb281eb13dc2c5 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/tools/release Gerrit-Branch: master Gerrit-Owner: 20after4 <mmod...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits