Пример #1
0
def show(globs: AttrDict, full: bool, patch: bool, patch_only: bool,
         browse: bool, bugs: List[int]):
    """Displaying bugs."""
    results = []
    tmpl = template.get_template('view', '/issue.txt')
    for bug_no in bugs:
        if browse:
            click.launch('https://github.com/{}/issues/{:d}'.format(
                globs.project, bug_no))
            continue
        r, bug = globs.req_get(bug_no, model='Issue')

        if full and bug.comments:
            r, comments = globs.req_get('{}/comments'.format(bug_no),
                                        model='Comment')
        else:
            comments = []
        if (patch or patch_only) and bug.pull_request:
            url = '{}/repos/{}/pulls/{}'.format(globs.host_url, globs.project,
                                                bug_no)
            headers = {'Accept': 'application/vnd.github.patch'}
            r, c = globs.req_get(url, headers=headers, is_json=False)
            patch = c.decode('utf-8')
        else:
            patch = None
        results.append(tmpl.render(bug=bug, comments=comments, full=True,
                                   patch=patch, patch_only=patch_only,
                                   project=globs.repo_obj()))
    if results:
        utils.pager('\n'.join(results), pager=globs.pager)
Пример #2
0
def list_bugs(globs: AttrDict, label: List[str], page: int,
              pull_requests: bool, order: str, state: str):
    """Listing bugs."""
    bugs = []
    params = {}
    if pull_requests:
        # FIXME: Dirty solution to supporting PRs only, needs rethink
        url = '{}/repos/{}/pulls'.format(globs.host_url, globs.project)
    else:
        url = ''
    if page != 1:
        params['page'] = page
    if label:
        params['labels'] = ','.join(label)

    states = ['open', 'closed'] if state == 'all' else [state, ]
    for state in states:
        _params = params.copy()
        _params['state'] = state
        r, _bugs = globs.req_get(url, params=_params, model='Issue')
        bugs.extend(_bugs)

    result = template.display_bugs(bugs, order, state=state,
                                   project=globs.repo_obj())
    if result:
        utils.pager(result, pager=globs.pager)
Пример #3
0
def milestones(globs: AttrDict, order: str, state: str, create: str,
               list: bool):
    """Repository milestones."""
    if not list and not create:
        fail('No action specified!')
        return 1
    milestones_url = '{}/repos/{}/milestones'.format(globs.host_url,
                                                     globs.project)
    r, milestones = globs.req_get(milestones_url, model='Milestone')

    if list:
        tmpl = template.get_template('view', '/list_milestones.txt')
        columns = utils.T.width if utils.T.width else 80
        max_id = max(i.number for i in milestones)
        id_len = len(str(max_id))

        result = tmpl.render(milestones=milestones, order=order, state=state,
                             project=globs.repo_obj(),
                             id_len=id_len, max_title=columns - id_len - 2)
        if result:
            utils.pager(result, pager=globs.pager)
    elif create:
        data = {'title': create}
        r, milestone = globs.req_post('', body=data, model='Milestone')
        success('Milestone {:d} created'.format(milestone.number))
Пример #4
0
def comment(globs: AttrDict, message: str, stdin: bool, bugs: List[int]):
    """Commenting on bugs."""
    if stdin:
        message = click.get_text_stream().read()
    elif message:
        message = message
    else:
        message = template.edit_text()
    for bug in bugs:
        globs.req_post('{}/comments'.format(bug), body={'body': message},
                       model='Comment')
Пример #5
0
class InvalidKeyTest(TestCase):
    def setUp(self):
        self.ad = AttrDict(carrots=3, snacks=0)

    def test_invalid_key_set(self):
        with expect.raises(AttributeError):
            self.ad.__setattr__({True: False}, None)

    def test_invalid_key_delete(self):
        with expect.raises(AttributeError):
            self.ad.__delattr__({True: False})
