Esempio n. 1
0
def _easyconfigs_pr_common(paths, start_branch=None, pr_branch=None, target_account=None, commit_msg=None):
    """
    Common code for new_pr and update_pr functions:
    * check whether all supplied paths point to existing files
    * create temporary clone of target git repository
    * fetch/checkout specified starting branch
    * copy files to right location
    * stage/commit all files in PR branch
    * push PR branch to GitHub (to account specified by --github-user)

    @paths: list of paths that will be used to create/update PR
    @start_branch: name of branch to start from
    @pr_branch: name of branch to push to GitHub
    @target_account: name of target GitHub account for PR
    @commit_msg: commit message to use
    """
    # we need files to create the PR with
    if paths:
        non_existing_paths = []
        for path in paths:
            if not os.path.exists(path):
                non_existing_paths.append(path)

        if non_existing_paths:
            raise EasyBuildError("One or more non-existing paths specified: %s", ', '.join(non_existing_paths))
    else:
        raise EasyBuildError("No paths specified")

    pr_target_repo = build_option('pr_target_repo')

    # initialize repository
    git_working_dir = tempfile.mkdtemp(prefix='git-working-dir')
    git_repo = init_repo(git_working_dir, pr_target_repo)

    if pr_target_repo != GITHUB_EASYCONFIGS_REPO:
        raise EasyBuildError("Don't know how to create/update a pull request to the %s repository", pr_target_repo)

    if start_branch is None:
        start_branch = build_option('pr_target_branch')

    # set up repository
    setup_repo(git_repo, target_account, pr_target_repo, start_branch)

    _log.debug("git status: %s", git_repo.git.status())

    # copy files to right place
    file_info = copy_easyconfigs(paths, os.path.join(git_working_dir, pr_target_repo))

    # checkout target branch
    if pr_branch is None:
        name_version = file_info['ecs'][0].name + string.translate(file_info['ecs'][0].version, None, '-.')
        pr_branch = '%s_new_pr_%s' % (time.strftime("%Y%m%d%H%M%S"), name_version)

    git_repo.create_head(pr_branch).checkout()
    _log.info("New branch '%s' created to commit files to", pr_branch)

    # stage
    _log.debug("Staging all %d new/modified easyconfigs", len(file_info['paths_in_repo']))
    git_repo.index.add(file_info['paths_in_repo'])

    # overview of modifications
    if build_option('extended_dry_run'):
        print_msg("\nFull patch:\n", log=_log, prefix=False)
        print_msg(git_repo.git.diff(cached=True) + '\n', log=_log, prefix=False)

    diff_stat = git_repo.git.diff(cached=True, stat=True)

    # commit
    if commit_msg:
        _log.debug("Committing all %d new/modified easyconfigs at once", len(file_info['paths_in_repo']))
    else:
        commit_msg_parts = []
        for path, new in zip(file_info['paths_in_repo'], file_info['new']):
            commit_msg_parts.append("%s easyconfig %s" % (('modify', 'add')[new], os.path.basename(path)))
        commit_msg = ', '.join(commit_msg_parts)

    git_repo.index.commit(commit_msg)

    # push to GitHub
    github_user = build_option('github_user')
    github_url = '[email protected]:%s/%s.git' % (github_user, pr_target_repo)
    salt = ''.join(random.choice(string.letters) for _ in range(5))
    remote_name = 'github_%s_%s' % (github_user, salt)

    dry_run = build_option('dry_run') or build_option('extended_dry_run')

    if not dry_run:
        _log.debug("Pushing branch '%s' to remote '%s' (%s)", pr_branch, remote_name, github_url)
        try:
            my_remote = git_repo.create_remote(remote_name, github_url)
            res = my_remote.push(pr_branch)
        except GitCommandError as err:
            raise EasyBuildError("Failed to push branch '%s' to GitHub (%s): %s", pr_branch, github_url, err)

        if res:
            if res[0].ERROR & res[0].flags:
                raise EasyBuildError("Pushing branch '%s' to remote %s (%s) failed: %s",
                                     pr_branch, my_remote, github_url, res[0].summary)
            else:
                _log.debug("Pushed branch %s to remote %s (%s): %s", pr_branch, my_remote, github_url, res[0].summary)
        else:
            raise EasyBuildError("Pushing branch '%s' to remote %s (%s) failed: empty result",
                                 pr_branch, my_remote, github_url)

    return file_info, git_repo, pr_branch, diff_stat
