示例#1
0
def update_labels(source_repo, service, source_service, destination):
    """
    Update labels for the selected repository, default to repo in $PWD
    """
    app = App()
    url = app.guess_remote_url()
    git_project = app.get_git_project(url)
    try:
        repo_labels = git_project.get_labels()
    except AttributeError:
        click.echo(
            f"Project {git_project.__class__.__name__} does not support repository-wide labels.",
            err=True,
        )
        sys.exit(2)
    if not repo_labels:
        print("No labels.")
        return

    for repo_for_copy in destination:
        other_serv = app.get_service(service, repo=repo_for_copy)
        changes = other_serv.update_labels(labels=repo_labels)

        click.echo(
            "{changes} labels of {labels_count} copied to {repo_name}".format(
                changes=changes, labels_count=len(repo_labels), repo_name=repo_for_copy
            )
        )
示例#2
0
def get_changes(lower_bound, upper_bound):
    """
    Get changelog-like changes in a commit range
    """
    app = App()
    url = app.guess_remote_url()
    git_project = app.get_git_project(url)
    commits = get_commits_in_range(lower_bound=lower_bound, upper_bound=upper_bound)
    reg = re.compile(r"Merge pull request #(\d+) from (\w+)/\w+")

    for com in commits:
        # we could get all the commit messages in a single git call,
        # but parsing that would be pretty hard and prone to errors
        commit_metadata = get_commit_metadata(com)
        match = reg.match(commit_metadata.message)
        if match:
            pr_id = match.group(1)
            author = match.group(2)

            pr = git_project.get_pr(int(pr_id))

            print(
                f"* {commit_metadata.body}, by [@{author}](https://github.com/{author}), "
                f"[#{pr_id}](https://github.com/{git_project.namespace}"
                f"/{git_project.repo}/pull/{pr_id})"
            )
            print(f"  * description: {pr.description!r}")
            for m_commit in get_commits_in_a_merge(com):
                m = get_commit_metadata(m_commit)
                print(f"  * commit: {m.message}")

        else:
            print(f"* {commit_metadata.message}")
示例#3
0
def fork(service, repo):
    """
    Fork selected repository
    """
    a = App()
    s = a.get_service(service)
    s.fork(repo)
示例#4
0
def create_pr(target_remote, target_branch):
    """
    Create a pull or a merge request against upstream remote.

    The default projects's branch is used implicitly
    (which everyone can configure in their project settings).
    """
    app = App()

    url = app.guess_remote_url()
    git_project = app.get_git_project(url)

    username = git_project.service.user.get_username()

    if not target_branch:
        target_branch = git_project.default_branch
        logger.info(f"Branch not specified, using {target_branch}.")

    base = "{}/{}".format(target_remote, target_branch)

    git_push()

    title, body = prompt_for_pr_content(get_commit_msgs(base))

    pr = git_project.create_pr(title,
                               body,
                               target_branch,
                               app.get_current_branch(),
                               fork_username=username)

    logger.info("PR link: %s", pr.url)
    print(pr.url)
示例#5
0
def remove_merged_branches(merged_with_branch):
    """
    Remove branches which are already merged (in master by default)

    Argument MERGED_WITH_BRANCH defaults to master and checks whether
    a branch was merged with this one
    """
    a = App()
    to_remove = []
    for branch_dict in a.list_branches(merged_with_branch):
        branch_name = branch_dict["name"]
        if branch_name == merged_with_branch or branch_name == branch_dict["remote_tracking"]:
            # don't remove self or a local copy of remote branch
            continue
        if branch_dict["merged"] == "merged":
            to_remove.append(branch_name)
    if not to_remove:
        print("Nothing to remove.")
        return
    print("Shall we remove these local branches?")
    for b in to_remove:
        print(f"* {b}")
    inp = input("Y/N? ")
    if inp in ("y", "Y", "yolo"):
        print("Removing...")
        for b in to_remove:
            a.remove_branch(b)
    else:
        print("Doing nothing, stay safe my friend.")