Пример #6
0
def reopen(globs: AttrDict, stdin: bool, message: str, bugs: List[int]):
    """Reopening closed bugs."""
    if stdin:
        message = click.get_text_stream().read()
    elif not message:
        try:
            message = template.edit_text()
        except template.EmptyMessageError:
            # Message isn't required for reopening, but it is good practice
            message = None
    for bug in bugs:
        if message:
            globs.req_post('{}/comments'.format(bug), body={'body': message},
                           model='Comment')
        globs.req_post(bug, body={'state': 'open'}, model='Issue')
Пример #7
0
def milestone(globs: AttrDict, milestone: str, bugs: List[int]):
    """Issue milestones."""
    milestones_url = '{}/repos/{}/milestones'.format(globs.host_url,
                                                     globs.project)
    r, milestones = globs.req_get(milestones_url, model='Milestone')

    milestone_mapping = dict((m.title, m.number) for m in milestones)

    try:
        milestone = milestone_mapping[milestone]
    except KeyError:
        raise ValueError('No such milestone {:!r}'.format(milestone))

    for bug_no in bugs:
        globs.req_post(bug_no, body={'milestone': milestone},
                       model='Milestone')
Пример #8
0
def munge(dct: Dict) -> AttrDict:
    dct = AttrDict(**dct)
    if 'start' in dct:
        dct.start = parse_datetime(dct.start)
    if 'end' in dct:
        dct.end = parse_datetime(dct.end)
    return dct
Пример #9
0
def setup(globs: AttrDict, local: bool):
    """Setup GitHub access token."""
    if not utils.SYSTEM_CERTS:
        warn('Falling back on bundled certificates')
    if utils.CURL_CERTS:
        warn('Using certs specified in $CURL_CERTS')
    default_user = os.getenv('GITHUB_USER',
                             utils.get_git_config_val('github.user',
                                                      getpass.getuser()))
    user = click.prompt('GitHub user', default_user)
    if not user:
        user = default_user
    password = click.prompt('GitHub password', hide_input=True,
                            confirmation_prompt=False)

    private = click.confirm('Support private repositories')

    data = {
        'scopes': ['repo' if private else 'public_repo'],
        'note': 'hubugs',
        'note_url': 'https://github.com/JNRowe/hubugs'
    }

    # Unfortunately, we need to forcibly define the header to workaround
    # GitHub sending a 404(in an effort to stop information leakage)
    header = {
        'Authorization': 'Basic ' + b64encode(':'.join([user, password]))
    }
    r, auth = globs.req_post('https://api.github.com/authorizations',
                             body=data, headers=header, model='Authorisation',
                             token=False)
    utils.set_git_config_val('hubugs.token', auth.token, local)
    success('Configuration complete!')
Пример #10
0
def search(globs: AttrDict, order: str, state: str, term: str):
    """Searching bugs."""
    search_url = '{}/search/issues'.format(globs.host_url)
    states = ['open', 'closed'] if state == 'all' else [state, ]
    params = {
        'q': term,
        'repo': globs.project,
    }
    bugs = []
    for state in states:
        params['state'] = state
        r, c = globs.req_get(search_url, params=params, model='issue')
        bugs.extend(c.issues)
    result = template.display_bugs(bugs, order, term=term, state=state,
                                   project=globs.repo_obj())
    if result:
        utils.pager(result, pager=globs.pager)
Пример #11
0
def label(globs: AttrDict, add: List[str], create: List[str],
          remove: List[str], list: bool, bugs: List[int]):
    """Labelling bugs."""
    label_names = utils.sync_labels(globs, add, create)

    if list:
        click.echo(', '.join(sorted(label_names)))
        return

    for bug_no in bugs:
        r, bug = globs.req_get(bug_no, model='Issue')
        labels = [label.name for label in bug.labels]
        labels.extend(add + create)

        for string in remove:
            labels.remove(string)
        globs.req_post(bug_no, body={'labels': labels}, model='Label')