Esempio n. 2
0
def _easyconfigs_pr_common(paths,
                           start_branch=None,
                           pr_branch=None,
                           target_account=None,
                           commit_msg=None):
    """
    Common code for new_pr and update_pr functions:
    * check whether all supplied paths point to existing files
    * create temporary clone of target git repository
    * fetch/checkout specified starting branch
    * copy files to right location
    * stage/commit all files in PR branch
    * push PR branch to GitHub (to account specified by --github-user)

    @paths: list of paths that will be used to create/update PR
    @start_branch: name of branch to start from
    @pr_branch: name of branch to push to GitHub
    @target_account: name of target GitHub account for PR
    @commit_msg: commit message to use
    """
    # we need files to create the PR with
    if paths:
        non_existing_paths = []
        for path in paths:
            if not os.path.exists(path):
                non_existing_paths.append(path)

        if non_existing_paths:
            raise EasyBuildError(
                "One or more non-existing paths specified: %s",
                ', '.join(non_existing_paths))
    else:
        raise EasyBuildError("No paths specified")

    pr_target_repo = build_option('pr_target_repo')

    # initialize repository
    git_working_dir = tempfile.mkdtemp(prefix='git-working-dir')
    git_repo = init_repo(git_working_dir, pr_target_repo)

    if pr_target_repo != GITHUB_EASYCONFIGS_REPO:
        raise EasyBuildError(
            "Don't know how to create/update a pull request to the %s repository",
            pr_target_repo)

    if start_branch is None:
        start_branch = build_option('pr_target_branch')

    # set up repository
    setup_repo(git_repo, target_account, pr_target_repo, start_branch)

    _log.debug("git status: %s", git_repo.git.status())

    # copy files to right place
    file_info = copy_easyconfigs(paths,
                                 os.path.join(git_working_dir, pr_target_repo))

    # checkout target branch
    if pr_branch is None:
        name_version = file_info['ecs'][0].name + string.translate(
            file_info['ecs'][0].version, None, '-.')
        pr_branch = '%s_new_pr_%s' % (time.strftime("%Y%m%d%H%M%S"),
                                      name_version)

    # create branch to commit to and push;
    # use force to avoid errors if branch already exists (OK since this is a local temporary copy of the repo)
    git_repo.create_head(pr_branch, force=True).checkout()
    _log.info("New branch '%s' created to commit files to", pr_branch)

    # stage
    _log.debug("Staging all %d new/modified easyconfigs",
               len(file_info['paths_in_repo']))
    git_repo.index.add(file_info['paths_in_repo'])

    # overview of modifications
    if build_option('extended_dry_run'):
        print_msg("\nFull patch:\n", log=_log, prefix=False)
        print_msg(git_repo.git.diff(cached=True) + '\n',
                  log=_log,
                  prefix=False)

    diff_stat = git_repo.git.diff(cached=True, stat=True)

    # commit
    if commit_msg:
        _log.debug("Committing all %d new/modified easyconfigs at once",
                   len(file_info['paths_in_repo']))
    else:
        commit_msg_parts = []
        for path, new in zip(file_info['paths_in_repo'], file_info['new']):
            commit_msg_parts.append(
                "%s easyconfig %s" %
                (('modify', 'add')[new], os.path.basename(path)))
        commit_msg = ', '.join(commit_msg_parts)

    git_repo.index.commit(commit_msg)

    # push to GitHub
    github_user = build_option('github_user')
    github_url = '[email protected]:%s/%s.git' % (github_user, pr_target_repo)
    salt = ''.join(random.choice(string.letters) for _ in range(5))
    remote_name = 'github_%s_%s' % (github_user, salt)

    dry_run = build_option('dry_run') or build_option('extended_dry_run')

    if not dry_run:
        _log.debug("Pushing branch '%s' to remote '%s' (%s)", pr_branch,
                   remote_name, github_url)
        try:
            my_remote = git_repo.create_remote(remote_name, github_url)
            res = my_remote.push(pr_branch)
        except GitCommandError as err:
            raise EasyBuildError(
                "Failed to push branch '%s' to GitHub (%s): %s", pr_branch,
                github_url, err)

        if res:
            if res[0].ERROR & res[0].flags:
                raise EasyBuildError(
                    "Pushing branch '%s' to remote %s (%s) failed: %s",
                    pr_branch, my_remote, github_url, res[0].summary)
            else:
                _log.debug("Pushed branch %s to remote %s (%s): %s", pr_branch,
                           my_remote, github_url, res[0].summary)
        else:
            raise EasyBuildError(
                "Pushing branch '%s' to remote %s (%s) failed: empty result",
                pr_branch, my_remote, github_url)

    return file_info, git_repo, pr_branch, diff_stat