示例#6
0
def fork(repo):
    """
    Fork selected repository
    """
    app = App()

    target_repo_org, target_repo_name = repo.split("/", 1)
    # let's default to github if there is only 1 slash in repo

    if "/" in target_repo_name:
        git_project = app.get_git_project(repo)
    else:
        git_project = app.get_git_project(f"https://github.com/{repo}")
    username = git_project.service.user.get_username()
    forked_repo = git_project.fork_create()
    # FIXME: haxxxxx
    forked_repo.repo = target_repo_name
    forked_repo.namespace = username

    forked_repo_ssh_url = forked_repo.get_git_urls()["ssh"]

    clone_repo_and_cd_inside(target_repo_name, forked_repo_ssh_url, target_repo_org)

    set_upstream_remote(
        clone_url=git_project.get_git_urls()["git"],
        ssh_url=git_project.get_git_urls()["ssh"],
        pull_merge_name="pull",
    )
    set_origin_remote(forked_repo_ssh_url, pull_merge_name="pull")
    fetch_all()
示例#7
0
def create_pr(target_remote, target_branch):
    """
    Fork selected repository
    """
    a = App()
    s = a.guess_service(remote=target_remote)
    pr_url = s.create_pull_request(target_remote, target_branch, a.get_current_branch())
    print(pr_url)
示例#8
0
def list_branches(merged_with, remote):
    """
    List git branches in current git repository
    """
    a = App()
    print(
        tabulate(
            a.list_branches(merged_with=merged_with, remote=remote),
            tablefmt="fancy_grid",
        ))
示例#9
0
def list_tags(repo):
    """
    List the tags for the selected repository, default to repo in $PWD
    """
    app = App()
    url = repo or app.guess_remote_url()
    git_project = app.get_git_project(url)
    repo_tags = git_project.get_tags()
    if not repo_tags:
        print("No tags.")
        return
    print(
        tabulate([(tag.name, tag.commit_sha) for tag in repo_tags],
                 tablefmt="fancy_grid"))
示例#10
0
def list_prs(repo):
    """
    List pull requests of a selected repository, default to repo in $PWD
    """
    app = App()
    url = repo or app.guess_remote_url()
    git_project = app.get_git_project(url)
    prs = git_project.get_pr_list()
    if not prs:
        print("No open pull requests.")
        return
    print(
        tabulate(
            [("#%s" % pr.id, pr.title, "@%s" % pr.author, pr.url) for pr in prs],
            tablefmt="fancy_grid",
        )
    )
示例#11
0
def create_pr(target_remote, target_branch):
    """
    Create a pull or a merge request against upstream remote.

    The default projects's branch is used implicitly
    (which everyone can configure in their project settings).
    """
    app = App()

    url = app.guess_remote_url()
    git_project = app.get_git_project(url)

    username = git_project.service.user.get_username()

    if not target_branch:
        target_branch = git_project.default_branch
        logger.info(f"Branch not specified, using {target_branch}.")

    base = "{}/{}".format(target_remote, target_branch)

    git_push()

    commit_msgs = get_commit_msgs(base)
    project_pr_template = None
    if "github.com" in git_project.get_web_url():
        try:
            project_pr_template = git_project.get_file_content(
                ".github/PULL_REQUEST_TEMPLATE.md"
            )
        except FileNotFoundError:
            logger.debug("No PR template found.")
    template = assemble_pr_template(
        commit_msgs, project_pr_template=project_pr_template
    )

    title, body = prompt_for_pr_content(template)

    pr = git_project.create_pr(
        title, body, target_branch, app.get_current_branch(), fork_username=username
    )

    logger.info("PR link: %s", pr.url)
    print(pr.url)
示例#12
0
def list_tags(service, repo):
    """
    List the tags for the selected repository, default to repo in $PWD
    """
    app = App()
    if repo:
        serv = app.get_service(service, repo=repo)
    else:
        serv = app.guess_service()
    repo_tags = serv.list_tags()
    if not repo_tags:
        print("No tags.")
        return
    print(tabulate([
        (
            tag['name'],
            tag['url']
        )
        for tag in repo_tags
    ], tablefmt="fancy_grid"))
示例#13
0
def list_labels(service, repo):
    """
    List the labels for the selected repository, default to repo in $PWD
    """
    app = App()
    if repo:
        serv = app.get_service(service, repo=repo)
    else:
        serv = app.guess_service()
    repo_labels = serv.list_labels()
    if not repo_labels:
        print("No labels.")
        return
    print(tabulate([
        (
            label.name,
            label.color,
            label.description
        )
        for label in repo_labels
    ], tablefmt="fancy_grid"))
