From f53cfc6dec17fc372cd4433064e1882575eb22d3 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Mon, 18 Feb 2013 15:24:38 +0800 Subject: [PATCH] Command pull to fetch a patch from a tracker issue --- README.md | 12 ++++++ extra/bash_completion | 5 ++- lib/jira.py | 19 +++++++-- moodle-pull.py | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ moodle-rebase.py | 2 +- 5 files changed, 142 insertions(+), 5 deletions(-) create mode 100755 moodle-pull.py diff --git a/README.md b/README.md index 96e9271..4869f50 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,18 @@ To purge the cache of all the instances mdk purge --all +pull +---- + +Pulls a patch using the information from a tracker issue. + +**Example** + +Assuming we type that command on a 2.3 instance, pulls the corresponding patch from the issue MDL-12345 in a testing branch + + mdk pull --testing 12345 + + push ---- diff --git a/extra/bash_completion b/extra/bash_completion index a20e5aa..27fd890 100644 --- a/extra/bash_completion +++ b/extra/bash_completion @@ -44,7 +44,7 @@ function _moodle() { if [[ "${COMP_CWORD}" == 1 ]]; then # List the commands and aliases. # Ignoring these commands on purpose: init - OPTS="alias backport backup check config create fix info install phpunit purge push rebase remove run update upgrade" + OPTS="alias backport backup check config create fix info install phpunit purge pull push rebase remove run update upgrade" OPTS="$OPTS $($BIN alias list | cut -d ':' -f 1)" else # List of options according to the command. @@ -132,6 +132,9 @@ function _moodle() { OPTS="$OPTS $($BIN info -ln)" fi ;; + pull) + OPTS="--integration --testing" + ;; push) if [[ "$PREV" != "--branch" && "$PREV" != "-b" && "$PREV" != "--remote" && "$PREV" != "-r" ]]; then OPTS="--branch --remote --force --include-stable --force-stable --update-tracker" diff --git a/lib/jira.py b/lib/jira.py index 6106b18..d73865f 100644 --- a/lib/jira.py +++ b/lib/jira.py @@ -26,6 +26,7 @@ import sys import json from tools import debug from config import Conf +from urllib import urlencode import getpass try: from restkit import request, BasicAuth @@ -62,10 +63,14 @@ class Jira(object): """Returns a property of this instance""" return self.info().get(param, default) - def getIssue(self, key): - """Load the issue info from the jira server using a rest api call""" + def getIssue(self, key, fields='*all'): + """Load the issue info from the jira server using a rest api call. - requesturl = self.url + 'rest/api/' + self.apiversion + '/issue/' + key + '?expand=names' + The returned key 'named' of the returned dict is organised by name of the fields, not id. + """ + + querystring = {'fields': fields, 'expand': 'names'} + requesturl = self.url + 'rest/api/' + self.apiversion + '/issue/' + key + '?%s' % (urlencode(querystring)) response = request(requesturl, filters=[self.auth]) if response.status_int == 404: @@ -75,6 +80,14 @@ class Jira(object): raise JiraException('Jira is not available.') issue = json.loads(response.body_string()) + issue['named'] = {} + + # Populate the named fields in a separate key. Allows us to easily find them without knowing the field ID. + namelist = issue.get('names', {}) + for fieldkey, fieldvalue in issue.get('fields', {}).items(): + if namelist.get(fieldkey, None) != None: + issue['named'][namelist.get(fieldkey)] = fieldvalue + return issue def getServerInfo(self): diff --git a/moodle-pull.py b/moodle-pull.py new file mode 100755 index 0000000..dc8a876 --- /dev/null +++ b/moodle-pull.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Moodle Development Kit + +Copyright (c) 2013 Frédéric Massart - FMCorz.net + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +http://github.com/FMCorz/mdk +""" + +import sys +import argparse +import re +from lib import workplace, tools, jira +from lib.tools import debug +from lib.config import Conf + +Wp = workplace.Workplace() +C = Conf() + +# Arguments +parser = argparse.ArgumentParser(description="Pull a branch from a tracker issue.") +parser.add_argument('-i', '--integration', action='store_true', help='checkout the stable branch before proceeding to the pull (Integration mode).') +parser.add_argument('-t', '--testing', action='store_true', help='checkout a testing branch before proceeding to the pull (Testing mode).') +parser.add_argument('issue', metavar='issue', default=None, nargs='?', help='tracker issue to pull from (MDL-12345, 12345). If not specified, read from current branch.') +args = parser.parse_args() + +M = Wp.resolve() +if not M: + debug('This is not a Moodle instance') + sys.exit(1) + +if args.testing and args.integration: + debug('You cannot combine --integration and --testing') + sys.exit(1) + +# Tracker issue number. +issue = re.sub(r'(MDL|mdl)(-|_)?', '', args.issue) +mdl = 'MDL-' + issue + +# Reading the information about the current instance. +branch = M.get('branch') + +# Get information from Tracker +debug('Retrieving information about %s from Moodle Tracker' % (mdl)) +J = jira.Jira() +issueInfo = J.getIssue(mdl) +remoteUrl = issueInfo.get('named').get(C.get('tracker.fieldnames.repositoryurl')) +remoteBranch = issueInfo.get('named').get(C.get('tracker.fieldnames.%s.branch' % (branch))) +if not remoteUrl or not remoteBranch: + debug('Not enough information to pull the branch') + +# Stash +stash = M.git().stash(untracked=True) +if stash[0] != 0: + debug('Error while trying to stash your changes. Exiting...') + sys.exit(1) +elif not stash[1].startswith('No local changes'): + debug('Stashed your local changes') + +# Create a testing branch +if args.testing: + i = 0 + while True: + i += 1 + suffix = 'test' if i <= 1 else 'test' + str(i) + newBranch = M.generateBranchName(issue, suffix=suffix, version=branch) + if not M.git().hasBranch(newBranch): + break + track = '%s/%s' % (C.get('upstreamRemote'), M.get('stablebranch')) + M.git().createBranch(newBranch, track=track) + if not M.git().checkout(newBranch): + debug('Could not checkout branch %s' % (newBranch)) + sys.exit(1) + debug('Checked out branch %s' % (newBranch)) + +# Checkout the stable branch +elif args.integration: + if not M.git().checkout(M.get('stablebranch')): + debug('Could not checkout branch %s' % (M.get('stablebranch'))) + debug('Checked out branch %s' % (M.get('stablebranch'))) + +# Pull branch from tracker +debug('Pulling branch %s from %s into %s' % (remoteBranch, remoteUrl, M.currentBranch())) +M.git().pull(remote=remoteUrl, ref=remoteBranch) + +# Stash pop +if not stash[1].startswith('No local changes'): + pop = M.git().stash(command='pop') + if pop[0] != 0: + debug('An error ocured while unstashing your changes') + else: + debug('Popped the stash') + +debug('Done.') diff --git a/moodle-rebase.py b/moodle-rebase.py index 511b82f..86140d1 100755 --- a/moodle-rebase.py +++ b/moodle-rebase.py @@ -121,7 +121,7 @@ for M in Mlist: pop = M.git().stash(command='pop') if pop[0] != 0: debug('An error ocured while unstashing your changes') - debug(result[2]) + debug(pop[2]) else: debug('Popped the stash') -- 2.11.0