Generate release notes.

def release(obj, commit='HEAD', components=False):
    """Generate release notes."""
    options = obj.options
    repository = obj.repository

    try:
        sha = 'oid'
        commits = _pygit2_commits(commit, repository)
    except ImportError:
        try:
            sha = 'hexsha'
            commits = _git_commits(commit, repository)
        except ImportError:
            click.echo('To use this feature, please install pygit2. '
                       'GitPython will also work but is not recommended '
                       '(python <= 2.7 only).', file=sys.stderr)
            return 2

    messages = OrderedDict([(getattr(c, sha), c.message) for c in commits])

    for commit_sha1 in amended_commits(messages):
        if commit_sha1 in messages:
            del messages[commit_sha1]

    full_messages = list(
        enrich_git_log_dict(messages, options.get('commit_msg_labels'))
    )
    indent = '  ' if components else ''
    wrapper = textwrap.TextWrapper(
        width=70,
        initial_indent=indent + '- ',
        subsequent_indent=indent + '  ',
    )

    for label, section in options.get('commit_msg_labels'):
        if section is None:
            continue
        bullets = []
        for commit in full_messages:
            bullets += [
                {'text': bullet, 'component': commit['component']}
                for lbl, bullet in commit['paragraphs']
                if lbl == label and bullet is not None
            ]
        if len(bullets) > 0:
            click.echo(section)
            click.echo('~' * len(section))
            click.echo()
            if components:
                def key(cmt):
                    return cmt['component']

                for component, bullets in itertools.groupby(
                        sorted(bullets, key=key), key):
                    bullets = list(bullets)
                    if len(bullets) > 0:
                        click.echo('+ {}'.format(component))
                        click.echo()
                    for bullet in bullets:
                        click.echo(wrapper.fill(bullet['text']))
                    click.echo()
            else:
                for bullet in bullets:
                    click.echo(wrapper.fill(bullet['text']))
            click.echo()

    return 0