示例#14
0
def list_prs(service, repo):
    """
    List pull requests of a selected repository, default to repo in $PWD
    """
    a = App()
    if repo:
        s = a.get_service(service, repo=repo)
    else:
        s = a.guess_service()
    prs = s.list_pull_requests()
    if not prs:
        print("No open pull requests.")
        return
    print(tabulate([
        (
            "#%s" % pr['id'],
            pr['title'],
            "@%s" % pr['author'],
            pr['url']
        )
        for pr in prs
    ], tablefmt="fancy_grid"))
示例#15
0
def update_labels(source_repo, service, source_service, destination):
    """
    Update labels for the selected repository, default to repo in $PWD
    """
    app = App()
    if source_repo:
        serv = app.get_service(source_service, repo=source_repo)
    else:
        serv = app.guess_service()
    repo_labels = serv.list_labels()
    if not repo_labels:
        print("No labels.")
        return

    for repo_for_copy in destination:
        other_serv = app.get_service(service, repo=repo_for_copy)
        changes = other_serv.update_labels(labels=repo_labels)

        click.echo("{changes} labels of {labels_count} copied to {repo_name}".format(
            changes=changes,
            labels_count=len(repo_labels),
            repo_name=repo_for_copy
        ))
示例#16
0
def list_labels(repo):
    """
    List the labels for the selected repository, default to repo in $PWD
    """
    app = App()
    url = repo or app.guess_remote_url()
    git_project = app.get_git_project(url)
    try:
        repo_labels = git_project.get_labels()
    except AttributeError:
        click.echo(
            f"We don't support repository-wide labels for type {git_project.__class__.__name__}.",
            err=True,
        )
        sys.exit(2)
    if not repo_labels:
        print("No labels.")
        return
    print(
        tabulate(
            [(label.name, label.color, label.description) for label in repo_labels],
            tablefmt="fancy_grid",
        )
    )
示例#17
0
def status(with_pr_comments):
    """
    Get information about project. If not on master,
    figure out if the branch is associated with a PR and get status of that PR.
    """
    app = App()
    url = app.guess_remote_url()
    git_project = app.get_git_project(url)

    pr = app.get_current_branch_pr(git_project)
    if pr:
        click.echo(f"#{pr.id} ", nl=False)
        click.echo(click.style(pr.title, fg="white"), nl=False)
        click.echo(", by @", nl=False)
        click.echo(click.style(pr.author, bold=True))
        if len(pr.description) > 255:
            click.echo(click.style(f"{pr.description[:255]}...", fg="yellow"))
        else:
            click.echo(click.style(pr.description, fg="yellow"))
        top_commit = pr.get_all_commits()[-1]

        commit_statuses = git_project.get_commit_statuses(top_commit)
        # github returns all statuses, not just the latest:
        # so let's just display the latest ones
        processed = set()
        for cs in commit_statuses:
            if cs.context in processed:
                continue
            if cs.state in (CommitStatus.pending, CommitStatus.running):
                color, symbol = "yellow", "🚀"
            elif cs.state in (CommitStatus.failure, CommitStatus.error):
                color, symbol = "red", "🞭"
            elif cs.state == CommitStatus.success:
                color, symbol = "green", "✓"
            elif cs.state == CommitStatus.canceled:
                color, symbol = "orange", "🗑"
            else:
                logger.warning(
                    f"I don't know this type of commit status: {cs.state.value}, {cs.comment}"
                )
                continue
            processed.add(cs.context)
            click.echo(
                click.style(f"{symbol} {cs.context} - {cs.comment} {cs.url}", fg=color)
            )
        if with_pr_comments:
            pr_comments = pr.get_comments()
            if pr_comments:
                click.echo()
                for comment in pr_comments:
                    click.echo(
                        click.style(f"{comment.author} ({comment.created})", bold=True)
                    )
                    click.echo(click.style(comment.body))
                    click.echo(click.style(40 * "-"))
    else:
        open_issues = git_project.get_issue_list()
        click.echo(f"Open issues: {len(open_issues)}")
        open_prs = git_project.get_pr_list()
        click.echo(f"Open PRs: {len(open_prs)}")
        latest_release = git_project.get_latest_release()
        if latest_release:
            click.echo(f"Latest release: {latest_release.title}")