def create_from_template(self, template_name, data, directory, chmod=None, outfile=None): # Configure template name extention = '.em' if not template_name.endswith(extention): template_file = template_name + extention else: template_file = template_name template_name = template_name[:len(extention)] # Open the template with change_directory(directory): with open(template_file, 'r') as f: template = f.read() execute_command('git rm ' + template_file) # Expand template outfile = outfile if outfile is not None else template_name info("Expanding template: '" + template_file + "' to '" + outfile + "'") result = em.expand(template, **data) # Write the template out with change_directory(directory): with open(outfile, 'w+') as f: f.write(result) # Set permissions if needed if chmod is not None: os.chmod(outfile, chmod)
def main(sysargs): parser = get_argument_parser() args = parser.parse_args(sys.argv[1:]) repository = args.repository verbose = args.verbose # checkout target rpository info("Manually clone the repository") info(" git clone {0}".format(repository)) git = get_vcs_client('git', tempfile.mktemp()) info(fmt("@{gf}@!==> @|") + "Fetching repository from '{0}'".format(repository)) ret = git.checkout(repository, verbose=verbose) if not ret: error("Could not checkout {}".format(repository)) return 1 # get the github repository info base_org, base_repo = get_gh_info(git.get_url()) # get correct repo info (case sensitive) gh = get_github_interface() base_org, base_repo = get_gh_info(gh.get_repo(base_org, base_repo)['html_url']) base_branch = git.get_branches()[0] # is this ok? with change_directory(git.get_path()): # write travis yaml write_travis_yaml() # write readme write_readme_md(**locals()) # create pull request open_pull_request(base_org=base_org, base_repo=base_repo, base_branch=base_branch, new_branch="add_travis")
def commit(self): if self.disabled: return info(fmt("@{bf}<==@| Command successful, committing changes to working copy")) current_branch = get_current_branch() if current_branch is None: error("Could not determine current branch.", exit=True) with inbranch(get_commit_hash(get_current_branch())): with change_directory(self.clone_dir): new_branches = get_branches() for branch in self.current_branches: if branch in new_branches: new_branches.remove(branch) for branch in get_branches(local_only=True): if branch not in new_branches: with inbranch(branch): cmd = 'git pull --rebase origin ' + branch execute_command(cmd) execute_command('git push --all', silent=False) try: execute_command('git push --tags', silent=False) except subprocess.CalledProcessError: warning("Force pushing tags from clone to working repository, " "you will have to force push back to origin...") execute_command('git push --force --tags', silent=False) self.clean_up()
def commit(self): if self.disabled: return info( fmt("@{bf}<==@| Command successful, committing changes to working copy" )) current_branch = get_current_branch() if current_branch is None: error("Could not determine current branch.", exit=True) with inbranch(get_commit_hash(get_current_branch())): with change_directory(self.clone_dir): new_branches = get_branches() for branch in self.current_branches: if branch in new_branches: new_branches.remove(branch) for branch in get_branches(local_only=True): if branch not in new_branches: with inbranch(branch): cmd = 'git pull --rebase origin ' + branch execute_command(cmd) execute_command('git push --all', silent=False) try: execute_command('git push --tags', silent=False) except subprocess.CalledProcessError: warning( "Force pushing tags from clone to working repository, " "you will have to force push back to origin...") execute_command('git push --force --tags', silent=False) self.clean_up()
def create_from_template(self, template_name, data, directory, chmod=None, outfile=None): # Configure template name extention = '.em' if not template_name.endswith(extention): template_file = template_name + extention else: template_file = template_name template_name = template_name[:len(extention)] template_path = os.path.join('templates', template_file) # Get the template contents using pkg_resources group = 'bloom.generators.debian' # info("Looking for template: " + group + ':' + template_path) try: template = pkg_resources.resource_string(group, template_path) except IOError as err: error("Failed to load template " "'{0}': {1}".format(template_name, str(err))) self.exit(code.DEBIAN_FAILED_TO_LOAD_TEMPLATE) # Expand template outfile = outfile if outfile is not None else template_name info("Expanding template: '" + template_file + "' to '" + \ outfile + "'") result = em.expand(template, **data) # Write the template out with change_directory(directory): with open(outfile, 'w+') as f: f.write(result) # Set permissions if needed if chmod is not None: os.chmod(outfile, chmod)
def export_upstream(uri, tag, vcs_type, output_dir, show_uri, name): tag = tag if tag != ":{none}" else None output_dir = output_dir or os.getcwd() if uri.startswith("git@"): uri_is_path = False else: uri_parsed = urlparse(uri) uri = uri if uri_parsed.scheme else uri_parsed.path uri_is_path = False if uri_parsed.scheme else True name = name or "upstream" with temporary_directory() as tmp_dir: info( "Checking out repository at '{0}'".format(show_uri or uri) + (" to reference '{0}'.".format(tag) if tag else ".") ) if uri_is_path: upstream_repo = get_vcs_client(vcs_type, uri) else: repo_path = os.path.join(tmp_dir, "upstream") upstream_repo = get_vcs_client(vcs_type, repo_path) if not upstream_repo.checkout(uri, tag or ""): error( "Failed to clone repository at '{0}'".format(uri) + (" to reference '{0}'.".format(tag) if tag else "."), exit=True, ) if get_root() is not None and has_submodules(upstream_repo.get_path()): error( """\ bloom does not support exporting git repositories with submodules, see: - https://github.com/ros-infrastructure/bloom/issues/202 - https://github.com/ros-infrastructure/bloom/issues/217 - https://github.com/vcstools/vcstools/issues/84 """, exit=True, ) tarball_prefix = "{0}-{1}".format(name, tag) if tag else name tarball_path = os.path.join(output_dir, tarball_prefix) full_tarball_path = tarball_path + ".tar.gz" info("Exporting to archive: '{0}'".format(full_tarball_path)) if not upstream_repo.export_repository(tag or "", tarball_path): error("Failed to create archive of upstream repository at '{0}'".format(show_uri)) if tag and vcs_type == "git": # can only check for git repos with change_directory(upstream_repo.get_path()): if not tag_exists(tag): warning("'{0}' is not a tag in the upstream repository...".format(tag)) if not branch_exists(tag): warning("'{0}' is not a branch in the upstream repository...".format(tag)) if not os.path.exists(full_tarball_path): error("Tarball was not created.", exit=True) info("md5: {0}".format(calculate_file_md5(full_tarball_path)))
def list_tracks(repository, distro): release_repo = get_release_repo(repository, distro) tracks_dict = None with change_directory(release_repo.get_path()): if check_for_bloom_conf(repository): info("No tracks, but old style bloom.conf available for conversion") else: tracks_dict = get_tracks_dict_raw() if tracks_dict and tracks_dict['tracks'].keys(): info("Available tracks: " + str(tracks_dict['tracks'].keys())) else: error("Release repository has no tracks nor an old style bloom.conf file.", exit=True) return tracks_dict['tracks'].keys() if tracks_dict else None
def get_upstream_meta(upstream_dir, ros_distro): meta = None directory = os.getcwd() with change_directory(upstream_dir): if get_root() is not None: # If in a git repo current_branch = get_current_branch() else: current_branch = None name, version, packages = get_package_data(current_branch, quiet=False, release_directory=directory) meta = {'name': name, 'version': version, 'type': 'package.xml'} return meta
def export_upstream(uri, tag, vcs_type, output_dir, show_uri, name): tag = tag if tag != ':{none}' else None output_dir = output_dir or os.getcwd() if uri.startswith('git@'): uri_is_path = False else: uri_parsed = urlparse(uri) uri = uri if uri_parsed.scheme else uri_parsed.path uri_is_path = False if uri_parsed.scheme else True name = name or 'upstream' with temporary_directory() as tmp_dir: info("Checking out repository at '{0}'".format(show_uri or uri) + (" to reference '{0}'.".format(tag) if tag else '.')) if uri_is_path: upstream_repo = get_vcs_client(vcs_type, uri) else: repo_path = os.path.join(tmp_dir, 'upstream') upstream_repo = get_vcs_client(vcs_type, repo_path) if not upstream_repo.checkout(uri, tag or ''): error("Failed to clone repository at '{0}'".format(uri) + (" to reference '{0}'.".format(tag) if tag else '.'), exit=True) if get_root() is not None and has_submodules(upstream_repo.get_path()): error("""\ bloom does not support exporting git repositories with submodules, see: - https://github.com/ros-infrastructure/bloom/issues/202 - https://github.com/ros-infrastructure/bloom/issues/217 - https://github.com/vcstools/vcstools/issues/84 """, exit=True) tarball_prefix = '{0}-{1}'.format(name, tag) if tag else name tarball_path = os.path.join(output_dir, tarball_prefix) full_tarball_path = tarball_path + '.tar.gz' info("Exporting to archive: '{0}'".format(full_tarball_path)) if not upstream_repo.export_repository(tag or '', tarball_path): error("Failed to create archive of upstream repository at '{0}'". format(show_uri)) if tag and vcs_type == 'git': # can only check for git repos with change_directory(upstream_repo.get_path()): if not tag_exists(tag): warning( "'{0}' is not a tag in the upstream repository...". format(tag)) if not branch_exists(tag): warning( "'{0}' is not a branch in the upstream repository..." .format(tag)) if not os.path.exists(full_tarball_path): error("Tarball was not created.", exit=True) info("md5: {0}".format(calculate_file_md5(full_tarball_path)))
def get_upstream_meta(upstream_dir, ros_distro): meta = None with change_directory(upstream_dir): if get_root() is not None: # If in a git repo current_branch = get_current_branch() else: current_branch = None name, version, packages = get_package_data(current_branch, quiet=False) meta = { 'name': name, 'version': version, 'type': 'package.xml' } return meta
def commit(self): with inbranch(get_commit_hash(get_current_branch())): with change_directory(self.clone_dir): new_branches = get_branches() for branch in self.current_branches: if branch in new_branches: new_branches.remove(branch) for branch in get_branches(local_only=True): if branch not in new_branches: with inbranch(branch): cmd = "git pull --rebase origin " + branch execute_command(cmd) execute_command("git push --all") execute_command("git push --tags") self.clean_up()
def detect_branches(self): self.packages = None with inbranch(self.src): if self.name is not None: self.packages = [self.name] return [self.name] name, version, packages = get_package_data(self.src) self.packages = packages # Check meta packages for valid CMakeLists.txt if isinstance(self.packages, dict): for path, pkg in self.packages.iteritems(): with change_directory(path): if is_metapackage(pkg): check_metapackage_for_valid_cmake(pkg.name) return name if type(name) is list else [name]
def get_upstream_meta(upstream_dir, ros_distro): meta = None with change_directory(upstream_dir): if get_root() is not None: # If in a git repo current_branch = get_current_branch() else: current_branch = None name, version, stackages = get_package_data( current_branch, quiet=False, fuerte=(ros_distro == 'fuerte')) meta = { 'name': name, 'version': version, 'type': 'package.xml' if isinstance(stackages, dict) else 'stack.xml' } return meta
def list_tracks(repository, distro): release_repo = get_release_repo(repository, distro) tracks_dict = None with change_directory(release_repo.get_path()): upconvert_bloom_to_config_branch() if check_for_bloom_conf(repository): info( "No tracks, but old style bloom.conf available for conversion") else: tracks_dict = get_tracks_dict_raw() if tracks_dict and tracks_dict['tracks'].keys(): info("Available tracks: " + str(tracks_dict['tracks'].keys())) else: error( "Release repository has no tracks nor an old style bloom.conf file.", exit=True) return tracks_dict['tracks'].keys() if tracks_dict else None
def commit(self): if self.disabled: return current_branch = get_current_branch() if current_branch is None: error("Could not determine current branch.", exit=True) with inbranch(get_commit_hash(get_current_branch())): with change_directory(self.clone_dir): new_branches = get_branches() for branch in self.current_branches: if branch in new_branches: new_branches.remove(branch) for branch in get_branches(local_only=True): if branch not in new_branches: with inbranch(branch): cmd = 'git pull --rebase origin ' + branch execute_command(cmd) execute_command('git push --all') execute_command('git push --tags') self.clean_up()
def export_upstream(uri, tag, vcs_type, output_dir, show_uri, name): tag = tag if tag != ':{none}' else None output_dir = output_dir or os.getcwd() if uri.startswith('git@'): uri_is_path = False else: uri_parsed = urlparse(uri) uri = uri if uri_parsed.scheme else uri_parsed.path uri_is_path = False if uri_parsed.scheme else True name = name or 'upstream' with temporary_directory() as tmp_dir: info("Checking out repository at '{0}'".format(show_uri or uri) + (" to reference '{0}'.".format(tag) if tag else '.')) if uri_is_path: upstream_repo = get_vcs_client(vcs_type, uri) else: repo_path = os.path.join(tmp_dir, 'upstream') upstream_repo = get_vcs_client(vcs_type, repo_path) if not upstream_repo.checkout(uri, tag or ''): error("Failed to clone repository at '{0}'".format(uri) + (" to reference '{0}'.".format(tag) if tag else '.'), exit=True) tarball_prefix = '{0}-{1}'.format(name, tag) if tag else name tarball_path = os.path.join(output_dir, tarball_prefix) full_tarball_path = tarball_path + '.tar.gz' info("Exporting to archive: '{0}'".format(full_tarball_path)) if not upstream_repo.export_repository(tag or '', tarball_path): error("Failed to create archive of upstream repository at '{0}'" .format(show_uri)) if tag and vcs_type == 'git': # can only check for git repos with change_directory(upstream_repo.get_path()): if not tag_exists(tag): warning("'{0}' is not a tag in the upstream repository..." .format(tag)) if not branch_exists(tag): warning("'{0}' is not a branch in the upstream repository..." .format(tag)) if not os.path.exists(full_tarball_path): error("Tarball was not created.", exit=True) info("md5: {0}".format(calculate_file_md5(full_tarball_path)))
def export_upstream(uri, tag, vcs_type, output_dir, show_uri, name): tag = tag if tag != ':{none}' else None output_dir = output_dir or os.getcwd() if uri.startswith('git@'): uri_is_path = False else: uri_parsed = urlparse(uri) uri = uri if uri_parsed.scheme else uri_parsed.path uri_is_path = False if uri_parsed.scheme else True name = name or 'upstream' with temporary_directory() as tmp_dir: info("Checking out repository at '{0}'".format(show_uri or uri) + (" to reference '{0}'.".format(tag) if tag else '.')) if uri_is_path: upstream_repo = get_vcs_client(vcs_type, uri) else: repo_path = os.path.join(tmp_dir, 'upstream') upstream_repo = get_vcs_client(vcs_type, repo_path) if not upstream_repo.checkout(uri, tag or ''): error("Failed to clone repository at '{0}'".format(uri) + (" to reference '{0}'.".format(tag) if tag else '.'), exit=True) tarball_prefix = '{0}-{1}'.format(name, tag) if tag else name tarball_path = os.path.join(output_dir, tarball_prefix) full_tarball_path = tarball_path + '.tar.gz' info("Exporting to archive: '{0}'".format(full_tarball_path)) if not upstream_repo.export_repository(tag or '', tarball_path): error("Failed to create archive of upstream repository at '{0}'" .format(show_uri)) if tag: with change_directory(upstream_repo.get_path()): if not tag_exists(tag): warning("'{0}' is not a tag in the upstream repository..." .format(tag)) if not branch_exists(tag): warning("'{0}' is not a branch in the upstream repository..." .format(tag)) if not os.path.exists(full_tarball_path): error("Tarball was not created.", exit=True) info("md5: {0}".format(calculate_file_md5(full_tarball_path)))
def main(sysargs): parser = get_argument_parser() args = parser.parse_args(sys.argv[1:]) repository = args.repository verbose = args.verbose # checkout target rpository info("Manually clone the repository") info(" git clone {0}".format(repository)) git = get_vcs_client('git', tempfile.mktemp()) info( fmt("@{gf}@!==> @|") + "Fetching repository from '{0}'".format(repository)) ret = git.checkout(repository, verbose=verbose) if not ret: error("Could not checkout {}".format(repository)) return 1 # get the github repository info base_org, base_repo = get_gh_info(git.get_url()) # get correct repo info (case sensitive) gh = get_github_interface() base_org, base_repo = get_gh_info( gh.get_repo(base_org, base_repo)['html_url']) base_branch = git.get_branches()[0] # is this ok? with change_directory(git.get_path()): # write travis yaml write_travis_yaml() # write readme write_readme_md(**locals()) # create pull request open_pull_request(base_org=base_org, base_repo=base_repo, base_branch=base_branch, new_branch="add_travis")
def commit(self): with inbranch(get_commit_hash(get_current_branch())): with change_directory(self.clone_dir): execute_command('git push --force --all') execute_command('git push --force --tags') self.clean_up()
def perform_release(repository, track, distro, new_track, interactive, pretend, pull_request_only): release_repo = get_release_repo(repository, distro) with change_directory(release_repo.get_path()): # Check to see if the old bloom.conf exists if check_for_bloom_conf(repository): # Convert to a track info("Old bloom.conf file detected.") info(fmt("@{gf}@!==> @|Converting to bloom.conf to track")) convert_old_bloom_conf(None if new_track else distro) upconvert_bloom_to_config_branch() # Check that the track is valid tracks_dict = get_tracks_dict_raw() # If new_track, create the new track first if new_track: if not track: error("You must specify a track when creating a new one.", exit=True) if track in tracks_dict['tracks']: warning("Track '{0}' exists, editing...".format(track)) edit_track_cmd(track) tracks_dict = get_tracks_dict_raw() else: # Create a new track called <track>, # copying an existing track if possible, # and overriding the ros_distro warning("Creating track '{0}'...".format(track)) overrides = {'ros_distro': distro} new_track_cmd(track, copy_track='', overrides=overrides) tracks_dict = get_tracks_dict_raw() if track and track not in tracks_dict['tracks']: error("Given track '{0}' does not exist in release repository." .format(track)) error("Available tracks: " + str(tracks_dict['tracks'].keys()), exit=True) elif not track: tracks = tracks_dict['tracks'].keys() # Error out if there are no tracks if len(tracks) == 0: error("Release repository has no tracks.") info("Manually clone the repository:") info(" git clone {0}".format(release_repo.get_url())) info("And then create a new track:") info(" git-bloom-config new <track name>") error("Run again after creating a track.", exit=True) # Error out if there is more than one track if len(tracks) != 1: error("No track specified and there is not just one track.") error("Please specify one of the available tracks: " + str(tracks), exit=True) # Get the only track track = tracks[0] start_summary(track) if not pull_request_only: _perform_release(repository, track, distro, new_track, interactive, pretend, tracks_dict) # Propose github pull request info(fmt("@{gf}@!==> @|") + "Generating pull request to distro file located at '{0}'" .format(get_disitrbution_file_url(distro))) try: pull_request_url = open_pull_request(track, repository, distro) if pull_request_url: info(fmt(_success) + "Pull request opened at: {0}".format(pull_request_url)) if 'BLOOM_NO_WEBBROWSER' not in os.environ and platform.system() in ['Darwin']: webbrowser.open(pull_request_url) else: info("The release of your packages was successful, but the pull request failed.") info("Please manually open a pull request by editing the file here: '{0}'" .format(get_disitrbution_file_url(distro))) info(fmt(_error) + "No pull request opened.") except Exception as e: debug(traceback.format_exc()) error("Failed to open pull request: {0} - {1}".format(type(e).__name__, e), exit=True)
def open_pull_request(track, repository, distro): # Get the diff distribution_file = get_distribution_file(distro) if repository in distribution_file.repositories and \ distribution_file.repositories[repository].release_repository is not None: orig_version = distribution_file.repositories[repository].release_repository.version else: orig_version = None updated_distribution_file = generate_ros_distro_diff(track, repository, distro) if updated_distribution_file is None: # There were no changes, no pull request required return None version = updated_distribution_file.repositories[repository].release_repository.version updated_distro_file_yaml = yaml_from_distribution_file(updated_distribution_file) # Determine if the distro file is hosted on github... base_org, base_repo, base_branch, base_path = get_gh_info(get_disitrbution_file_url(distro)) if None in [base_org, base_repo, base_branch, base_path]: warning("Automated pull request only available via github.com") return # Get the github interface gh = get_github_interface() # Determine the head org/repo for the pull request head_org = gh.username # The head org will always be gh user head_repo = None # Check if the github user and the base org are the same if gh.username == base_org: # If it is, then a fork is not necessary head_repo = base_repo else: info(fmt("@{bf}@!==> @|@!Checking on github for a fork to make the pull request from...")) # It is not, so a fork will be required # Check if a fork already exists on the user's account with the same name base_full_name = '{base_org}/{base_repo}'.format(**locals()) try: repo_data = gh.get_repo(gh.username, base_repo) if repo_data.get('fork', False): # Check if it is a fork # If it is, check that it is a fork of the destination parent = repo_data.get('parent', {}).get('full_name', None) if parent == base_full_name: # This is a valid fork head_repo = base_repo except GithubException as exc: debug("Received GithubException while checking for fork: {exc}".format(**locals())) pass # 404 or unauthorized, but unauthorized should have been caught above # If not head_repo, then either the fork has a different name, or there isn't one if head_repo is None: info(fmt("@{bf}@!==> @|@!" + "{head_org}/{base_repo} is not a fork, searching...".format(**locals()))) # First we should look at every repository for the user and see if they are a fork user_repos = gh.list_repos(gh.username) for repo in user_repos: # If it is a fork and the parent is base_org/base_repo if repo.get('fork', False) and repo.get('parent', {}).get('full_name', '') == base_full_name: # Then this is a valid fork head_repo = repo['name'] # If not head_repo still, a fork does not exist and must be created if head_repo is None: warning("Could not find a fork of {base_full_name} on the {gh.username} Github account." .format(**locals())) warning("Would you like to create one now?") if not maybe_continue(): warning("Skipping the pull request...") return # Create a fork try: gh.create_fork(base_org, base_repo) # Will raise if not successful head_repo = base_repo except GithubException as exc: error("Aborting pull request: {0}".format(exc)) return info(fmt("@{bf}@!==> @|@!" + "Using this fork to make a pull request from: {head_org}/{head_repo}".format(**locals()))) # Clone the fork info(fmt("@{bf}@!==> @|@!" + "Cloning {0}/{1}...".format(head_org, head_repo))) new_branch = None title = "{0}: {1} in '{2}' [bloom]".format(repository, version, base_path) body = """\ Increasing version of package(s) in repository `{0}` to `{2}`: - distro file: `{3}` - bloom version: `{4}` - previous version for package: `{1}` """.format(repository, orig_version or 'null', version, base_path, bloom.__version__) body += get_changelog_summary(generate_release_tag(distro)) with temporary_directory() as temp_dir: def _my_run(cmd, msg=None): if msg: info(fmt("@{bf}@!==> @|@!" + sanitize(msg))) else: info(fmt("@{bf}@!==> @|@!" + sanitize(str(cmd)))) from subprocess import check_call check_call(cmd, shell=True) # Use the oauth token to clone rosdistro_url = 'https://{gh.token}:[email protected]/{base_org}/{base_repo}.git'.format(**locals()) rosdistro_fork_url = 'https://{gh.token}:[email protected]/{head_org}/{head_repo}.git'.format(**locals()) _my_run('mkdir -p {base_repo}'.format(**locals())) with change_directory(base_repo): _my_run('git init') branches = [x['name'] for x in gh.list_branches(head_org, head_repo)] new_branch = 'bloom-{repository}-{count}' count = 0 while new_branch.format(repository=repository, count=count) in branches: count += 1 new_branch = new_branch.format(repository=repository, count=count) # Final check info(fmt("@{cf}Pull Request Title: @{yf}" + title)) info(fmt("@{cf}Pull Request Body : \n@{yf}" + body)) msg = fmt("@!Open a @|@{cf}pull request@| @!@{kf}from@| @!'@|@!@{bf}" + "{head_repo}/{head_repo}:{new_branch}".format(**locals()) + "@|@!' @!@{kf}into@| @!'@|@!@{bf}" + "{base_org}/{base_repo}:{base_branch}".format(**locals()) + "@|@!'?") info(msg) if not maybe_continue(): warning("Skipping the pull request...") return _my_run('git checkout -b {new_branch}'.format(**locals())) _my_run('git pull {rosdistro_url} {base_branch}'.format(**locals()), "Pulling latest rosdistro branch") with open('{0}'.format(base_path), 'w') as f: info(fmt("@{bf}@!==> @|@!Writing new distribution file: ") + str(base_path)) f.write(updated_distro_file_yaml) _my_run('git add {0}'.format(base_path)) _my_run('git commit -m "{0}"'.format(title)) _my_run('git push {rosdistro_fork_url} {new_branch}'.format(**locals()), "Pushing changes to fork") # Open the pull request return gh.create_pull_request(base_org, base_repo, base_branch, head_org, new_branch, title, body)
def open_pull_request(track, repository, distro): # Get the diff release_file = get_release_file(distro) if repository in release_file.repositories: orig_version = release_file.repositories[repository].version else: orig_version = None updated_release_file = generate_ros_distro_diff(track, repository, distro) if updated_release_file is None: # There were no changes, no pull request required return None version = updated_release_file.repositories[repository].version updated_distro_file = yaml_from_release_file(updated_release_file) # Determine if the distro file is hosted on github... gh_org, gh_repo, gh_branch, gh_path = get_gh_info( get_release_file_url(distro)) if None in [gh_org, gh_repo, gh_branch, gh_path]: warning("Automated pull request only available via github.com") return # Get the github user name gh_username = None bloom_user_path = os.path.join(os.path.expanduser('~'), '.bloom_user') if os.path.exists(bloom_user_path): with open(bloom_user_path, 'r') as f: gh_username = f.read().strip() gh_username = gh_username or getpass.getuser() response = raw_input("github user name [{0}]: ".format(gh_username)) if response: gh_username = response info( "Would you like bloom to store your github user name (~/.bloom_user)?" ) if maybe_continue(): with open(bloom_user_path, 'w') as f: f.write(gh_username) else: with open(bloom_user_path, 'w') as f: f.write(' ') warning( "If you want to have bloom store it in the future remove the ~/.bloom_user file." ) # Get the github password gh_password = getpass.getpass("github password (This is not stored):") if not gh_password or not gh_username: error("Either the github username or github password is not set.") warning("Skipping the pull request...") return # Check for fork info(fmt("@{bf}@!==> @|@!Checking for rosdistro fork on github...")) gh_user_repos = fetch_github_api( 'https://api.github.com/users/{0}/repos'.format(gh_username), use_pagination=True) if gh_user_repos is None: error("Failed to get a list of repositories for user: '******'".format( gh_username)) warning("Skipping the pull request...") return if 'rosdistro' not in [x['name'] for x in gh_user_repos if 'name' in x]: warning( "Github user '{0}' does not have a fork ".format(gh_username) + "of the {0}:{1} repository, create one?".format(gh_org, gh_repo)) if not maybe_continue(): warning("Skipping the pull request...") return # Create a fork create_fork(gh_org, gh_repo, gh_username, gh_password) # Clone the fork info( fmt("@{bf}@!==> @|@!" + "Cloning {0}/{1}...".format(gh_username, gh_repo))) temp_dir = tempfile.mkdtemp() new_branch = None title = "{0}: {1} in '{2}' [bloom]".format(repository, version, gh_path) body = """\ Increasing version of package(s) in repository `{0}`: - previous version: `{1}` - new version: `{2}` - distro file: `{3}` - bloom version: `{4}` """.format(repository, orig_version or 'null', version, gh_path, bloom.__version__) with change_directory(temp_dir): def _my_run(cmd): info(fmt("@{bf}@!==> @|@!" + str(cmd))) # out = check_output(cmd, stderr=subprocess.STDOUT, shell=True) out = None from subprocess import call call(cmd, shell=True) if out: info(out, use_prefix=False) _my_run('git clone https://github.com/{0}/{1}.git'.format( gh_username, gh_repo)) with change_directory(gh_repo): _my_run( 'git remote add bloom https://github.com/{0}/{1}.git'.format( gh_org, gh_repo)) _my_run('git remote update') _my_run('git fetch') track_branches() branches = get_branches() new_branch = 'bloom-{repository}-{count}' count = 0 while new_branch.format(repository=repository, count=count) in branches: count += 1 new_branch = new_branch.format(repository=repository, count=count) # Final check info(fmt("@{cf}Pull Request Title: @{yf}" + title)) info(fmt("@{cf}Pull Request Body : \n@{yf}" + body)) msg = fmt( "@!Open a @|@{cf}pull request@| @!@{kf}from@| @!'@|@!@{bf}" + "{gh_username}/{gh_repo}:{new_branch}".format(**locals()) + "@|@!' @!@{kf}into@| @!'@|@!@{bf}" + "{gh_org}/{gh_repo}:{gh_branch}".format(**locals()) + "@|@!'?") info(msg) if not maybe_continue(): warning("Skipping the pull request...") return _my_run('git checkout -b {0} bloom/{1}'.format( new_branch, gh_branch)) with open('{0}'.format(gh_path), 'w') as f: info( fmt("@{bf}@!==> @|@!Writing new distribution file: ") + str(gh_path)) f.write(updated_distro_file) _my_run('git add {0}'.format(gh_path)) _my_run('git commit -m "{0}"'.format(title)) _my_run('git push origin {0}'.format(new_branch)) # Open the pull request return create_pull_request(gh_org, gh_repo, gh_username, gh_password, gh_branch, new_branch, title, body)
def perform_release(repository, track, distro, new_track, interactive, pretend): release_repo = get_release_repo(repository, distro) with change_directory(release_repo.get_path()): # Check to see if the old bloom.conf exists if check_for_bloom_conf(repository): # Convert to a track info("Old bloom.conf file detected.") info(fmt("@{gf}@!==> @|Converting to bloom.conf to track")) convert_old_bloom_conf(None if new_track else distro) upconvert_bloom_to_config_branch() # Check that the track is valid tracks_dict = get_tracks_dict_raw() # If new_track, create the new track first if new_track: if not track: error("You must specify a track when creating a new one.", exit=True) if track in tracks_dict['tracks']: warning("Track '{0}' exists, editing...".format(track)) edit_track_cmd(track) tracks_dict = get_tracks_dict_raw() else: # Create a new track called <track>, # copying an existing track if possible, # and overriding the ros_distro warning("Creating track '{0}'...".format(track)) overrides = {'ros_distro': distro} new_track_cmd(track, copy_track='', overrides=overrides) tracks_dict = get_tracks_dict_raw() if track and track not in tracks_dict['tracks']: error("Given track '{0}' does not exist in release repository.". format(track)) error("Available tracks: " + str(tracks_dict['tracks'].keys()), exit=True) elif not track: tracks = tracks_dict['tracks'].keys() # Error out if there are no tracks if len(tracks) == 0: error("Release repository has no tracks.") info("Manually clone the repository:") info(" git clone {0}".format(release_repo.get_url())) info("And then create a new track:") info(" git-bloom-config new <track name>") error("Run again after creating a track.", exit=True) # Error out if there is more than one track if len(tracks) != 1: error("No track specified and there is not just one track.") error("Please specify one of the available tracks: " + str(tracks), exit=True) # Get the only track track = tracks[0] start_summary(track) # Ensure the track is complete track_dict = tracks_dict['tracks'][track] track_dict = update_track(track_dict) tracks_dict['tracks'][track] = track_dict # Set the release repositories' remote if given release_repo_url = track_dict.get('release_repo_url', None) if release_repo_url is not None: info( fmt("@{gf}@!==> @|") + "Setting release repository remote url to '{0}'".format( release_repo_url)) cmd = 'git remote set-url origin ' + release_repo_url info(fmt("@{bf}@!==> @|@!") + str(cmd)) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Setting the remote url failed, exiting.", exit=True) # Check for push permissions try: info( fmt("@{gf}@!==> @|Testing for push permission on release repository" )) cmd = 'git remote -v' info(fmt("@{bf}@!==> @|@!") + str(cmd)) subprocess.check_call(cmd, shell=True) # Dry run will authenticate, but not push cmd = 'git push --dry-run' info(fmt("@{bf}@!==> @|@!") + str(cmd)) subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Cannot push to remote release repository.", exit=True) # Write the track config before releasing write_tracks_dict_raw(tracks_dict) # Run the release info( fmt("@{gf}@!==> @|") + "Releasing '{0}' using release track '{1}'".format( repository, track)) cmd = 'git-bloom-release ' + str(track) if pretend: cmd += ' --pretend' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Release failed, exiting.", exit=True) info( fmt(_success) + "Released '{0}' using release track '{1}' successfully".format( repository, track)) # Commit the summary update_summary(track, repository, distro) commit_summary() # Check for pushing if interactive: info("Releasing complete, push?") if not maybe_continue(): error("User answered no to continue prompt, aborting.", exit=True) # Push changes to the repository info( fmt("@{gf}@!==> @|") + "Pushing changes to release repository for '{0}'".format( repository)) cmd = 'git push --all' if pretend: cmd += ' --dry-run' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error( "Pushing changes failed, would you like to add '--force' to 'git push --all'?" ) if not maybe_continue(): error("Pushing changes failed, exiting.", exit=True) cmd += ' --force' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing changes failed, exiting.", exit=True) info(fmt(_success) + "Pushed changes successfully") # Push tags to the repository info( fmt("@{gf}@!==> @|") + "Pushing tags to release repository for '{0}'".format(repository)) cmd = 'git push --tags' if pretend: cmd += ' --dry-run' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error( "Pushing changes failed, would you like to add '--force' to 'git push --tags'?" ) if not maybe_continue(): error("Pushing tags failed, exiting.", exit=True) cmd += ' --force' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing tags failed, exiting.", exit=True) info(fmt(_success) + "Pushed tags successfully") # Propose github pull request info( fmt("@{gf}@!==> @|") + "Generating pull request to distro file located at '{0}'".format( get_release_file_url(distro))) try: pull_request_url = open_pull_request(track, repository, distro) if pull_request_url: info( fmt(_success) + "Pull request opened at: {0}".format(pull_request_url)) if 'BLOOM_NO_WEBBROWSER' in os.environ and platform.system( ) not in ['Darwin']: webbrowser.open(pull_request_url) else: info( "The release of your packages was successful, but the pull request failed." ) info( "Please manually open a pull request by editing the file here: '{0}'" .format(get_release_file_url(distro))) info(fmt(_error) + "No pull request opened.") except Exception as e: debug(traceback.format_exc()) error("Failed to open pull request: {0} - {1}".format( type(e).__name__, e), exit=True)
def perform_release(repository, track, distro, new_track, interactive, pretend, ssh_pull_request): release_repo = get_release_repo(repository, distro) with change_directory(release_repo.get_path()): # Check to see if the old bloom.conf exists if check_for_bloom_conf(repository): # Convert to a track info("Old bloom.conf file detected.") info(fmt("@{gf}@!==> @|Converting to bloom.conf to track")) convert_old_bloom_conf(None if new_track else distro) upconvert_bloom_to_config_branch() # Check that the track is valid tracks_dict = get_tracks_dict_raw() # If new_track, create the new track first if new_track: if not track: error("You must specify a track when creating a new one.", exit=True) if track in tracks_dict['tracks']: warning("Track '{0}' exists, editing...".format(track)) edit_track_cmd(track) tracks_dict = get_tracks_dict_raw() else: # Create a new track called <track>, # copying an existing track if possible, # and overriding the ros_distro warning("Creating track '{0}'...".format(track)) overrides = {'ros_distro': distro} new_track_cmd(track, copy_track='', overrides=overrides) tracks_dict = get_tracks_dict_raw() if track and track not in tracks_dict['tracks']: error("Given track '{0}' does not exist in release repository." .format(track)) error("Available tracks: " + str(tracks_dict['tracks'].keys()), exit=True) elif not track: tracks = tracks_dict['tracks'].keys() # Error out if there are no tracks if len(tracks) == 0: error("Release repository has no tracks.") info("Manually clone the repository:") info(" git clone {0}".format(release_repo.get_url())) info("And then create a new track:") info(" git-bloom-config new <track name>") error("Run again after creating a track.", exit=True) # Error out if there is more than one track if len(tracks) != 1: error("No track specified and there is not just one track.") error("Please specify one of the available tracks: " + str(tracks), exit=True) # Get the only track track = tracks[0] start_summary(track) # Ensure the track is complete track_dict = tracks_dict['tracks'][track] track_dict = update_track(track_dict) tracks_dict['tracks'][track] = track_dict # Set the release repositories' remote if given release_repo_url = track_dict.get('release_repo_url', None) if release_repo_url is not None: info(fmt("@{gf}@!==> @|") + "Setting release repository remote url to '{0}'" .format(release_repo_url)) cmd = 'git remote set-url origin ' + release_repo_url info(fmt("@{bf}@!==> @|@!") + str(cmd)) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Setting the remote url failed, exiting.", exit=True) # Check for push permissions try: info(fmt( "@{gf}@!==> @|Testing for push permission on release repository" )) cmd = 'git remote -v' info(fmt("@{bf}@!==> @|@!") + str(cmd)) subprocess.check_call(cmd, shell=True) # Dry run will authenticate, but not push cmd = 'git push --dry-run' info(fmt("@{bf}@!==> @|@!") + str(cmd)) subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Cannot push to remote release repository.", exit=True) # Write the track config before releasing write_tracks_dict_raw(tracks_dict) # Run the release info(fmt("@{gf}@!==> @|") + "Releasing '{0}' using release track '{1}'" .format(repository, track)) cmd = 'git-bloom-release ' + str(track) if pretend: cmd += ' --pretend' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Release failed, exiting.", exit=True) info(fmt(_success) + "Released '{0}' using release track '{1}' successfully" .format(repository, track)) # Commit the summary update_summary(track, repository, distro) commit_summary() # Check for pushing if interactive: info("Releasing complete, push?") if not maybe_continue(): error("User answered no to continue prompt, aborting.", exit=True) # Push changes to the repository info(fmt("@{gf}@!==> @|") + "Pushing changes to release repository for '{0}'" .format(repository)) cmd = 'git push --all' if pretend: cmd += ' --dry-run' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing changes failed, would you like to add '--force' to 'git push --all'?") if not maybe_continue(): error("Pushing changes failed, exiting.", exit=True) cmd += ' --force' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing changes failed, exiting.", exit=True) info(fmt(_success) + "Pushed changes successfully") # Push tags to the repository info(fmt("@{gf}@!==> @|") + "Pushing tags to release repository for '{0}'" .format(repository)) cmd = 'git push --tags' if pretend: cmd += ' --dry-run' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing changes failed, would you like to add '--force' to 'git push --tags'?") if not maybe_continue(): error("Pushing tags failed, exiting.", exit=True) cmd += ' --force' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing tags failed, exiting.", exit=True) info(fmt(_success) + "Pushed tags successfully") # Propose github pull request info(fmt("@{gf}@!==> @|") + "Generating pull request to distro file located at '{0}'" .format(get_disitrbution_file_url(distro))) try: pull_request_url = open_pull_request(track, repository, distro, ssh_pull_request) if pull_request_url: info(fmt(_success) + "Pull request opened at: {0}".format(pull_request_url)) if 'BLOOM_NO_WEBBROWSER' in os.environ and platform.system() not in ['Darwin']: webbrowser.open(pull_request_url) else: info("The release of your packages was successful, but the pull request failed.") info("Please manually open a pull request by editing the file here: '{0}'" .format(get_disitrbution_file_url(distro))) info(fmt(_error) + "No pull request opened.") except Exception as e: debug(traceback.format_exc()) error("Failed to open pull request: {0} - {1}".format(type(e).__name__, e), exit=True)
def open_pull_request(track, repository, distro): # Get the diff release_file = get_release_file(distro) if repository in release_file.repositories: orig_version = release_file.repositories[repository].version else: orig_version = None updated_release_file = generate_ros_distro_diff(track, repository, distro) if updated_release_file is None: # There were no changes, no pull request required return None version = updated_release_file.repositories[repository].version updated_distro_file = yaml_from_release_file(updated_release_file) # Determine if the distro file is hosted on github... gh_org, gh_repo, gh_branch, gh_path = get_gh_info(get_release_file_url(distro)) if None in [gh_org, gh_repo, gh_branch, gh_path]: warning("Automated pull request only available via github.com") return # Get the github user name gh_username = None bloom_user_path = os.path.join(os.path.expanduser("~"), ".bloom_user") if os.path.exists(bloom_user_path): with open(bloom_user_path, "r") as f: gh_username = f.read().strip() gh_username = gh_username or getpass.getuser() response = raw_input("github user name [{0}]: ".format(gh_username)) if response: gh_username = response info("Would you like bloom to store your github user name (~/.bloom_user)?") if maybe_continue(): with open(bloom_user_path, "w") as f: f.write(gh_username) else: with open(bloom_user_path, "w") as f: f.write(" ") warning("If you want to have bloom store it in the future remove the ~/.bloom_user file.") # Get the github password gh_password = getpass.getpass("github password (This is not stored):") if not gh_password or not gh_username: error("Either the github username or github password is not set.") warning("Skipping the pull request...") return # Check for fork info(fmt("@{bf}@!==> @|@!Checking for rosdistro fork on github...")) gh_user_repos = fetch_github_api("https://api.github.com/users/{0}/repos".format(gh_username), use_pagination=True) if gh_user_repos is None: error("Failed to get a list of repositories for user: '******'".format(gh_username)) warning("Skipping the pull request...") return if "rosdistro" not in [x["name"] for x in gh_user_repos if "name" in x]: warning( "Github user '{0}' does not have a fork ".format(gh_username) + "of the {0}:{1} repository, create one?".format(gh_org, gh_repo) ) if not maybe_continue(): warning("Skipping the pull request...") return # Create a fork create_fork(gh_org, gh_repo, gh_username, gh_password) # Clone the fork info(fmt("@{bf}@!==> @|@!" + "Cloning {0}/{1}...".format(gh_username, gh_repo))) temp_dir = tempfile.mkdtemp() new_branch = None title = "{0}: {1} in '{2}' [bloom]".format(repository, version, gh_path) body = """\ Increasing version of package(s) in repository `{0}`: - previous version: `{1}` - new version: `{2}` - distro file: `{3}` - bloom version: `{4}` """.format( repository, orig_version or "null", version, gh_path, bloom.__version__ ) with change_directory(temp_dir): def _my_run(cmd): info(fmt("@{bf}@!==> @|@!" + str(cmd))) # out = check_output(cmd, stderr=subprocess.STDOUT, shell=True) out = None from subprocess import call call(cmd, shell=True) if out: info(out, use_prefix=False) _my_run("git clone https://github.com/{0}/{1}.git".format(gh_username, gh_repo)) with change_directory(gh_repo): _my_run("git remote add bloom https://github.com/{0}/{1}.git".format(gh_org, gh_repo)) _my_run("git remote update") _my_run("git fetch") track_branches() branches = get_branches() new_branch = "bloom-{repository}-{count}" count = 0 while new_branch.format(repository=repository, count=count) in branches: count += 1 new_branch = new_branch.format(repository=repository, count=count) # Final check info(fmt("@{cf}Pull Request Title: @{yf}" + title)) info(fmt("@{cf}Pull Request Body : \n@{yf}" + body)) msg = fmt( "@!Open a @|@{cf}pull request@| @!@{kf}from@| @!'@|@!@{bf}" + "{gh_username}/{gh_repo}:{new_branch}".format(**locals()) + "@|@!' @!@{kf}into@| @!'@|@!@{bf}" + "{gh_org}/{gh_repo}:{gh_branch}".format(**locals()) + "@|@!'?" ) info(msg) if not maybe_continue(): warning("Skipping the pull request...") return _my_run("git checkout -b {0} bloom/{1}".format(new_branch, gh_branch)) with open("{0}".format(gh_path), "w") as f: info(fmt("@{bf}@!==> @|@!Writing new distribution file: ") + str(gh_path)) f.write(updated_distro_file) _my_run("git add {0}".format(gh_path)) _my_run('git commit -m "{0}"'.format(title)) _my_run("git push origin {0}".format(new_branch)) # Open the pull request return create_pull_request(gh_org, gh_repo, gh_username, gh_password, gh_branch, new_branch, title, body)
def perform_release(repository, track, distro, new_track, interactive): release_repo = get_release_repo(repository, distro) with change_directory(release_repo.get_path()): # Check for push permissions try: info(fmt("@{gf}@!==> @|Testing for push permission on release repository")) check_output('git push', shell=True) except subprocess.CalledProcessError: error("Cannot push to remote release repository.", exit=True) # Check to see if the old bloom.conf exists if check_for_bloom_conf(repository): # Convert to a track info("Old bloom.conf file detected.") info(fmt("@{gf}@!==> @|Converting to bloom.conf to track")) convert_old_bloom_conf(None if new_track else distro) # Check that the track is valid tracks_dict = get_tracks_dict_raw() # If new_track, create the new track first if new_track: if not track: error("You must specify a track when creating a new one.", exit=True) overrides = {'ros_distro': distro} if track in tracks_dict['tracks']: warning("Track '{0}' exists, editing instead...".format(track)) edit_track_cmd(track) else: # Create a new track called <track>, # copying an existing track if possible, # and overriding the ros_distro new_track_cmd(track, copy_track='', overrides=overrides) tracks_dict = get_tracks_dict_raw() if track and track not in tracks_dict['tracks']: error("Given track '{0}' does not exist in release repository." .format(track)) error("Available tracks: " + str(tracks_dict['tracks'].keys()), exit=True) elif not track: tracks = tracks_dict['tracks'].keys() # Error out if there are no tracks if len(tracks) == 0: error("Release repository has no tracks.") info("Manually clone the repository:") info(" git clone {0}".format(release_repo.get_url())) info("And then create a new track:") info(" git-bloom-config new <track name>") error("Run again after creating a track.", exit=True) # Error out if there is more than one track if len(tracks) != 1: error("No track specified and there is not just one track.") error("Please specify one of the available tracks: " + str(tracks), exit=True) # Get the only track track = tracks[0] # Ensure the track is complete track_dict = tracks_dict['tracks'][track] update_track(track_dict) tracks_dict['tracks'][track] = track_dict write_tracks_dict_raw(tracks_dict) # Run the release info(fmt("@{gf}@!==> @|") + "Releasing '{0}' using release track '{1}'" .format(repository, track)) cmd = 'git-bloom-release ' + str(track) info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Release failed, exiting.", exit=True) info(fmt(_success) + "Released '{0}' using release track '{1}' successfully" .format(repository, track)) # Check for pushing if interactive: info("Releasing complete, push?") if not maybe_continue(): error("User answered no to continue prompt, aborting.", exit=True) # Push changes to the repository info(fmt("@{gf}@!==> @|") + "Pushing changes to release repository for '{0}'" .format(repository)) cmd = 'git push --all' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing changes failed, would you like to add '--force' to 'git push --all'?") if not maybe_continue(): error("Pushing changes failed, exiting.", exit=True) cmd += ' --force' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing changes failed, exiting.", exit=True) info(fmt(_success) + "Pushed changes successfully") # Push tags to the repository info(fmt("@{gf}@!==> @|") + "Pushing tags to release repository for '{0}'" .format(repository)) cmd = 'git push --tags' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing changes failed, would you like to add '--force' to 'git push --tags'?") if not maybe_continue(): error("Pushing tags failed, exiting.", exit=True) cmd += ' --force' info(fmt("@{bf}@!==> @|@!" + str(cmd))) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: error("Pushing tags failed, exiting.", exit=True) info(fmt(_success) + "Pushed tags successfully") # Propose github pull request info(fmt("@{gf}@!==> @|") + "Generating pull request to distro file located at '{0}'" .format(ROS_DISTRO_FILE).format(distro)) generate_ros_distro_diff(track, repository, distro) info("In the future this will create a pull request for you, done for now...") info(fmt(_success) + "Pull request opened at: '{0}'".format('Not yet Implemented'))
def open_pull_request(track, repository, distro, distro_file_url=ROS_DISTRO_FILE): # Get the diff distro_file_url = distro_file_url.format(distro) distro_file_raw = fetch_distro_file(distro_file_url) distro_file = yaml.load(distro_file_raw) if repository in distro_file['repositories']: orig_version = distro_file['repositories'][repository].get('version', None) else: orig_version = None udiff_patch_file, updated_distro_file = generate_ros_distro_diff(track, repository, distro, distro_file_url, distro_file, distro_file_raw) if None in [udiff_patch_file, updated_distro_file]: # There were no changes, no pull request required return None version = distro_file['repositories'][repository]['version'] # Determine if the distro file is hosted on github... distro_file_url = distro_file_url.format(distro) gh_org, gh_repo, gh_branch, gh_path = get_gh_info(distro_file_url) if None in [gh_org, gh_repo, gh_branch, gh_path]: warning("Automated pull request only available via github.com") return # Determine if we have a .netrc file gh_username = None try: netrc_hosts = netrc.netrc().hosts except Exception as e: error("Failed to parse ~/.netrc file: {0}".format(e)) warning("Skipping the pull request...") return for host in netrc_hosts.keys(): if 'github.com' in host: gh_username = netrc_hosts[host][0] gh_password = netrc_hosts[host][2] if None in [gh_username, gh_password]: error("Either the github username or github password is not set in the ~/.netrc file.") warning("Skipping the pull request...") return # Check for fork info(fmt("@{bf}@!==> @|@!Checking for rosdistro fork on github...")) gh_user_repos = fetch_github_api('https://api.github.com/users/{0}/repos'.format(gh_username)) if gh_user_repos is None: error("Failed to get a list of repositories for user: '******'".format(gh_username)) warning("Skipping the pull request...") return if 'rosdistro' not in [x['name'] for x in gh_user_repos if 'name' in x]: warning("Github user '{0}' does not have a fork ".format(gh_username) + "of the {0}:{1} repository, create one?".format(gh_org, gh_repo)) if not maybe_continue(): warning("Skipping the pull request...") return # Create a fork create_fork(gh_org, gh_repo, gh_username, gh_password) # Clone the fork info(fmt("@{bf}@!==> @|@!" + "Cloning {0}/{1}...".format(gh_username, gh_repo))) temp_dir = tempfile.mkdtemp() new_branch = None title = "{0}: {1} in '{2}' [bloom]".format(repository, version, os.path.basename(gh_path)) body = """\ Increasing version of package(s) in repository `{0}`: - previous version: `{1}` - new version: `{2}` - distro file: `{3}` - bloom version: `{4}` """.format(repository, orig_version or 'null', version, gh_path, bloom.__version__) with change_directory(temp_dir): def _my_run(cmd): info(fmt("@{bf}@!==> @|@!" + str(cmd))) out = check_output(cmd, stderr=subprocess.STDOUT, shell=True) if out: info(out, use_prefix=False) _my_run('git clone https://github.com/{0}/{1}.git'.format(gh_username, gh_repo)) with change_directory(gh_repo): _my_run('git remote add bloom https://github.com/{0}/{1}.git'.format(gh_org, gh_repo)) _my_run('git remote update') _my_run('git fetch') track_branches() branches = get_branches() new_branch = 'bloom-patch-{0}' count = 0 while new_branch.format(count) in branches: count += 1 new_branch = new_branch.format(count) # Final check info(fmt("@{cf}Pull Request Title: @{yf}" + title)) info(fmt("@{cf}Pull Request Body : \n@{yf}" + body)) msg = fmt("@!Open a @|@{cf}pull request@| @!@{kf}from@| @!'@|@!@{bf}" + "{gh_username}/{gh_repo}:{new_branch}".format(**locals()) + "@|@!' @!@{kf}into@| @!'@|@!@{bf}" + "{gh_org}/{gh_repo}:{gh_branch}".format(**locals()) + "@|@!'?") info(msg) if not maybe_continue(): warning("Skipping the pull request...") return _my_run('git checkout -b {0} bloom/{1}'.format(new_branch, gh_branch)) with open('{0}'.format(gh_path), 'w') as f: info(fmt("@{bf}@!==> @|@!Writing new distribution file: ") + str(gh_path)) f.write(updated_distro_file) _my_run('git add {0}'.format(gh_path)) _my_run('git commit -m "{0}"'.format(title)) _my_run('git push origin {0}'.format(new_branch)) # Open the pull request return create_pull_request(gh_org, gh_repo, gh_username, gh_password, gh_branch, new_branch, title, body)