Esempio n. 3
0
def _easyconfigs_pr_common(paths, start_branch=None, pr_branch=None, target_account=None, commit_msg=None):
    """
    Common code for new_pr and update_pr functions:
    * check whether all supplied paths point to existing files
    * create temporary clone of target git repository
    * fetch/checkout specified starting branch
    * copy files to right location
    * stage/commit all files in PR branch
    * push PR branch to GitHub (to account specified by --github-user)

    @paths: list of paths that will be used to create/update PR
    @start_branch: name of branch to start from
    @pr_branch: name of branch to push to GitHub
    @target_account: name of target GitHub account for PR
    @commit_msg: commit message to use
    """
    # salt to use names of remotes/branches that are created
    salt = ''.join(random.choice(string.letters) for _ in range(5))

    # we need files to create the PR with
    if paths:
        non_existing_paths = []
        for path in paths:
            if not os.path.exists(path):
                non_existing_paths.append(path)

        if non_existing_paths:
            raise EasyBuildError("One or more non-existing paths specified: %s", ', '.join(non_existing_paths))
    else:
        raise EasyBuildError("No paths specified")

    tmp_git_working_dir = tempfile.mkdtemp(prefix='git-working-dir')

    # copy or init git working directory
    pr_target_repo = build_option('pr_target_repo')
    git_working_dirs_path = build_option('git_working_dirs_path')
    if build_option('git_working_dirs_path'):
        workdir = os.path.join(git_working_dirs_path, pr_target_repo)
        if os.path.exists(workdir):
            try:
                print_msg("copying %s..." % workdir)
                os.rmdir(tmp_git_working_dir)
                shutil.copytree(workdir, tmp_git_working_dir)
            except OSError as err:
                raise EasyBuildError("Failed to copy git working dir %s to %s: %s", workdir, tmp_git_working_dir, err)

    git_repo = git.Repo.init(tmp_git_working_dir)

    _log.debug("temporary git working directory ready at %s", tmp_git_working_dir)

    if pr_target_repo != GITHUB_EASYCONFIGS_REPO:
        raise EasyBuildError("Don't know how to create/update a pull request to the %s repository", pr_target_repo)

    # add remote to pull from
    github_url = 'https://github.com/%s/%s.git' % (target_account, pr_target_repo)
    _log.debug("Cloning from %s", github_url)

    origin = git_repo.create_remote('pr_target_account_%s_%s' % (target_account, salt), github_url)
    if not origin.exists():
        raise EasyBuildError("%s does not exist?", github_url)

    if start_branch is None:
        start_branch = build_option('pr_target_branch')

    # git fetch
    # can't use --depth to only fetch a shallow copy, since pushing to another repo from a shallow copy doesn't work
    print_msg("fetching branch '%s' from %s..." % (start_branch, github_url))
    try:
        res = origin.fetch()
    except GitCommandError as err:
        raise EasyBuildError("Failed to fetch branch '%s' from %s: %s", start_branch, github_url, err)
    if res:
        if res[0].flags & res[0].ERROR:
            raise EasyBuildError("Fetching branch '%s' from remote %s failed: %s", start_branch, origin, res[0].note)
        else:
            _log.debug("Fetched branch '%s' from remote %s (note: %s)", start_branch, origin, res[0].note)
    else:
        raise EasyBuildError("Fetching branch '%s' from remote %s failed: empty result", start_branch, origin)

    # git checkout -b <branch>; git pull
    if hasattr(origin.refs, start_branch):
        origin_start_branch = getattr(origin.refs, start_branch)
    else:
        raise EasyBuildError("Branch '%s' not found at %s", start_branch, github_url)

    _log.debug("Checking out branch '%s' from remote %s", start_branch, github_url)
    try:
        origin_start_branch.checkout(b=start_branch)
    except GitCommandError as err:
        alt_branch = 'pr_start_branch_%s_%s' % (start_branch, salt)
        _log.debug("Trying to work around checkout error ('%s') by using different branch name '%s'", err, alt_branch)
        origin_start_branch.checkout(b=alt_branch)
    _log.debug("git status: %s", git_repo.git.status())

    # copy files to right place
    file_info = copy_easyconfigs(paths, tmp_git_working_dir)

    # checkout target branch
    if pr_branch is None:
        name_version = file_info['ecs'][0].name + string.translate(file_info['ecs'][0].version, None, '-.')
        pr_branch = '%s_new_pr_%s' % (time.strftime("%Y%m%d%H%M%S"), name_version)

    git_repo.create_head(pr_branch).checkout()
    _log.info("New branch '%s' created to commit files to", pr_branch)

    # stage
    _log.debug("Staging all %d new/modified easyconfigs", len(file_info['paths_in_repo']))
    git_repo.index.add(file_info['paths_in_repo'])

    # overview of modifications
    if build_option('extended_dry_run'):
        print_msg("\nFull patch:\n", log=_log, prefix=False)
        print_msg(git_repo.git.diff(cached=True) + '\n', log=_log, prefix=False)

    diff_stat = git_repo.git.diff(cached=True, stat=True)

    # commit
    if commit_msg:
        _log.debug("Committing all %d new/modified easyconfigs at once", len(file_info['paths_in_repo']))
        git_repo.index.commit(commit_msg)
    else:
        commit_msg_parts = []
        for path, new in zip(file_info['paths_in_repo'], file_info['new']):
            commit_msg_parts.append("%s easyconfig %s" % (('modify', 'add')[new], os.path.basename(path)))
        commit_msg = ', '.join(commit_msg_parts)
        git_repo.index.commit(commit_msg)

    # push to GitHub
    github_user = build_option('github_user')
    github_url = '[email protected]:%s/%s.git' % (github_user, pr_target_repo)
    remote_name = 'github_%s_%s' % (github_user, salt)

    dry_run = build_option('dry_run') or build_option('extended_dry_run')

    if not dry_run:
        my_remote = git_repo.create_remote(remote_name, github_url)
        res = my_remote.push(pr_branch)
        if res:
            if res[0].ERROR & res[0].flags:
                raise EasyBuildError("Pushing branch '%s' to remote %s (%s) failed: %s",
                                     pr_branch, my_remote, github_url, res[0].summary)
            else:
                _log.debug("Pushed branch %s to remote %s (%s): %s", pr_branch, my_remote, github_url, res[0].summary)
        else:
            raise EasyBuildError("Pushing branch '%s' to remote %s (%s) failed: empty result",
                                 pr_branch, my_remote, github_url)

    return file_info, git_repo, pr_branch, diff_stat