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
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
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