def issues(self, state): # Parameters are not documented, this is from the Gogs issue page URL. # ?type=all&sort=&state=closed&labels=0&milestone=0&assignee=0 # state seems to be the only one which works for api/v1. if state not in ['open', 'closed', 'all']: raise GitIssueError( 'state must be one of "open", "closed", or "all"') issues = [] # Gogs does't not support 'all' so we must iterate over 'open' and # 'closed' states to get all issues. for state in { 'open': ['open'], 'closed': ['closed'], 'all': ['open', 'closed'] }[state]: next_url = '%s/issues' % self.repos_url while next_url: response = get(next_url, headers=self.header, params={'state': state}) if response.status_code == 200: issues += [ GogsIssue(issue, self.repos_url, self.header) for issue in response.json() ] # If a link to the next page of issues present, use it. next_url = response.links['next'][ 'url'] if 'next' in response.links else None else: raise GitIssueError(response) return reversed(sorted(issues))
def edit(self, **kwargs): data = {} title = kwargs.pop('title', None) if title: if not isinstance(title, basestring): raise ValueError('title must be a string') data['title'] = title body = kwargs.pop('body', None) if body: if not isinstance(body, basestring): raise ValueError('body must be a string') data['description'] = body assignee = _check_assignee_(kwargs.pop('assignee', None)) if assignee: data['assignee_ids'] = [assignee.id] labels = _check_labels_(kwargs.pop('labels', [])) if labels: data['labels'] = '' if not any([label.name == 'none' for label in labels]): data['labels'] = [label.name for label in labels] milestone = _check_milestone_(kwargs.pop('milestone', None)) if milestone: data['milestone_id'] = milestone.id response = put(self.issue_url, headers=_headers_(), data=data) if len(data) == 0: raise GitIssueError('aborted edit due to no changes') if response.status_code == 200: return GitLabIssue(response.json(), self.issue_url[:self.issue_url.rfind('/')]) else: raise GitIssueError(response)
def issues(self, state): if state not in ['open', 'closed']: raise GitIssueError('invalid issue state: %s' % state) issues = [] try: # GitLab returns a list of strings for labels, cache labels so we # can get their color CACHE['labels'] = self.labels() except GitIssueError: pass for state in { 'open': ['open'], 'closed': ['closed'], 'all': ['open', 'closed'] }[state]: next_url = self.issues_url while next_url: response = get(next_url, headers=_headers_(), params={ 'state': _encode_state_(state), 'scope': 'all', 'per_page': 100, }) if response.status_code == 200: issues += [ GitLabIssue(issue, self.issues_url) for issue in response.json() ] next_url = response.links['next'][ 'url'] if 'next' in response.links else None else: raise GitIssueError(response) return reversed(sorted(issues))
def issue(self, number): response = get('%s/issues/%s' % (self.repos_url, number), auth=self.auth, headers=self.headers) if response.status_code == 200: return GitHubIssue(response.json(), self.auth, self.headers) else: raise GitIssueError(response) raise GitIssueError('could not find issue: %s' % number)
def edit(self, **kwargs): data = {} # title (string) The title of the issue title = kwargs.pop('title', None) if title: if not isinstance(title, basestring): raise ValueError('title must be a string') data['title'] = title # body (string) The contents of the issue body = kwargs.pop('body', None) if body: if not isinstance(body, basestring): raise ValueError('body must be a string') data['body'] = body # assignee (string) Username for the user that this issue should be # assigned to. assignee = _check_assignee_(kwargs.pop('assignee', None)) if assignee: data['assignee'] = assignee.username # milestone (int) The ID of the milestone to associate this issue with. milestone = _check_milestone_(kwargs.pop('milestone', None)) if milestone: data['milestone'] = milestone.id # labels (array of int) Labels ID to associate with this issue. labels = _check_labels_(kwargs.pop('labels', [])) if len(labels) > 0: data['labels'] = [] if not any([label.name == 'none' for label in labels]): data['labels'] = [label.id for label in labels] if len(data) == 0: raise GitIssueError('aborted edit due to no changes') if 'labels' in data: # NOTE: Work around for Gogs not supporting editing of labels using # the edit issue API, instead use the explicit issue labels API. warn('Gogs does not reliably support repeatedly editing labels ' 'and may fail') labels = data.pop('labels') if len(labels) == 0: # "none" was found in labels, delete all labels for the issue. response = delete('%s/labels' % self.issue_url, headers=self.header) if response.status_code != 204: raise GitIssueError(response) else: # Replace all labels. response = put('%s/labels' % self.issue_url, headers=self.header, json={'labels': labels}) if response.status_code != 200: raise GitIssueError(response) response = patch('%s/%r' % (self.issues_url, self.number), headers=self.header, json=data) if response.status_code == 201: return GogsIssue(response.json(), self.repos_url, self.header) else: raise GitIssueError(response)
def user_search(self, keyword): response = get('%s/users/search' % self.api_url, headers=self.header, params={'q': keyword}) if response.status_code == 200: users = response.json()['data'] else: raise GitIssueError(response) if len(users) == 0: raise GitIssueError('unable to find user: %s' % keyword) return [GogsUser(user) for user in users]
def user_search(self, keyword): response = get(self.users_url, headers=_headers_(), params={'search': keyword}) if response.status_code == 200: users = [GitLabUser(user) for user in response.json()] if len(users) == 0: raise GitIssueError('unable to find user: %s' % keyword) return users else: raise GitIssueError(response)
def close(service, **kwargs): """Close an existing open issue.""" issue = service.issue(kwargs.pop('number')) if issue.state != 'open': raise GitIssueError('issue %s is not open' % issue.number) comment = None if not kwargs['no_message']: if kwargs['message']: comment = kwargs.pop('message') else: comment = '\n'.join(_editor_()) if len(comment.strip()) == 0: raise GitIssueError('aborted due to empty message') issue = issue.close(comment=comment) _finish_('Closed', issue.number, issue.url())
def _comments_(self): response = get('%s/%r/comments' % (self.issues_url, self.number), headers=self.header) if response.status_code == 200: self.cache['comments'] = response.json() else: raise GitIssueError(response)
def labels(self): response = get('%s/labels' % self.repos_url, headers=self.header) if response.status_code == 200: labels = [GogsLabel(label) for label in response.json()] else: raise GitIssueError(response) return labels
def reopen(service, **kwargs): """Reopen an existing closed issue.""" issue = service.issue(kwargs.pop('number')) if issue.state != 'closed': raise GitIssueError('issue %s is not closed' % issue.number) issue = issue.reopen() _finish_('Reopened', issue.number, issue.url())
def issue(self, number): response = get('%s/issues/%s' % (self.repos_url, number), headers=self.header) if response.status_code == 200: return GogsIssue(response.json(), self.repos_url, self.header) else: raise GitIssueError(response)
def create(service, **kwargs): """Create a new issue.""" assignee = _pick_user_(service, kwargs.pop('assignee', None)) milestone = _check_milestone_(service, kwargs.pop('milestone', None)) labels = _check_labels_(service, kwargs.pop('labels', None)) if kwargs['message']: message = kwargs.pop('message').splitline().split('\\n') else: message = _editor_('\n'.join([ '', '<!-- This line will be ignored! Title above, body below. -->', '', '', ])) del message[1] title = message[0] body = '\n'.join(message[1:]) if len(message) > 1 else '' if len(title.strip()) == 0 and len(body.strip()) == 0: raise GitIssueError('aborting due to empty message') issue = service.create(title, body, assignee=assignee, labels=labels, milestone=milestone) _finish_('Created', issue.number, issue.url())
def create(self, title, body, **kwargs): # title (string) The title of the issue # body (string) The contents of the issue if not isinstance(title, basestring): raise ValueError('title must be a string') if not isinstance(body, basestring): raise ValueError('body must be a string') data = {'title': title, 'body': body} # assignee (string) Username for the user that this issue should be # assigned to. assignee = _check_assignee_(kwargs.pop('assignee', None)) if assignee: data['assignee'] = assignee.username # labels (array of int) Labels ID to associate with this issue. labels = _check_labels_(kwargs.pop('labels', [])) if len(labels) > 0: data['labels'] = [label.id for label in labels] # milestone (int) The ID of the milestone to associate this issue with. milestone = _check_milestone_(kwargs.pop('milestone', None)) if milestone: data['milestone'] = milestone.id response = post('%s/issues' % self.repos_url, json=data, headers=self.header) if response.status_code == 201: return GogsIssue(response.json(), self.repos_url, self.header) else: raise GitIssueError(response)
def create(self, title, body, **kwargs): # title (string) Required. The title of the issue. # body (string) The contents of the issue. if not isinstance(title, basestring): raise ValueError('title must be a string') if not isinstance(body, basestring): raise ValueError('body must be a string') data = {'title': title, 'body': body} # assignees (array of strings) Logins for Users to assign to this # issue. assignee = _check_assignee_(kwargs.pop('assignee', None)) if assignee: data['assignees'] = [assignee.username] # milestone (integer) The number of the milestone to associate this # issue with. milestone = _check_milestone_(kwargs.pop('milestone', None)) if milestone: data['milestone'] = milestone.number # labels (array of strings) Labels to associate with this issue. labels = _check_labels_(kwargs.pop('labels', [])) if len(labels) > 0: data['labels'] = [label.name for label in labels] response = post(self.issues_url, auth=self.auth, headers=self.headers, json=data) if response.status_code == 201: return GitHubIssue(response.json(), self.auth, self.headers) else: raise GitIssueError(response)
def comment(self, body): response = post(self.notes_url, headers=_headers_(), data={'body': body}) if response.status_code == 201: return GitLabIssueComment(response.json(), self.number) else: raise GitIssueError(response)
def milestones(self): response = get('%s/milestones' % self.project_url, headers=_headers_()) if response.status_code == 200: return [ GitLabMilestone(milestone) for milestone in response.json() ] else: raise GitIssueError(response)
def reopen(self): response = patch('%s/%r' % (self.issues_url, self.number), headers=self.header, json={'state': 'open'}) if response.status_code == 201: return GogsIssue(response.json(), self.repos_url, self.header) else: raise GitIssueError(response)
def comment(self, body): response = post('%s/%r/comments' % (self.issues_url, self.number), headers=self.header, json={'body': body}) if response.status_code == 201: return GogsIssueComment(response.json(), self.number) else: raise GitIssueError(response)
def milestones(self): response = get('%s/milestones' % self.repos_url, headers=self.header) if response.status_code == 200: milestones = [ GogsMilestone(milestone) for milestone in response.json() ] else: raise GitIssueError(response) return milestones
def reopen(self): response = patch(self.issue_url, auth=self.auth, headers=self.headers, json={'state': 'open'}) if response.status_code == 200: return GitHubIssue(response.json(), self.auth, self.headers) else: raise GitIssueError(response)
def comment(self, body): response = post(self.comments_url, auth=self.auth, headers=self.headers, json={'body': body}) if response.status_code == 201: return GitHubIssueComment(response.json()) else: raise GitIssueError(response)
def user_search(self, keyword): response = get('%s/search/users' % self.api_url, auth=self.auth, headers=self.headers, params={'q': keyword}) if response.status_code == 200: return [GitHubUser(user) for user in response.json()['items']] else: raise GitIssueError(response)
def reopen(self): response = put(self.issue_url, headers=_headers_(), data={'state_event': 'reopen'}) if response.status_code == 200: return GitLabIssue(response.json(), self.issue_url[:self.issue_url.rfind('/')]) else: raise GitIssueError(response)
def events(self): events = [] response = get(self.notes_url, headers=_headers_()) if response.status_code == 200: for note in response.json(): if note['system']: events.append(GitLabIssueEvent(note)) else: raise GitIssueError(response) return events
def edit(self, **kwargs): data = {} # title (string) Required. The title of the issue. title = kwargs.pop('title', None) if title: if not isinstance(title, basestring): raise ValueError('title must be a string') data['title'] = title body = kwargs.pop('body', None) if body: if not isinstance(body, basestring): raise ValueError('body must be a string') data['body'] = body # body (string) The contents of the issue. # assignees (array of strings) Logins for Users to assign to this # issue. assignee = _check_assignee_(kwargs.pop('assignee', None)) if assignee: data['assignees'] = [assignee.username] # milestone (integer) The number of the milestone to associate this # issue with. milestone = _check_milestone_(kwargs.pop('milestone', None)) if milestone: data['milestone'] = None if milestone.title != 'none': data['milestone'] = milestone.number # labels (array of strings) Labels to associate with this issue. labels = _check_labels_(kwargs.pop('labels', [])) if len(labels) > 0: data['labels'] = [] if not any([label.name == 'none' for label in labels]): data['labels'] = [label.name for label in labels] if len(data) == 0: raise GitIssueError('aborted edit due to no changes') response = patch(self.issue_url, auth=self.auth, headers=self.headers, json=data) if response.status_code == 200: return GitHubIssue(response.json(), self.auth, self.headers) else: raise GitIssueError(response)
def comment(service, **kwargs): """Comment on an existing issue.""" issue = service.issue(kwargs.pop('number')) if kwargs['message']: body = kwargs.pop('message') else: body = '\n'.join(_editor_()) if len(body.strip()) == 0: raise GitIssueError('aborted due to empty message') comment = issue.comment(body) _finish_('Commented on', '%s' % issue.number, comment.url())
def get_token(name): """Get basic authentication header from API token. Arguments: :name: Name of the service. """ try: token = get_config('issue.%s.token' % name) except CalledProcessError: raise GitIssueError('failed to get {0} API token, specify using:\n' 'git config issue.{0}.token <token>'.format(name)) return token
def _check_labels_(service, labels): checked = [] if labels: service_labels = service.labels() if any([label == 'none' for label in labels]): return [type(service_labels[0])()] service_labels = {label.name: label for label in service_labels} for label in labels: if label not in service_labels: raise GitIssueError('invalid label name: %s' % label) checked.append(service_labels[label]) return checked
def close(self, **kwargs): comment = kwargs.pop('comment', None) if comment: if not isinstance(comment, basestring): raise ValueError('comment must be a string') self.comment(comment) response = patch('%s/%r' % (self.issues_url, self.number), headers=self.header, json={'state': 'closed'}) if response.status_code == 201: return GogsIssue(response.json(), self.repos_url, self.header) else: raise GitIssueError(response)