From 85a851f1195d6f8ca971e3036d598d79ee05caa2 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Fri, 1 Mar 2019 21:41:03 +0100 Subject: [PATCH] add a merge-and-push command By defult if will: * pull rebase master branch on origin * rebase current feature branch with respect to master * merge feature branch to master * propose to delete copy of feature branch on origin * push master to origin * delete local feature branch --- git_redmine.py | 110 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/git_redmine.py b/git_redmine.py index 590e9d9..e2be7f0 100644 --- a/git_redmine.py +++ b/git_redmine.py @@ -308,6 +308,112 @@ def new(ctx): ctx.invoke(take, issue_number=issue.id) +class MyProgressPrinter(git.RemoteProgress): + def update(self, op_code, cur_count, max_count=None, message=''): + print(op_code, cur_count, max_count, cur_count / (max_count or 100.0), message or "NO MESSAGE") + + +@redmine.command(name='merge-and-push') +@click.argument('target_branch', default='master') +def merge_and_pus(target_branch): + repo = get_repo() + origin = repo.remote() + + if repo.head.is_detached: + raise click.UsageError('Your cannot merge from a detached HEAD.') + + if repo.is_dirty(): + raise click.UsageError('Your cannot merge, your repo is dirty.') + + current_head = repo.head.ref.name + + if current_head == target_branch: + raise click.UsageError('Your cannot merge on %s as your are already on it.') + + try: + repo.branches[target_branch] + except IndexError: + raise click.UsageError('%r is not a local branch.' % target_branch) + + try: + click.echo(u'Checking-out branch « %s » ... ' % target_branch, nl=False) + repo.branches[target_branch].checkout() + click.echo(click.style('Done.', fg='green')) + click.echo(u'Pull-rebasing from remote « %s » onto branch « %s » ... ' % (origin.name, target_branch), nl=False) + failure = False + for pi in origin.pull(rebase=True): + if pi.flags & pi.ERROR: + failure = True + click.echo(click.style(u'Pull-rebase from « %s » failed: %s.' % ( + pi.ref.name, pi.note), fg='red')) + click.echo(click.style('Done.', fg='green')) + if failure: + raise click.ClickException('Pull rebase failed.') + finally: + click.echo(u'Checking-out branch « %s »... ' % current_head, nl=False) + repo.branches[current_head].checkout() + click.echo(click.style('Done.', fg='green')) + + try: + click.echo(u'Rebasing branch « %s » onto branch « %s » ... ' % (current_head, target_branch), nl=False) + repo.git.rebase(target_branch) + except git.GitCommandError as e: + click.echo(click.style('command %r failed, aborting.' % e.command, fg='red')) + try: + repo.git.rebase(abort=True) + except git.GitCommandError as e: + click.echo(click.style('rebase abort failed, %s\n%s.' % (e.stdout, e.stderr), fg='red')) + raise click.Abort() + click.echo(click.style('Done.', fg='green')) + try: + click.echo('Checking-out to %s... ' % target_branch, nl=False) + repo.branches[target_branch].checkout() + click.echo(click.style('Done.', fg='green')) + click.echo(u'Merging branch « %s » into « %s » ... ' % (current_head, target_branch), nl=False) + try: + repo.git.merge(current_head, ff=True) + except git.GitCommandError as e: + click.echo(click.style('command %r failed, aborting.' % e.command, fg='red')) + try: + repo.git.merge(abort=True) + except git.GitCommandError as e: + click.echo(click.style('merge abort failed, %s\n%s.' % (e.stdout, e.stderr), fg='red')) + raise click.Abort() + + click.echo(click.style('Done.', fg='green')) + try: + origin.refs[current_head] + except IndexError: + pass + else: + if click.confirm(u'Do you want to delete feature branch « %s » on remote « %s » ?' % ( + current_head, origin.name)): + for pi in origin.push(refspec=':%s' % current_head): + if pi.flags & pi.ERROR: + click.echo(click.style(u'Push from « %s » to « %s » failed.' % ( + pi.local_ref.name, pi.remote_ref.name, pi.summary), fg='red')) + if click.confirm(u'Do you want to push « %s » on remote « %s » ?' % (target_branch, repo.remote().name)): + for pi in origin.push(): + if pi.flags & pi.ERROR: + click.echo(click.style(u'Push from « %s » to « %s » failed: %s.' % ( + pi.local_ref.name, pi.remote_ref.name, pi.summary), fg='red')) + if click.confirm(u'Do you want to delete feature branch « %s » ?' % current_head): + repo.delete_head(repo.branches[current_head]) + else: + repo.branches[current_head].checkout() + except Exception: + click.echo(click.style(u'\nFailure going back to branch « %s ».' % current_head, fg='red')) + repo.branches[current_head].checkout() + raise + + +@issue.command(name='open') +@click.option('--issue', default=None, type=int) +def _open(issue): + issue = get_issue(issue) + subprocess.call(['xdg-open', issue.url]) + + @project.command() @click.argument('project_id') def set(project_id): @@ -315,9 +421,9 @@ def set(project_id): api = get_redmine_api() try: api.project.get(project_id) - except: + except Exception: raise click.UsageError('Project %s is unknown' % project_id) - repo = git.Repo() + repo = get_repo() config_writer = repo.config_writer() if not config_writer.has_section('redmine'): config_writer.add_section('redmine')