def init(self): if self.itdb_exists(): print 'Already initialized issue database in branch \'%s\'.' % \ it.ITDB_BRANCH return # else, initialize the new .it database alongside the .git repo gitrepo = repo.find_git_repo() if not gitrepo: log.printerr('Not a valid Git repository.') else: parent, _ = os.path.split(gitrepo) ticket_dir = os.path.join(parent, it.TICKET_DIR) hold_file = os.path.join(ticket_dir, it.HOLD_FILE) misc.mkdirs(ticket_dir) misc.write_file_contents(hold_file, \ 'This is merely a placeholder file for git-it that prevents ' + \ 'this directory from\nbeing pruned by Git.') # Commit the new itdb to the repo curr_branch = git.current_branch() git.change_head_branch('git-it') git.command_lines('add', [hold_file]) msg = 'Initialized empty ticket database.' git.command_lines('commit', ['-m', msg, hold_file]) os.remove(hold_file) os.rmdir(ticket_dir) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'Initialized empty ticket database.'
def edit(self, sha): i, rel, fullsha, match = self.get_ticket(sha) sha7 = misc.chop(fullsha, 7) # Save the contents of this ticket to a file, so it can be edited i.save(it.EDIT_TMP_FILE) timestamp1 = os.path.getmtime(it.EDIT_TMP_FILE) success = os.system('vim "%s"' % it.EDIT_TMP_FILE) == 0 timestamp2 = os.path.getmtime(it.EDIT_TMP_FILE) if success: if timestamp1 < timestamp2: i = ticket.create_from_file(it.EDIT_TMP_FILE, fullsha, rel) # Now, when the edit has succesfully taken place, switch branches, commit, # and switch back curr_branch = git.current_branch() git.change_head_branch('git-it') msg = 'ticket \'%s\' edited' % sha7 i.save() git.command_lines('commit', ['-m', msg, i.filename()]) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' edited succesfully' % sha7 print '' self.list() else: print 'editing of ticket \'%s\' cancelled' % sha7 else: log.printerr('editing of ticket \'%s\' failed' % sha7) # Remove the temporary file os.remove(it.EDIT_TMP_FILE)
def current_pr(user, base='master'): repo = current_repo(user) branch = git.current_branch() pulls = repo.get_pulls(base=base, head=branch, state='open') try: return pulls[0] except IndexError: return None
def is_current_branch_updated(user): repo = current_repo(user) branch = git.current_branch() try: branch = repo.get_branch(branch) except GithubException: return False if not branch: return False local_sha = git.current_sha() return branch.commit.sha == local_sha
def push(self): auto_stash = False if not pre_push_pull_check(): auto_stash = True if git.stash_push(): print >> sys.stderr, 'Error auto-stashing. Aborting.' sys.exit(1) curr = git.current_branch() os.system('git checkout git-it') os.system('git push origin') os.system('git checkout \'%s\'' % curr) if auto_stash: if git.stash_pop(): print >> sys.stderr, 'There was an error auto-stash popping.'
def push(self): auto_stash = False if not pre_push_pull_check(): auto_stash = True if git.stash_push(): print >>sys.stderr, 'Error auto-stashing. Aborting.' sys.exit(1) curr = git.current_branch() os.system('git checkout git-it') os.system('git push origin') os.system('git checkout \'%s\'' % curr) if auto_stash: if git.stash_pop(): print >>sys.stderr, 'There was an error auto-stash popping.'
def rm(self, sha): match = self.match_or_error(sha) _, basename = os.path.split(match) sha7 = misc.chop(basename, 7) # Commit the new itdb to the repo curr_branch = git.current_branch() git.change_head_branch('git-it') msg = 'removed ticket \'%s\'' % sha7 git.command_lines('commit', ['-m', msg, match], from_root=True) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' removed'% sha7
def leave_ticket(self, sha): i, _, fullsha, match = self.get_ticket(sha) sha7 = misc.chop(sha, 7) curr_branch = git.current_branch() git.change_head_branch('git-it') msg = 'ticket \'%s\' left alone' % sha7 i.assigned_to = '-' i.save() git.command_lines('commit', ['-m', msg, match], from_root=True) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' left alone' % sha7
def rm(self, sha): match = self.match_or_error(sha) _, basename = os.path.split(match) sha7 = misc.chop(basename, 7) # Commit the new itdb to the repo curr_branch = git.current_branch() git.change_head_branch('git-it') msg = 'removed ticket \'%s\'' % sha7 git.command_lines('commit', ['-m', msg, match]) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' removed' % sha7
def pull(self): # check whether this working tree has unstaged/uncommitted changes # in order to prevent data loss from happening auto_stash = False if not pre_push_pull_check(): auto_stash = True if git.stash_push(): print >> sys.stderr, 'Error auto-stashing. Aborting.' # now we may sync the git-it branch safely! curr = git.current_branch() os.system('git checkout git-it') os.system('git pull') os.system('git checkout \'%s\'' % curr) if auto_stash: if git.stash_pop(): print >> sys.stderr, 'There was an error auto-stash popping.'
def pull(self): # check whether this working tree has unstaged/uncommitted changes # in order to prevent data loss from happening auto_stash = False if not pre_push_pull_check(): auto_stash = True if git.stash_push(): print >>sys.stderr, 'Error auto-stashing. Aborting.' # now we may sync the git-it branch safely! curr = git.current_branch() os.system('git checkout git-it') os.system('git pull') os.system('git checkout \'%s\'' % curr) if auto_stash: if git.stash_pop(): print >>sys.stderr, 'There was an error auto-stash popping.'
def take_ticket(self, sha): i, _, fullsha, match = self.get_ticket(sha) sha7 = misc.chop(sha, 7) curr_branch = git.current_branch() git.change_head_branch('git-it') fullname = os.popen('git config user.name').read().strip() msg = 'ticket \'%s\' taken by %s' % (sha7, fullname) i.assigned_to = fullname i.save() git.command_lines('commit', ['-m', msg, match]) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' taken' % sha7 print '' self.list()
def _test_git(): print("===> Testing git...") git = Git() picks = git.get_head_parents("head_parents_test") if len(picks) != 2: print( "--- Something is wrong, the HEAD is not a merge commit! Perhaps you're testing in gira repo?" ) print(picks) git.repo.git.checkout("master") git.repo.git.pull() if git.current_branch() != "master": print("XXX: Current branch should be master") if not git.needs_rebase("rebase_test", "master"): print("XXX: rebase is required") if git.needs_rebase("release-1.1", "release-1"): print("XXX: rebase NOT required") if not "test-remote-branches" in git.remote_branches(): print("XXX: expecting a remote branch 'test-remote-branches'")
def finish_ticket(self, sha, new_status): i, _, fullsha, match = self.get_ticket(sha) sha7 = misc.chop(fullsha, 7) if i.status not in ['open', 'test']: log.printerr('ticket \'%s\' already %s' % (sha7, i.status)) sys.exit(1) # Now, when the edit has succesfully taken place, switch branches, commit, # and switch back curr_branch = git.current_branch() git.change_head_branch('git-it') i.status = new_status msg = '%s ticket \'%s\'' % (i.status, sha7) i.save() git.command_lines('commit', ['-m', msg, match], from_root=True) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' %s' % (sha7, new_status)
def reopen_ticket(self, sha): i, _, fullsha, match = self.get_ticket(sha) sha7 = misc.chop(sha, 7) if i.status == 'open': log.printerr('ticket \'%s\' already open' % sha7) sys.exit(1) # Now, when the edit has succesfully taken place, switch branches, commit, # and switch back curr_branch = git.current_branch() git.change_head_branch('git-it') msg = 'ticket \'%s\' reopened' % sha7 i.status = 'open' i.save() git.command_lines('commit', ['-m', msg, match], from_root=True) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' reopened' % sha7
def mv(self, sha, to_rel): self.require_itdb() i, rel, fullsha, src_path = self.get_ticket(sha) sha7 = misc.chop(fullsha, 7) src_dir = os.path.join(repo.find_root(), it.TICKET_DIR, rel) target_dir = os.path.join(repo.find_root(), it.TICKET_DIR, to_rel) target_path = os.path.join(target_dir, fullsha) if src_dir == target_dir: log.printerr('ticket \'%s\' already in \'%s\'' % (sha7, to_rel)) return # Create the target dir, if neccessary if not os.path.isdir(target_dir): misc.mkdirs(target_dir) # Try to move the file into it try: # Commit the new itdb to the repo curr_branch = git.current_branch() git.change_head_branch('git-it') i.save(target_path) if os.path.isfile(src_path): os.remove(src_path) msg = 'moved ticket \'%s\' (%s --> %s)' % (sha7, rel, to_rel) git.command_lines('add', [target_path]) git.command_lines('commit', ['-m', msg, src_path, target_path]) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' moved to release \'%s\'' % (sha7, to_rel) print '' self.list() except OSError, e: log.printerr('could not move ticket \'%s\' to \'%s\':' % (sha7, to_rel)) log.printerr(e)
def reject_ticket(self, sha, message): i, _, fullsha, match = self.get_ticket(sha) sha7 = misc.chop(sha, 7) if 'rejected' == i.status: log.printerr('ticket \'%s\' already rejected' % sha7) sys.exit(1) if message is None or message == '': message = ticket.ask_for_pattern('Reason for rejection: ', ticket.not_empty) curr_branch = git.current_branch() git.change_head_branch('git-it') i.status = 'rejected' i.body = 'REJECTED: %s\n\n%s' % (message, i.body) msg = '%s ticket \'%s\'' % (i.status, sha7) i.save() git.command_lines('commit', ['-m', msg, match], from_root=True) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' rejected' % sha7
def reject_ticket(self, sha, message): i, _, fullsha, match = self.get_ticket(sha) sha7 = misc.chop(sha, 7) if 'rejected' == i.status: log.printerr('ticket \'%s\' already rejected' % sha7) sys.exit(1) if message is None or message == '': message = ticket.ask_for_pattern( 'Reason for rejection: ', ticket.not_empty) curr_branch = git.current_branch() git.change_head_branch('git-it') i.status = 'rejected' i.body = 'REJECTED: %s\n\n%s' % (message, i.body) msg = '%s ticket \'%s\'' % (i.status, sha7) i.save() git.command_lines('commit', ['-m', msg, match], from_root=True) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' rejected' % sha7
def edit(self, sha): i, rel, fullsha, match = self.get_ticket(sha) sha7 = misc.chop(fullsha, 7) # Save the contents of this ticket to a file, so it can be edited i.save(it.EDIT_TMP_FILE) timestamp1 = os.path.getmtime(it.EDIT_TMP_FILE) # fetch the editor command from the following sources in this order: # - git config --local core.editor # - git config --global core.editor # - git config --system core.editor # - $GIT_EDITOR # - $EDITOR # - /usr/bin/nano success = os.system('%s "%s"' % (git.get_editor(), it.EDIT_TMP_FILE)) == 0 timestamp2 = os.path.getmtime(it.EDIT_TMP_FILE) if success: if timestamp1 < timestamp2: try: i = ticket.create_from_file(it.EDIT_TMP_FILE, fullsha, rel) except ticket.MalformedTicketFieldException, e: print 'Error parsing ticket: %s' % e sys.exit(1) except ticket.MissingTicketFieldException, e: print 'Error parsing ticket: %s' % e sys.exit(1) # Now, when the edit has succesfully taken place, switch branches, commit, # and switch back curr_branch = git.current_branch() git.change_head_branch('git-it') msg = 'ticket \'%s\' edited' % sha7 i.save() git.command_lines('commit', ['-m', msg, i.filename()]) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' edited succesfully' % sha7
def edit(self, sha): i, rel, fullsha, match = self.get_ticket(sha) sha7 = misc.chop(fullsha, 7) # Save the contents of this ticket to a file, so it can be edited i.save(it.EDIT_TMP_FILE) timestamp1 = os.path.getmtime(it.EDIT_TMP_FILE) # fetch the editor command from the following sources in this order: # - git config --local core.editor # - git config --global core.editor # - git config --system core.editor # - $GIT_EDITOR # - $EDITOR # - /usr/bin/nano success = os.system('%s "%s"' % (git.get_editor(),it.EDIT_TMP_FILE)) == 0 timestamp2 = os.path.getmtime(it.EDIT_TMP_FILE) if success: if timestamp1 < timestamp2: try: i = ticket.create_from_file(it.EDIT_TMP_FILE, fullsha, rel) except ticket.MalformedTicketFieldException, e: print 'Error parsing ticket: %s' % e sys.exit(1) except ticket.MissingTicketFieldException, e: print 'Error parsing ticket: %s' % e sys.exit(1) # Now, when the edit has succesfully taken place, switch branches, commit, # and switch back curr_branch = git.current_branch() git.change_head_branch('git-it') msg = 'ticket \'%s\' edited' % sha7 i.save() git.command_lines('commit', ['-m', msg, i.filename()]) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) print 'ticket \'%s\' edited succesfully' % sha7
def new(self): self.require_itdb() # Create a fresh ticket try: i = ticket.create_interactive() except KeyboardInterrupt: print '' print 'aborting new ticket' return None # Generate a SHA1 id s = sha1_constructor() s.update(i.__str__()) s.update(os.getlogin()) s.update(datetime.datetime.now().__str__()) i.id = s.hexdigest() # Save the ticket to disk i.save() _, ticketname = os.path.split(i.filename()) sha7 = misc.chop(ticketname, 7) print 'new ticket \'%s\' saved' % sha7 # Commit the new ticket to the 'aaa' branch curr_branch = git.current_branch() git.change_head_branch('git-it') git.command_lines('add', [i.filename()]) msg = '%s added ticket \'%s\'' % (i.issuer, sha7) git.command_lines('commit', ['-m', msg, i.filename()]) os.remove(i.filename()) git.command_lines('rm', ['--cached', i.filename()]) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) return i
def new(self): self.require_itdb() # Create a fresh ticket try: i = ticket.create_interactive() except KeyboardInterrupt: print '' print 'aborting new ticket' return None # Generate a SHA1 id s = sha1_constructor() s.update(i.__str__()) s.update(os.getenv('LOGNAME')) s.update(datetime.datetime.now().__str__()) i.id = s.hexdigest() # Save the ticket to disk i.save() _, ticketname = os.path.split(i.filename()) sha7 = misc.chop(ticketname, 7) print 'new ticket \'%s\' saved' % sha7 # Commit the new ticket to the 'aaa' branch curr_branch = git.current_branch() git.change_head_branch('git-it') git.command_lines('add', [i.filename()]) msg = '%s added ticket \'%s\'' % (i.issuer, sha7) git.command_lines('commit', ['-m', msg, i.filename()]) os.remove(i.filename()) git.command_lines('rm', ['--cached', i.filename()]) git.change_head_branch(curr_branch) abs_ticket_dir = os.path.join(repo.find_root(), it.TICKET_DIR) git.command_lines('reset', ['HEAD', abs_ticket_dir]) misc.rmdirs(abs_ticket_dir) return i
def diff(user): current_branch = git.current_branch() # Check if we are on master and warn user if current_branch == 'master' and not click.confirm( 'You are on master branch, are you sure you want to continue?'): raise click.ClickException("Switch branches before continuing") # Check for un commited files actions.check_uncommit_files() # Push new commits if needed try: updated = git.update_branch() except RuntimeError as e: raise click.ClickException(str(e)) if updated: click.echo('Pushed changes to remote!') else: click.echo('Branch %s is already updated!' % current_branch) # Check if on master and exit in that case if current_branch == 'master': click.echo('No pull request as you are on master already') return # Try to find existing PR for current branch pr = gh.current_pr(user) # Add comment if wanted if pr and updated and click.confirm( 'Do you want to add comment about current changes in PR?'): MARKER = '# Everything below is ignored. Comment above what are your changes (or leave it blank to skip)' message = click.edit('\n\n' + MARKER) comment = None if message: comment = message.split(MARKER, 1)[0].rstrip('\n') if not comment: click.echo('No comments to be added!') else: pr.create_issue_comment(comment) # Create new Pull request elif not pr: repo = gh.current_repo(user) # Check if it needs a PR c = repo.compare('master', current_branch) if c.total_commits == 0: raise click.ClickException( 'Master and %s are totally synced. Commit some changes to start a PR.' % current_branch) # Get PR title and body MARKER = '# Everything below is ignored. First line is title, after that is body of pull request' message = click.edit('\n\n' + MARKER) comment = None if message: comment = message.split(MARKER, 1)[0].rstrip('\n') lines = comment.split('\n') else: raise click.ClickException('Aborting') body = '\n'.join(lines[1:]).rstrip('\n') pr = repo.create_pull(title=lines[0], body=body, head=current_branch, base='master') # Print current PR URL for user click.echo('Pull request updated, see: %s' % pr.html_url)