Пример #12
0
def edit(globs: AttrDict, stdin: bool, title: str, body:str, bugs: List[int]):
    """Editing bugs."""
    if (title or stdin) and len(bugs) > 1:
        raise ValueError('Can not use --stdin or command line title/body '
                         'with multiple bugs')
    for bug in bugs:
        if stdin:
            text = click.get_text_stream().readlines()
        elif not title:
            r, current = globs.req_get(bug, model='Issue')
            current_data = {'title': current.title, 'body': current.body}
            text = template.edit_text('open', current_data).splitlines()
        if stdin or not title:
            title = text[0]
            body = '\n'.join(text[1:])
        else:
            title = title
            body = body

        data = {'title': title, 'body': body}
        globs.req_post(bug, body=data, model='Issue')
Пример #13
0
def report_bug(globs: AttrDict):
    """Report a new bug against hubugs."""
    local = globs.project == 'JNRowe/hubugs'
    globs.project = 'JNRowe/hubugs'

    import html2text, jinja2, pygments  # NOQA: E401
    versions = dict([(m.__name__, getattr(m, '__version__', 'No version info'))
                     for m in (click, html2text, httplib2, jinja2, pygments)])
    data = {
        'local': local,
        'sys': sys,
        'version': _version.dotted,
        'versions': versions,
        'certs': utils.CA_CERTS,
    }
    text = template.edit_text('hubugs_report', data).splitlines()
    title = text[0]
    body = '\n'.join(text[1:])

    data = {'title': title, 'body': body}
    r, bug = globs.req_post('', body=data, model='Issue')
    success('Bug {:d} opened against hubugs, thanks!'.format(bug.number))
Пример #14
0
def munge(dct: Dict[str, str]) -> AttrDict:
    dct = AttrDict(**dct)
    if 'text' in dct:
        dct.text = html.escape(dct.text)
        for pat, repl in HTML_FILTERS.items():
            dct.text = pat.sub(repl, dct.text)
        for pat, repl in ABBREVS.items():
            dct.text = pat.sub(repl, dct.text)
        dct.text = dct.text.replace('\N{STX}', '<').replace('\N{ETX}', '>')
    if 'timestamp' in dct:
        dct.timestamp = parse_rfc3339(dct.timestamp)
    if 'self' in dct:
        dct.self = parse_rfc3339(dct.self)
    return dct
Пример #15
0
def open_bug(globs: AttrDict, add: List[str], create: List[str], stdin: bool,
             title: str, body: str):
    """Opening new bugs."""
    utils.sync_labels(globs, add, create)
    if stdin:
        text = click.get_text_stream('stdin').readlines()
    elif not title:
        text = template.edit_text('open').splitlines()
    if stdin or not title:
        title = text[0]
        body = '\n'.join(text[1:])
    else:
        title = title
        body = body
    data = {'title': title, 'body': body, 'labels': add + create}
    r, bug = globs.req_post('', body=data, model='Issue')
    success('Bug {:d} opened'.format(bug.number))
Пример #16
0
with open('data/µnotes.json') as f:
    notes = json.load(f, object_hook=AttrDict)

with open('data/config.json') as f:
    config = json.load(f, object_hook=AttrDict)

feed = AttrDict(
    version='https://jsonfeed.org/version/1.1',
    title='James Rowe',
    icon='https://micro.blog/JNRowe/avatar.jpg',
    home_page_url='https://jnrowe.github.com/mnotes/',
    feed_url='https://jnrowe.github.com/mnotes/feed.json',
    description=config.subtitle,
    authors=[
        {
            'name': config.author.name,
            'url': config.author.uri,
            'avatar': 'https://jnrowe.github.com/mnotes/avatar.png',
        },
    ],
    language='en',
    items=[]
)

for note, post in list(zip(reversed(notes),
                           page.getroot().cssselect('.note')))[:15]:
    loc = '%s#TS%s' % (config.url, note.timestamp)
    content = html.tostring(post, True).decode()
    content = content.strip().replace('\n', '')
    item = AttrDict(
Пример #17
0
 def setUp(self):
     self.ad = AttrDict(carrots=3, snacks=0)