def log(self, opts): """[<repo>] Display GitLab log for a repository""" repo = self.repository(opts) if not repo: return now = datetime.datetime.now() for event in reversed(repo.Event()): ts = datetime.datetime.strptime(event.created_at, '%Y-%m-%dT%H:%M:%S.%fZ') event.data = event.data or {} if ts.year == now.year: if (ts.month, ts.day) == (now.month, now.day): ts = wrap(ts.strftime("%H:%M"), attr.faint) else: ts = wrap(ts.strftime("%m/%d %H:%M"), attr.faint) else: ts = wrap(ts.strftime("%Y/%m/%d %H:%M"), attr.faint) if event.action_name == 'joined': print('%s %s joined' % (ts, event.author_username)) elif event.target_type == 'Issue': issue = glapi.ProjectIssue(self.gl, event.target_id, project_id=event.project_id) print('%s %s %s issue %s (%s)' % (ts, event.author_username, event.action_name, issue.iid, issue.title)) elif event.target_type == 'MergeRequest': issue = glapi.ProjectMergeRequest(self.gl, event.target_id, project_id=event.project_id) print('%s %s %s merge request %s (%s)' % (ts, event.author_username, event.action_name, issue.iid, issue.title)) elif event.target_type == 'Note': print('%s %s created a comment' % (ts, event.author_username)) elif 'total_commits_count' in event.data: if event.data['total_commits_count'] == 0: print('%s %s deleted branch %s' % (ts, event.author_username, event.data['ref'][11:])) else: print('%s %s pushed %s commits to %s' % (ts, event.author_username, event.data['total_commits_count'], event.data['ref'][11:])) elif 'ref' in event.data: print('%s %s created tag %s' % (ts, event.author_username, event.data['ref'][10:])) else: print( wrap( "Cannot display event. Please file a bug at github.com/seveas/git-spindle\nincluding the following output:", attr.bright)) pprint(event.json())
def merge_request(self, opts): """[--yes] [<yours:theirs>] Opens a merge request to merge your branch to an upstream branch""" repo = self.repository(opts) parent = self.parent_repo(repo) or repo # Which branch? src = opts['<yours:theirs>'] or '' dst = None if ':' in src: src, dst = src.split(':', 1) if not src: src = self.gitm('rev-parse', '--abbrev-ref', 'HEAD').stdout.strip() if not dst: dst = parent.default_branch if src == dst and parent == repo: err("Cannot file a merge request on the same branch") # Try to get the local commit commit = self.gitm('show-ref', 'refs/heads/%s' % src).stdout.split()[0] # Do they exist on GitLab? try: srcb = repo.Branch(src) except glapi.GitlabGetError: srcb = None if self.question( "Branch %s does not exist in your GitLab repo, shall I push?" % src): self.gitm('push', repo.remote, src, redirect=False) else: err("Aborting") if srcb and srcb.commit.id != commit: # Have we diverged? Then there are commits that are reachable from the GitLab branch but not local diverged = self.gitm('rev-list', srcb.commit.id, '^' + commit) if diverged.stderr or diverged.stdout: if self.question( "Branch %s has diverged from GitLab, shall I push and overwrite?" % src, default=False): self.gitm('push', '--force', repo.remote, src, redirect=False) else: err("Aborting") else: if self.question( "Branch %s not up to date on GitLab, but can be fast forwarded, shall I push?" % src): self.gitm('push', repo.remote, src, redirect=False) else: err("Aborting") dstb = parent.Branch(dst) if not dstb: err("Branch %s does not exist in %s/%s" % (dst, parent.namespace.path, parent.path)) # Do we have the dst locally? for remote in self.gitm('remote').stdout.strip().split("\n"): url = self.gitm('config', 'remote.%s.url' % remote).stdout.strip() if url in [parent.ssh_url_to_repo, parent.http_url_to_repo]: if not parent.public and url != parent.ssh_url_to_repo: err("You should configure %s/%s to fetch via ssh, it is a private repo" % (parent.namespace.path, parent.path)) self.gitm('fetch', remote, redirect=False) break else: err("You don't have %s/%s configured as a remote repository" % (parent.namespace.path, parent.path)) # How many commits? accept_empty_body = False commits = try_decode( self.gitm('log', '--pretty=%H', '%s/%s..%s' % (remote, dst, src)).stdout).strip().split() commits.reverse() if not commits: err("Your branch has no commits yet") # 1 commit: title/body from commit if len(commits) == 1: title, body = self.gitm( 'log', '--pretty=%s\n%b', '%s^..%s' % (commits[0], commits[0])).stdout.split('\n', 1) title = title.strip() body = body.strip() accept_empty_body = not bool(body) # More commits: title from branchname (titlecased, s/-/ /g), body comments from shortlog else: title = src if '/' in title: title = title[title.rfind('/') + 1:] title = title.title().replace('-', ' ') body = "" body += """ # Requesting a merge from %s/%s into %s/%s # # Please enter a message to accompany your merge request. Lines starting # with '#' will be ignored, and an empty message aborts the request. #""" % (repo.namespace.path, src, parent.namespace.path, dst) body += "\n# " + try_decode( self.gitm('shortlog', '%s/%s..%s' % (remote, dst, src)).stdout).strip().replace( '\n', '\n# ') body += "\n#\n# " + try_decode( self.gitm('diff', '--stat', '%s^..%s' % (commits[0], commits[-1])).stdout).strip().replace( '\n', '\n#') title, body = self.edit_msg("%s\n\n%s" % (title, body), 'MERGE_REQUEST_EDIT_MSG') if not body and not accept_empty_body: err("No merge request message specified") try: merge = glapi.ProjectMergeRequest( self.gl, { 'project_id': repo.id, 'target_project_id': parent.id, 'source_branch': src, 'target_branch': dst, 'title': title, 'description': body }) merge.save() print("merge request %d created %s" % (merge.iid, self.merge_url(merge))) except: filename = self.backup_message(title, body, 'merge-request-message-') err("Failed to create a merge request, the merge request text has been saved in %s" % filename)