Exemple #1
0
def delete_cmd(track):
    tracks_dict = get_tracks_dict_raw()
    if track not in tracks_dict['tracks']:
        error("Track '{0}' does not exist.".format(track), exit=True)
    del tracks_dict['tracks'][track]
    info("Deleted track '{0}'.".format(track))
    write_tracks_dict_raw(tracks_dict)
Exemple #2
0
def delete_cmd(track):
    tracks_dict = get_tracks_dict_raw()
    if track not in tracks_dict['tracks']:
        error("Track '{0}' does not exist.".format(track), exit=True)
    del tracks_dict['tracks'][track]
    info("Deleted track '{0}'.".format(track))
    write_tracks_dict_raw(tracks_dict)
Exemple #3
0
def main(sysargs=None):
    # Check that the current directory is a serviceable git/bloom repo
    ensure_clean_working_env()
    ensure_git_root()

    # Get tracks
    tracks_dict = get_tracks_dict_raw()
    if not tracks_dict['tracks']:
        error("No tracks configured, first create a track with "
              "'git-bloom-config new <track_name>'", exit=True)

    # Do argparse stuff
    parser = get_argument_parser([str(t) for t in tracks_dict['tracks']])
    parser = add_global_arguments(parser)
    args = parser.parse_args(sysargs)
    handle_global_arguments(args)

    verify_track(args.track, tracks_dict['tracks'][args.track])

    execute_track(args.track, tracks_dict['tracks'][args.track],
                  args.release_increment, args.pretend, args.debug, args.unsafe)

    # Notify the user of success and next action suggestions
    print('\n\n')
    warning("Tip: Check to ensure that the debian tags created have the same "
            "version as the upstream version you are releasing.")
    info(fmt("@{gf}@!Everything went as expected, "
         "you should check that the new tags match your expectations, and "
         "then push to the release repo with:@|"))
    info(fmt("  git push --all && git push --tags  "
             "@{kf}@!# You might have to add --force to the second command if you "
             "are over-writing existing flags"))
Exemple #4
0
def generate_ros_distro_diff(track, repository, distro, distro_file_url, distro_file, distro_file_raw):
    with inbranch('upstream'):
        # Check for package.xml(s)
        try:
            from catkin_pkg.packages import find_packages
        except ImportError:
            debug(traceback.format_exc())
            error("catkin_pkg was not detected, please install it.",
                  file=sys.stderr, exit=True)
        packages = find_packages(os.getcwd())
        if len(packages) == 0:
            warning("No packages found, will not generate 'package: path' entries for rosdistro.")
        track_dict = get_tracks_dict_raw()['tracks'][track]
        last_version = track_dict['last_version']
        release_inc = track_dict['release_inc']
        if repository not in distro_file['repositories']:
            global _user_provided_release_url
            distro_file['repositories'][repository] = {'url': _user_provided_release_url or ''}
        distro_file['repositories'][repository]['version'] = '{0}-{1}'.format(last_version, release_inc)
        if packages and (len(packages) > 1 or packages.keys()[0] != '.'):
            distro_file['repositories'][repository]['packages'] = {}
            for path, package in packages.iteritems():
                if os.path.basename(path) == package.name:
                    distro_file['repositories'][repository]['packages'][package.name] = None
                else:
                    distro_file['repositories'][repository]['packages'][package.name] = path
    distro_file_name = os.path.join('release', distro_file_url.split('/')[-1])
    distro_dump = yaml.dump(distro_file, indent=2, default_flow_style=False)
    if distro_file_raw != distro_dump:
        udiff = difflib.unified_diff(distro_file_raw.splitlines(), distro_dump.splitlines(),
                                     fromfile=distro_file_name, tofile=distro_file_name)
        temp_dir = tempfile.mkdtemp()
        version = distro_file['repositories'][repository]['version']
        udiff_file = os.path.join(temp_dir, repository + '-' + version + '.patch')
        udiff_raw = ''
        info("Unified diff for the ROS distro file located at '{0}':".format(udiff_file))
        for line in udiff:
            if line.startswith('@@'):
                udiff_raw += line
                line = fmt('@{cf}' + line)
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{gf}' + line)
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{rf}' + line)
            if line.startswith(' '):
                line += '\n'
                udiff_raw += line
            info(line, use_prefix=False, end='')
        with open(udiff_file, 'w+') as f:
            f.write(udiff_raw)
        return udiff_file, distro_dump
    else:
        warning("This release resulted in no changes to the ROS distro file...")
    return None, None
Exemple #5
0
def show(args):
    tracks_dict = get_tracks_dict_raw()
    if args.track not in tracks_dict['tracks']:
        error("Track '{0}' does not exist.".format(args.track), exit=True)
    info(
        yaml.dump({args.track: tracks_dict['tracks'][args.track]},
                  indent=2,
                  default_flow_style=False))
Exemple #6
0
def start_summary(track):
    global _original_version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    if 'last_version' not in track_dict or 'release_inc' not in track_dict:
        _original_version = 'null'
    else:
        last_version = track_dict['last_version']  # Actually current version now
        release_inc = track_dict['release_inc']
        _original_version = "{0}-{1}".format(last_version, release_inc)
Exemple #7
0
def start_summary(track):
    global _original_version
    track_dict = get_tracks_dict_raw()["tracks"][track]
    if "last_version" not in track_dict or "release_inc" not in track_dict:
        _original_version = "null"
    else:
        last_version = track_dict["last_version"]  # Actually current version now
        release_inc = track_dict["release_inc"]
        _original_version = "{0}-{1}".format(last_version, release_inc)
Exemple #8
0
def copy_track(src, dst):
    tracks_dict = get_tracks_dict_raw()
    if src not in tracks_dict['tracks']:
        error("Track '{0}' does not exist.".format(src), exit=True)
    if dst in tracks_dict['tracks']:
        error("Track '{0}' already exists.".format(dst), exit=True)
    tracks_dict['tracks'][dst] = copy.deepcopy(tracks_dict['tracks'][src])
    info("Saving '{0}' track.".format(dst))
    write_tracks_dict_raw(tracks_dict)
Exemple #9
0
def copy_track(src, dst):
    tracks_dict = get_tracks_dict_raw()
    if src not in tracks_dict['tracks']:
        error("Track '{0}' does not exist.".format(src), exit=True)
    if dst in tracks_dict['tracks']:
        error("Track '{0}' already exists.".format(dst), exit=True)
    tracks_dict['tracks'][dst] = copy.deepcopy(tracks_dict['tracks'][src])
    info("Saving '{0}' track.".format(dst))
    write_tracks_dict_raw(tracks_dict)
Exemple #10
0
def start_summary(track):
    global _original_version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    if 'last_version' not in track_dict or 'release_inc' not in track_dict:
        _original_version = 'null'
    else:
        last_version = track_dict[
            'last_version']  # Actually current version now
        release_inc = track_dict['release_inc']
        _original_version = "{0}-{1}".format(last_version, release_inc)
Exemple #11
0
def show_current():
    bloom_ls = ls_tree('bloom')
    bloom_files = [f for f, t in bloom_ls.iteritems() if t == 'file']
    if 'bloom.conf' in bloom_files:
        info("Old bloom.conf file detected, up converting...")
        convert_old_bloom_conf()
        bloom_ls = ls_tree('bloom')
        bloom_files = [f for f, t in bloom_ls.iteritems() if t == 'file']
    if 'tracks.yaml' in bloom_files:
        info(yaml.dump(get_tracks_dict_raw(), indent=2,
             default_flow_style=False))
Exemple #12
0
def main(sysargs=None):
    from bloom.config import upconvert_bloom_to_config_branch
    upconvert_bloom_to_config_branch()

    # Check that the current directory is a serviceable git/bloom repo
    ensure_clean_working_env()
    ensure_git_root()

    # Get tracks
    tracks_dict = get_tracks_dict_raw()
    if not tracks_dict['tracks']:
        error(
            "No tracks configured, first create a track with "
            "'git-bloom-config new <track_name>'",
            exit=True)

    # Do argparse stuff
    parser = get_argument_parser([str(t) for t in tracks_dict['tracks']])
    parser = add_global_arguments(parser)
    args = parser.parse_args(sysargs)
    handle_global_arguments(args)

    os.environ['BLOOM_TRACK'] = args.track

    verify_track(args.track, tracks_dict['tracks'][args.track])

    git_clone = GitClone()
    with git_clone:
        quiet_git_clone_warning(True)
        disable_git_clone(True)
        execute_track(args.track,
                      tracks_dict['tracks'][args.track],
                      args.release_increment,
                      args.pretend,
                      args.debug,
                      args.unsafe,
                      interactive=args.interactive)
        disable_git_clone(False)
        quiet_git_clone_warning(False)
    git_clone.commit()

    # Notify the user of success and next action suggestions
    info('\n\n', use_prefix=False)
    warning("Tip: Check to ensure that the debian tags created have the same "
            "version as the upstream version you are releasing.")
    info(
        fmt("@{gf}@!Everything went as expected, "
            "you should check that the new tags match your expectations, and "
            "then push to the release repo with:@|"))
    info(
        fmt("  git push --all && git push --tags  "
            "@{kf}@!# You might have to add --force to the second command if you "
            "are over-writing existing tags"))
Exemple #13
0
def show_current():
    bloom_ls = ls_tree(BLOOM_CONFIG_BRANCH)
    bloom_files = [f for f, t in bloom_ls.iteritems() if t == 'file']
    if 'bloom.conf' in bloom_files:
        info("Old bloom.conf file detected, up converting...")
        convert_old_bloom_conf()
        bloom_ls = ls_tree(BLOOM_CONFIG_BRANCH)
        bloom_files = [f for f, t in bloom_ls.iteritems() if t == 'file']
    if 'tracks.yaml' in bloom_files:
        info(
            yaml.dump(get_tracks_dict_raw(),
                      indent=2,
                      default_flow_style=False))
Exemple #14
0
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
Exemple #15
0
def execute_track(track, track_dict, release_inc, pretend=True, debug=False, fast=False):
    info("Processing release track settings for '{0}'".format(track))
    settings = process_track_settings(track_dict, release_inc)
    # setup extra settings
    archive_dir_path = tempfile.mkdtemp()
    settings['archive_dir_path'] = archive_dir_path
    if settings['release_tag'] != ':{none}':
        archive_file = '{name}-{release_tag}.tar.gz'.format(**settings)
    else:
        archive_file = '{name}.tar.gz'.format(**settings)
    settings['archive_path'] = os.path.join(archive_dir_path, archive_file)
    # execute actions
    info("", use_prefix=False)
    info("Executing release track '{0}'".format(track))
    for action in track_dict['actions']:
        if 'bloom-export-upstream' in action and settings['vcs_type'] == 'tar':
            warning("Explicitly skipping bloom-export-upstream for tar.")
            settings['archive_path'] = settings['vcs_uri']
            continue
        templated_action = template_str(action, settings)
        info(fmt("@{bf}@!==> @|@!" + sanitize(str(templated_action))))
        if pretend:
            continue
        stdout = None
        stderr = None
        if bloom.util._quiet:
            stdout = subprocess.PIPE
            stderr = subprocess.STDOUT
        if debug and 'DEBUG' not in os.environ:
            os.environ['DEBUG'] = '1'
        if fast and 'BLOOM_UNSAFE' not in os.environ:
            os.environ['BLOOM_UNSAFE'] = '1'
        templated_action = templated_action.split()
        templated_action[0] = find_full_path(templated_action[0])
        p = subprocess.Popen(templated_action, stdout=stdout, stderr=stderr,
                             shell=False, env=os.environ.copy())
        out, err = p.communicate()
        if bloom.util._quiet:
            info(out, use_prefix=False)
        ret = p.returncode
        if ret > 0:
            error(fmt(_error + "Error running command '@!{0}'@|")
                  .format(templated_action), exit=True)
        info('', use_prefix=False)
    if not pretend:
        # Update the release_inc
        tracks_dict = get_tracks_dict_raw()
        tracks_dict['tracks'][track]['release_inc'] = settings['release_inc']
        tracks_dict['tracks'][track]['last_version'] = settings['version']
        write_tracks_dict_raw(tracks_dict,
                              'Updating release inc to: ' + str(settings['release_inc']))
Exemple #16
0
def execute_track(track, track_dict, release_inc, pretend=True, debug=False, fast=False):
    info("Processing release track settings for '{0}'".format(track))
    settings = process_track_settings(track_dict, release_inc)
    # setup extra settings
    archive_dir_path = tempfile.mkdtemp()
    settings['archive_dir_path'] = archive_dir_path
    if settings['release_tag'] != ':{none}':
        archive_file = '{name}-{release_tag}.tar.gz'.format(**settings)
    else:
        archive_file = '{name}.tar.gz'.format(**settings)
    settings['archive_path'] = os.path.join(archive_dir_path, archive_file)
    # execute actions
    info("", use_prefix=False)
    info("Executing release track '{0}'".format(track))
    for action in track_dict['actions']:
        if 'bloom-export-upstream' in action and settings['vcs_type'] == 'tar':
            warning("Explicitly skipping bloom-export-upstream for tar.")
            settings['archive_path'] = settings['vcs_uri']
            continue
        templated_action = template_str(action, settings)
        info(fmt("@{bf}@!==> @|@!" + sanitize(str(templated_action))))
        if pretend:
            continue
        stdout = None
        stderr = None
        if bloom.util._quiet:
            stdout = subprocess.PIPE
            stderr = subprocess.STDOUT
        if debug and 'DEBUG' not in os.environ:
            os.environ['DEBUG'] = '1'
        if fast and 'BLOOM_UNSAFE' not in os.environ:
            os.environ['BLOOM_UNSAFE'] = '1'
        templated_action = templated_action.split()
        templated_action[0] = find_full_path(templated_action[0])
        p = subprocess.Popen(templated_action, stdout=stdout, stderr=stderr,
                             shell=False, env=os.environ.copy())
        out, err = p.communicate()
        if bloom.util._quiet:
            info(out, use_prefix=False)
        ret = p.returncode
        if ret > 0:
            error(fmt(_error + "Error running command '@!{0}'@|")
                  .format(templated_action), exit=True)
        info('', use_prefix=False)
    if not pretend:
        # Update the release_inc
        tracks_dict = get_tracks_dict_raw()
        tracks_dict['tracks'][track]['release_inc'] = settings['release_inc']
        tracks_dict['tracks'][track]['last_version'] = settings['version']
        write_tracks_dict_raw(tracks_dict,
                              'Updating release inc to: ' + str(settings['release_inc']))
Exemple #17
0
def new(track, template=None, copy_track=None, overrides={}):
    """
    Creates a new track

    :param track: Name of the track to create
    :param template: Template to base new track off
    :param copy_track: Track to copy values of,
        if '' then use any availabe track if one exists
    :param overrides: dict of entries to override default values
    """
    tracks_dict = get_tracks_dict_raw()
    if track in tracks_dict['tracks']:
        error("Cannot create track '{0}' beause it exists.".format(track))
        error("Run `git-bloom-config edit {0}` instead.".format(track),
              exit=True)
    track_dict = copy.copy(DEFAULT_TEMPLATE)
    template_dict = copy.copy(config_template[template])
    if copy_track is not None:
        if template is not None:
            error("You cannot specify both a template and track to copy.",
                  exit=True)
        if copy_track == '' and len(tracks_dict['tracks']) != 0:
            copy_track = list(reversed(sorted(
                tracks_dict['tracks'].keys())))[0]
        if copy_track and copy_track not in tracks_dict['tracks']:
            error("Cannot copy a track which does not exist: '{0}'".format(
                copy_track),
                  exit=True)
        if copy_track:
            template_dict = tracks_dict['tracks'][copy_track]
        else:
            template_dict = {}
    for key in template_entry_order:
        if key in template_dict:
            track_dict[key].default = template_dict[key]
        if key in overrides:
            track_dict[key].default = overrides[key]
        if track_dict[key].default == ':{name}':
            track_dict[key].default = track
        ret = safe_input(str(track_dict[key]))
        if ret:
            track_dict[
                key].default = ret  # This type checks against self.values
            if ret in [':{none}', 'None']:
                track_dict[key].default = None
        track_dict[key] = track_dict[key].default
    tracks_dict['tracks'][track] = track_dict
    write_tracks_dict_raw(tracks_dict)
    info("Created '{0}' track.".format(track))
Exemple #18
0
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
Exemple #19
0
def new(track, template=None, copy_track=None, overrides={}):
    """
    Creates a new track

    :param track: Name of the track to create
    :param template: Template to base new track off
    :param copy_track: Track to copy values of,
        if '' then use any availabe track if one exists
    :param overrides: dict of entries to override default values
    """
    tracks_dict = get_tracks_dict_raw()
    if track in tracks_dict['tracks']:
        error("Cannot create track '{0}' beause it exists.".format(track))
        error("Run `git-bloom-config edit {0}` instead.".format(track),
              exit=True)
    track_dict = copy.copy(DEFAULT_TEMPLATE)
    template_dict = copy.copy(config_template[template])
    if copy_track is not None:
        if template is not None:
            error("You cannot specify both a template and track to copy.",
                  exit=True)
        if copy_track == '' and len(tracks_dict['tracks']) != 0:
            copy_track = tracks_dict['tracks'].keys()[0]
        if copy_track and copy_track not in tracks_dict['tracks']:
            error("Cannot copy a track which does not exist: '{0}'"
                  .format(copy_track), exit=True)
        if copy_track:
            template_dict = tracks_dict['tracks'][copy_track]
        else:
            template_dict = {}
    for key in template_entry_order:
        if key in template_dict:
            track_dict[key].default = template_dict[key]
        if key in overrides:
            track_dict[key].default = overrides[key]
        if track_dict[key].default == ':{name}':
            track_dict[key].default = track
        ret = safe_input(str(track_dict[key]))
        if ret:
            track_dict[key].default = ret  # This type checks against self.values
            if ret in [':{none}', 'None']:
                track_dict[key].default = None
        track_dict[key] = track_dict[key].default
    tracks_dict['tracks'][track] = track_dict
    write_tracks_dict_raw(tracks_dict)
    info("Created '{0}' track.".format(track))
Exemple #20
0
def generate_ros_distro_diff(track, repository, distro, distro_file_url=ROS_DISTRO_FILE):
    distro_file_url = distro_file_url.format(distro)
    distro_file_raw = fetch_distro_file(distro_file_url)
    distro_file = yaml.load(distro_file_raw)
    with inbranch('upstream'):
        # Check for package.xml(s)
        try:
            from catkin_pkg.packages import find_packages
        except ImportError:
            error("catkin_pkg was not detected, please install it.",
                  file=sys.stderr, exit=True)
        packages = find_packages(os.getcwd())
        if len(packages) == 0:
            warning("No packages found, will not generate 'package: path' entries for rosdistro.")
        track_dict = get_tracks_dict_raw()['tracks'][track]
        last_version = track_dict['last_version']
        release_inc = track_dict['release_inc']
        distro_file['repositories'][repository]['version'] = '{0}-{1}'.format(last_version, release_inc)
        if packages and (len(packages) > 1 or packages.keys()[0] != '.'):
            distro_file['repositories'][repository]['packages'] = {}
            for path, package in packages.iteritems():
                distro_file['repositories'][repository]['packages'][package.name] = path
    distro_file_name = distro_file_url.split('/')[-1]
    # distro_dump_orig = yaml.dump(distro_file_orig, indent=2, default_flow_style=False)
    distro_dump = yaml.dump(distro_file, indent=2, default_flow_style=False)
    udiff = difflib.unified_diff(distro_file_raw.splitlines(), distro_dump.splitlines(),
                                 fromfile=distro_file_name, tofile=distro_file_name)
    if udiff:
        info("Unified diff for the ROS distro file located at '{0}':".format(distro_file_url))
        for line in udiff:
            if line.startswith('@@'):
                line = fmt('@{cf}' + line)
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                line = fmt('@{gf}' + line)
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                line = fmt('@{rf}' + line)
            if line.startswith(' '):
                line += '\n'
            info(line, use_prefix=False, end='')
    else:
        warning("This release resulted in no changes to the ROS distro file...")
Exemple #21
0
def edit(track):
    tracks_dict = get_tracks_dict_raw()
    if track not in tracks_dict['tracks']:
        error("Track '{0}' does not exist.".format(track), exit=True)
    # Ensure the track is complete
    track_dict = tracks_dict['tracks'][track]
    update_track(track_dict)
    # Prompt for updates
    for key in template_entry_order:
        pe = DEFAULT_TEMPLATE[key]
        pe.default = tracks_dict['tracks'][track][key]
        ret = raw_input(str(pe))
        if ret:
            pe.default = ret  # This type checks against self.values
            if ret in [':{none}', 'None']:
                pe.default = None
        tracks_dict['tracks'][track][key] = pe.default
    tracks_dict['tracks'][track] = track_dict
    info("Saving '{0}' track.".format(track))
    write_tracks_dict_raw(tracks_dict)
Exemple #22
0
def edit(track):
    tracks_dict = get_tracks_dict_raw()
    if track not in tracks_dict['tracks']:
        error("Track '{0}' does not exist.".format(track), exit=True)
    # Ensure the track is complete
    track_dict = tracks_dict['tracks'][track]
    update_track(track_dict)
    # Prompt for updates
    for key in template_entry_order:
        pe = DEFAULT_TEMPLATE[key]
        pe.default = tracks_dict['tracks'][track][key]
        ret = raw_input(str(pe))
        if ret:
            pe.default = ret  # This type checks against self.values
            if ret in [':{none}', 'None']:
                pe.default = None
        tracks_dict['tracks'][track][key] = pe.default
    tracks_dict['tracks'][track] = track_dict
    info("Saving '{0}' track.".format(track))
    write_tracks_dict_raw(tracks_dict)
Exemple #23
0
def convert_old_bloom_conf(prefix=None):
    prefix = prefix if prefix is not None else 'convert'
    tracks_dict = get_tracks_dict_raw()
    track = prefix
    track_count = 0
    while track in tracks_dict['tracks']:
        track_count += 1
        track = prefix + str(track_count)
    track_dict = copy.copy(DEFAULT_TEMPLATE)
    cmd = 'git config -f bloom.conf bloom.upstream'
    upstream_repo = check_output(cmd, shell=True).strip()
    cmd = 'git config -f bloom.conf bloom.upstreamtype'
    upstream_type = check_output(cmd, shell=True).strip()
    try:
        cmd = 'git config -f bloom.conf bloom.upstreambranch'
        upstream_branch = check_output(cmd, shell=True).strip()
    except subprocess.CalledProcessError:
        upstream_branch = ''
    for key in template_entry_order:
        if key == 'vcs_uri':
            track_dict[key] = upstream_repo
            continue
        if key == 'vcs_type':
            track_dict[key] = upstream_type
            continue
        if key == 'vcs_uri':
            track_dict[key] = upstream_branch or None
            continue
        track_dict[key] = track_dict[key].default
    debug('Converted bloom.conf:')
    with open('bloom.conf', 'r') as f:
        debug(f.read())
    debug('To this track:')
    debug(str({track: track_dict}))
    tracks_dict['tracks'][track] = track_dict
    write_tracks_dict_raw(tracks_dict)
    execute_command('git rm bloom.conf', shell=True)
    execute_command('git commit -m "Removed bloom.conf"', shell=True)
    # Now move the old bloom branch into master
    upconvert_bloom_to_config_branch()
Exemple #24
0
def convert_old_bloom_conf(prefix=None):
    prefix = prefix if prefix is not None else 'convert'
    tracks_dict = get_tracks_dict_raw()
    track = prefix
    track_count = 0
    while track in tracks_dict['tracks']:
        track_count += 1
        track = prefix + str(track_count)
    track_dict = copy.copy(DEFAULT_TEMPLATE)
    cmd = 'git config -f bloom.conf bloom.upstream'
    upstream_repo = check_output(cmd, shell=True).strip()
    cmd = 'git config -f bloom.conf bloom.upstreamtype'
    upstream_type = check_output(cmd, shell=True).strip()
    try:
        cmd = 'git config -f bloom.conf bloom.upstreambranch'
        upstream_branch = check_output(cmd, shell=True).strip()
    except subprocess.CalledProcessError:
        upstream_branch = ''
    for key in template_entry_order:
        if key == 'vcs_uri':
            track_dict[key] = upstream_repo
            continue
        if key == 'vcs_type':
            track_dict[key] = upstream_type
            continue
        if key == 'vcs_uri':
            track_dict[key] = upstream_branch or None
            continue
        track_dict[key] = track_dict[key].default
    debug('Converted bloom.conf:')
    with open('bloom.conf', 'r') as f:
        debug(f.read())
    debug('To this track:')
    debug(str({track: track_dict}))
    tracks_dict['tracks'][track] = track_dict
    write_tracks_dict_raw(tracks_dict)
    execute_command('git rm bloom.conf', shell=True)
    execute_command('git commit -m "Removed bloom.conf"', shell=True)
    # Now move the old bloom branch into master
    upconvert_bloom_to_config_branch()
Exemple #25
0
def execute_track(track, track_dict, release_inc, pretend=True, debug=False, fast=False):
    info("Processing release track settings for '{0}'".format(track))
    settings = process_track_settings(track_dict, release_inc)
    # setup extra settings
    archive_dir_path = tempfile.mkdtemp()
    settings['archive_dir_path'] = archive_dir_path
    if settings['release_tag'] != ':{none}':
        archive_file = '{name}-{release_tag}.tar.gz'.format(**settings)
    else:
        archive_file = '{name}.tar.gz'.format(**settings)
    settings['archive_path'] = os.path.join(archive_dir_path, archive_file)
    # execute actions
    info("", use_prefix=False)
    info("Executing release track '{0}'".format(track))
    for action in track_dict['actions']:
        if 'bloom-export-upstream' in action and settings['vcs_type'] == 'tar':
            warning("Explicitly skipping bloom-export-upstream for tar.")
            settings['archive_path'] = settings['vcs_uri']
            continue
        templated_action = template_str(action, settings)
        info(fmt("@{bf}@!==> @|@!" + sanitize(str(templated_action))))
        if pretend:
            continue
        stdout = None
        stderr = None
        if bloom.util._quiet:
            stdout = subprocess.PIPE
            stderr = subprocess.STDOUT
        if debug and 'DEBUG' not in os.environ:
            os.environ['DEBUG'] = '1'
        if fast and 'BLOOM_UNSAFE' not in os.environ:
            os.environ['BLOOM_UNSAFE'] = '1'
        templated_action = templated_action.split()
        templated_action[0] = find_full_path(templated_action[0])
        p = subprocess.Popen(templated_action, stdout=stdout, stderr=stderr,
                             shell=False, env=os.environ.copy())
        out, err = p.communicate()
        if bloom.util._quiet:
            info(out, use_prefix=False)
        ret = p.returncode
        if ret > 0:
            if 'bloom-generate' in templated_action[0] and ret == code.GENERATOR_NO_ROSDEP_KEY_FOR_DISTRO:
                error(fmt(_error + "The following generator action reported that it is missing one or more"))
                error(fmt("    @|rosdep keys, but that the key exists in other platforms:"))
                error(fmt("@|'@!{0}'@|").format(templated_action))
                info('', use_prefix=False)
                error(fmt("@|If you are @!@_@{rf}absolutely@| sure that this key is unavailable for the platform in"))
                error(fmt("@|question, the generator can be skipped and you can proceed with the release."))
                if maybe_continue('n', 'Skip generator action and continue with release'):
                    info("\nAction skipped, continuing with release.\n")
                    continue

                info('', use_prefix=False)

            error(fmt(_error + "Error running command '@!{0}'@|")
                  .format(templated_action), exit=True)
        info('', use_prefix=False)
    if not pretend:
        # Update the release_inc
        tracks_dict = get_tracks_dict_raw()
        tracks_dict['tracks'][track]['release_inc'] = settings['release_inc']
        tracks_dict['tracks'][track]['last_version'] = settings['version']
        write_tracks_dict_raw(tracks_dict,
                              'Updating release inc to: ' + str(settings['release_inc']))
Exemple #26
0
def update_summary(track, repository, distro):
    global _original_version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']  # Actually current version now
    release_inc = track_dict['release_inc']
    version = "{0}-{1}".format(last_version, release_inc)
    summary_file = get_summary_file()
    msg = """\
## {repository} - {version}

User `{user}@{hostname}` released the packages in the `{repository}` repository by running `{cmd}` on `{date}`

""".format(
        **{
            'repository': repository,
            'date': get_rfc_2822_date(datetime.datetime.now()),
            'user': getpass.getuser(),
            'hostname': socket.gethostname(),
            'cmd': ' '.join(sys.argv),
            'version': version
        })
    packages = [p.name for p in get_packages().values()]
    if len(packages) > 1:
        msg += "These packages were released:\n"
        for p in sorted(packages):
            msg += "- `{0}`\n".format(p)
    else:
        package_name = packages[0]
        msg += "The `{0}` package was released.\n".format(package_name)
    ignored_packages = get_ignored_packages()
    if ignored_packages:
        msg += "\nThese packages were explicitly ignored:\n"
        for ip in ignored_packages:
            msg += "- `{0}`\n".format(ip)
    summary_file = get_summary_file()
    release_file = get_release_file(distro)
    reps = release_file.repositories
    distro_version = reps[repository].version if repository in reps else None
    msg += """
Version of package(s) in repository `{repo}`:
- rosdistro version: `{rosdistro_pv}`
- old version: `{old_pv}`
- new version: `{new_pv}`

Versions of tools used:
- bloom version: `{bloom_v}`
- catkin_pkg version: `{catkin_pkg_v}`
- rosdep version: `{rosdep_v}`
- rosdistro version: `{rosdistro_v}`
- vcstools version: `{vcstools_v}`
""".format(**dict(
        repo=repository,
        rosdistro_pv=distro_version or 'null',
        old_pv=_original_version,
        new_pv=version,
        bloom_v=bloom.__version__,
        catkin_pkg_v=catkin_pkg.__version__,
        # Until https://github.com/ros-infrastructure/rosdistro/issues/16
        rosdistro_v=pkg_resources.require("rosdistro")[0].version,
        rosdep_v=rosdep2.__version__,
        vcstools_v=vcstools.__version__.version))
    summary_file.write(msg)
Exemple #27
0
def generate_ros_distro_diff(track, repository, distro):
    release_dict = get_release_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning(
            "No packages found, will not generate 'package: path' entries for rosdistro."
        )
    # Get version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']
    release_inc = track_dict['release_inc']
    version = '{0}-{1}'.format(last_version, release_inc)
    # Create a repository if there isn't already one
    if repository not in release_dict['repositories']:
        global _user_provided_release_url
        release_dict['repositories'][repository] = {
            'url': _user_provided_release_url
        }
    # Update the repository
    repo = release_dict['repositories'][repository]
    if 'tags' not in repo:
        repo['tags'] = {}
    repo['tags']['release'] = 'release/%s/{package}/{version}' % distro
    repo['version'] = version
    if 'packages' not in repo:
        repo['packages'] = {}
    for path, pkg in packages.items():
        if pkg.name not in repo['packages']:
            repo['packages'][pkg.name] = {}
        repo['packages'][
            pkg.name]['subfolder'] = path  # This will be shortened
    # Remove any missing packages
    for pkg_name in dict(repo['packages']):
        if pkg_name not in [p.name for p in packages.values()]:
            if pkg_name in repo['packages']:
                del repo['packages'][pkg_name]
    # Do the diff
    distro_file_name = get_relative_release_file_path(distro)
    updated_release_file = rosdistro.ReleaseFile('distro', release_dict)
    distro_dump = yaml_from_release_file(updated_release_file)
    distro_file_raw = load_url_to_file_handle(
        get_release_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        udiff = difflib.unified_diff(distro_file_raw.splitlines(),
                                     distro_dump.splitlines(),
                                     fromfile=distro_file_name,
                                     tofile=distro_file_name)
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir,
                                  repository + '-' + version + '.patch')
        udiff_raw = ''
        info("Unified diff for the ROS distro file located at '{0}':".format(
            udiff_file))
        for line in udiff:
            if line.startswith('@@'):
                udiff_raw += line
                line = fmt('@{cf}' + sanitize(line))
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{gf}' + sanitize(line))
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{rf}' + sanitize(line))
            if line.startswith(' '):
                line += '\n'
                udiff_raw += line
            info(line, use_prefix=False, end='')
        with open(udiff_file, 'w+') as f:
            f.write(udiff_raw)
        return updated_release_file
    else:
        warning(
            "This release resulted in no changes to the ROS distro file...")
    return None
Exemple #28
0
def open_pull_request(track, repository, distro, interactive):
    global _rosdistro_index_commit
    # 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()
    if gh is None:
        return None
    # 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)
    track_dict = get_tracks_dict_raw()['tracks'][track]
    body = u"""\
Increasing version of package(s) in repository `{repository}` to `{version}`:

- upstream repository: {upstream_repo}
- release repository: {release_repo}
- distro file: `{distro_file}`
- bloom version: `{bloom_version}`
- previous version for package: `{orig_version}`
""".format(
        repository=repository,
        orig_version=orig_version or 'null',
        version=version,
        distro_file=base_path,
        bloom_version=bloom.__version__,
        upstream_repo=track_dict['vcs_uri'],
        release_repo=updated_distribution_file.repositories[repository].release_repository.url,
    )
    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}" + sanitize(title)))
            info(fmt("@{cf}Pull Request Body : \n@{yf}" + sanitize(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 interactive and 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")
            if _rosdistro_index_commit is not None:
                _my_run('git reset --hard {_rosdistro_index_commit}'.format(**globals()))
            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)
Exemple #29
0
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)
Exemple #30
0
def execute_track(track,
                  track_dict,
                  release_inc,
                  pretend=True,
                  debug=False,
                  fast=False):
    info("Processing release track settings for '{0}'".format(track))
    settings = process_track_settings(track_dict, release_inc)
    # setup extra settings
    archive_dir_path = tempfile.mkdtemp()
    settings['archive_dir_path'] = archive_dir_path
    if settings['release_tag'] != ':{none}':
        archive_file = '{name}-{release_tag}.tar.gz'.format(**settings)
    else:
        archive_file = '{name}.tar.gz'.format(**settings)
    settings['archive_path'] = os.path.join(archive_dir_path, archive_file)
    # execute actions
    info("", use_prefix=False)
    info("Executing release track '{0}'".format(track))
    for action in track_dict['actions']:
        if 'bloom-export-upstream' in action and settings['vcs_type'] == 'tar':
            warning("Explicitly skipping bloom-export-upstream for tar.")
            settings['archive_path'] = settings['vcs_uri']
            continue
        templated_action = template_str(action, settings)
        info(fmt("@{bf}@!==> @|@!" + sanitize(str(templated_action))))
        if pretend:
            continue
        stdout = None
        stderr = None
        if bloom.util._quiet:
            stdout = subprocess.PIPE
            stderr = subprocess.STDOUT
        if debug and 'DEBUG' not in os.environ:
            os.environ['DEBUG'] = '1'
        if fast and 'BLOOM_UNSAFE' not in os.environ:
            os.environ['BLOOM_UNSAFE'] = '1'
        templated_action = templated_action.split()
        templated_action[0] = find_full_path(templated_action[0])
        p = subprocess.Popen(templated_action,
                             stdout=stdout,
                             stderr=stderr,
                             shell=False,
                             env=os.environ.copy())
        out, err = p.communicate()
        if bloom.util._quiet:
            info(out, use_prefix=False)
        ret = p.returncode
        if ret > 0:
            if 'bloom-generate' in templated_action[
                    0] and ret == code.GENERATOR_NO_ROSDEP_KEY_FOR_DISTRO:
                error(
                    fmt(_error +
                        "The following generator action reported that it is missing one or more"
                        ))
                error(
                    fmt("    @|rosdep keys, but that the key exists in other platforms:"
                        ))
                error(fmt("@|'@!{0}'@|").format(templated_action))
                info('', use_prefix=False)
                error(
                    fmt("@|If you are @!@_@{rf}absolutely@| sure that this key is unavailable for the platform in"
                        ))
                error(
                    fmt("@|question, the generator can be skipped and you can proceed with the release."
                        ))
                if maybe_continue(
                        'n',
                        'Skip generator action and continue with release'):
                    info("\nAction skipped, continuing with release.\n")
                    continue

                info('', use_prefix=False)

            error(fmt(_error + "Error running command '@!{0}'@|").format(
                templated_action),
                  exit=True)
        info('', use_prefix=False)
    if not pretend:
        # Update the release_inc
        tracks_dict = get_tracks_dict_raw()
        tracks_dict['tracks'][track]['release_inc'] = settings['release_inc']
        tracks_dict['tracks'][track]['last_version'] = settings['version']
        # if release tag is set to ask and a custom value is used
        if settings['version'] != settings['release_tag']:
            tracks_dict['tracks'][track]['last_release'] = settings[
                'release_tag']
        write_tracks_dict_raw(
            tracks_dict,
            'Updating release inc to: ' + str(settings['release_inc']))
Exemple #31
0
def show(args):
    tracks_dict = get_tracks_dict_raw()
    if args.track not in tracks_dict['tracks']:
        error("Track '{0}' does not exist.".format(args.track), exit=True)
    info(yaml.dump({args.track: tracks_dict['tracks'][args.track]}, indent=2,
         default_flow_style=False))
Exemple #32
0
def update_summary(track, repository, distro):
    global _original_version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']  # Actually current version now
    release_inc = track_dict['release_inc']
    version = "{0}-{1}".format(last_version, release_inc)
    summary_file = get_summary_file()
    msg = """\
## {repository} ({distro}) - {version}

User `{user}@{hostname}` released the packages in the `{repository}` repository into the \
`{distro}` distro by running `{cmd}` on `{date}`

""".format(
        repository=repository,
        distro=distro,
        date=get_rfc_2822_date(datetime.datetime.now()),
        user=getpass.getuser(),
        hostname=socket.gethostname(),
        cmd=' '.join(sys.argv),
        version=version
    )
    packages = [p.name for p in get_packages().values()]
    if len(packages) > 1:
        msg += "These packages were released:\n"
        for p in sorted(packages):
            msg += "- `{0}`\n".format(p)
    else:
        package_name = packages[0]
        msg += "The `{0}` package was released.\n".format(package_name)
    ignored_packages = get_ignored_packages()
    if ignored_packages:
        msg += "\nThese packages were explicitly ignored:\n"
        for ip in ignored_packages:
            msg += "- `{0}`\n".format(ip)
    summary_file = get_summary_file()
    release_file = get_distribution_file(distro)
    reps = release_file.repositories
    distro_version = None
    if repository in reps and reps[repository].release_repository is not None:
        distro_version = reps[repository].release_repository.version
    msg += """
Version of package(s) in repository `{repo}`:
- rosdistro version: `{rosdistro_pv}`
- old version: `{old_pv}`
- new version: `{new_pv}`

Versions of tools used:
- bloom version: `{bloom_v}`
- catkin_pkg version: `{catkin_pkg_v}`
- rosdep version: `{rosdep_v}`
- rosdistro version: `{rosdistro_v}`
- vcstools version: `{vcstools_v}`
""".format(
        repo=repository,
        rosdistro_pv=distro_version or 'null',
        old_pv=_original_version,
        new_pv=version,
        bloom_v=bloom.__version__,
        catkin_pkg_v=catkin_pkg.__version__,
        # Until https://github.com/ros-infrastructure/rosdistro/issues/16
        rosdistro_v=pkg_resources.require("rosdistro")[0].version,
        rosdep_v=rosdep2.__version__,
        vcstools_v=vcstools.__version__.version
    )
    summary_file.write(msg)
Exemple #33
0
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)
Exemple #34
0
def generate_ros_distro_diff(track, repository, distro):
    distribution_dict = get_distribution_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning("No packages found, will not generate 'package: path' entries for rosdistro.")
    # Get version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']
    release_inc = track_dict['release_inc']
    version = '{0}-{1}'.format(last_version, release_inc)
    # Create a repository if there isn't already one
    if repository not in distribution_dict['repositories']:
        global _user_provided_release_url
        distribution_dict['repositories'][repository] = {}
    # Create a release entry if there isn't already one
    if 'release' not in distribution_dict['repositories'][repository]:
        distribution_dict['repositories'][repository]['release'] = {
            'url': _user_provided_release_url
        }
    # Update the repository
    repo = distribution_dict['repositories'][repository]['release']
    if 'tags' not in repo:
        repo['tags'] = {}
    repo['tags']['release'] = generate_release_tag(distro)
    repo['version'] = version
    if 'packages' not in repo:
        repo['packages'] = []
    for path, pkg in packages.items():
        if pkg.name not in repo['packages']:
            repo['packages'].append(pkg.name)
    # Remove any missing packages
    packages_being_released = [p.name for p in packages.values()]
    for pkg_name in list(repo['packages']):
        if pkg_name not in packages_being_released:
            repo['packages'].remove(pkg_name)
    repo['packages'].sort()

    # Do the diff
    distro_file_name = get_relative_distribution_file_path(distro)
    updated_distribution_file = rosdistro.DistributionFile(distro, distribution_dict)
    distro_dump = yaml_from_distribution_file(updated_distribution_file)
    distro_file_raw = load_url_to_file_handle(get_disitrbution_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        # Calculate the diff
        udiff = difflib.unified_diff(distro_file_raw.splitlines(), distro_dump.splitlines(),
                                     fromfile=distro_file_name, tofile=distro_file_name)
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir, repository + '-' + version + '.patch')
        udiff_raw = ''
        info("Unified diff for the ROS distro file located at '{0}':".format(udiff_file))
        for line in udiff:
            if line.startswith('@@'):
                udiff_raw += line
                line = fmt('@{cf}' + sanitize(line))
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{gf}' + sanitize(line))
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{rf}' + sanitize(line))
            if line.startswith(' '):
                line += '\n'
                udiff_raw += line
            info(line, use_prefix=False, end='')
        # Assert that only this repository is being changed
        distro_file_yaml = yaml.load(distro_file_raw)
        distro_yaml = yaml.load(distro_dump)
        if 'repositories' in distro_file_yaml:
            distro_file_repos = distro_file_yaml['repositories']
            for repo in distro_yaml['repositories']:
                if repo == repository:
                    continue
                if repo not in distro_file_repos or distro_file_repos[repo] != distro_yaml['repositories'][repo]:
                    error("This generated pull request modifies a repository entry other than the one being released.")
                    error("This likely occured because the upstream rosdistro changed during this release.")
                    error("This pull request will abort, please re-run this command with the -p option to try again.",
                          exit=True)
        # Write the diff out to file
        with open(udiff_file, 'w+') as f:
            f.write(udiff_raw)
        # Return the diff
        return updated_distribution_file
    else:
        warning("This release resulted in no changes to the ROS distro file...")
    return None
Exemple #35
0
def generate_substitutions_from_package(
    package,
    os_name,
    os_version,
    ros_distro,
    installation_prefix='/usr',
    pkgrel=0,
    peer_packages=None,
    releaser_history=None,
    fallback_resolver=None
):
    tracks_dict = get_tracks_dict_raw()
    peer_packages = peer_packages or []
    data = {}
    # Name, Version, Description
    data['Name'] = package.name
    data['Version'] = package.version
    data['Description'] = archify_string(package.description)
    # License
    if not package.licenses or not package.licenses[0]:
        error("No license set for package '{0}', aborting.".format(package.name), exit=True)
    data['Licenses'] = package.licenses
    # Websites
    websites = [str(url) for url in package.urls if url.type == 'website']
    data['Homepage'] = websites[0] if websites else ''
    if data['Homepage'] == '':
        warning("No homepage set")
    # Package Release Number
    # Bloom's release number starts at 0 however Arch Linux expects it to starts at 1 by convention.
    data['Pkgrel'] = str(int(pkgrel)+1)
    # Package name
    data['Package'] = sanitize_package_name(package.name)
    # Installation prefix
    data['InstallationPrefix'] = installation_prefix

    # Resolve dependencies
    depends = package.run_depends + package.buildtool_export_depends
    build_depends = package.build_depends + package.buildtool_depends + package.test_depends
    unresolved_keys = depends + build_depends + package.replaces + package.conflicts
    # The installer key is not considered here, but it is checked when the keys are checked before this
    resolved_deps = resolve_dependencies(unresolved_keys, os_name,
                                         os_version, ros_distro,
                                         peer_packages + [d.name for d in package.replaces + package.conflicts],
                                         fallback_resolver)
    data['Depends'] = sorted(
        set(format_depends(depends, resolved_deps))
    )
    data['BuildDepends'] = sorted(
        set(format_depends(build_depends, resolved_deps))
    )
    data['Replaces'] = sorted(
        set(format_depends(package.replaces, resolved_deps))
    )
    data['Conflicts'] = sorted(
        set(format_depends(package.conflicts, resolved_deps))
    )
    # Set the distribution
    data['Distribution'] = os_version
    # Use the time stamp to set the date strings
    stamp = datetime.datetime.now(tz.tzlocal())
    data['Date'] = stamp.strftime('%a %b %d %Y')
    data['ROSDistribution'] = ros_distro
    # Maintainers
    maintainers = []
    for m in package.maintainers:
        maintainers.append(str(m))
    data['Maintainer'] = maintainers[0]
    data['Maintainers'] = ', '.join(maintainers)
    # Changelog
    if releaser_history:
        sorted_releaser_history = sorted(releaser_history,
                                         key=lambda k: LooseVersion(k), reverse=True)
        sorted_releaser_history = sorted(sorted_releaser_history,
                                         key=lambda k: strptime(releaser_history.get(k)[0], '%a %b %d %Y'),
                                         reverse=True)
        changelogs = [(v, releaser_history[v]) for v in sorted_releaser_history]
    else:
        # Ensure at least a minimal changelog
        changelogs = []
    print("Version!",package.version)
    if package.version + '-' + str(pkgrel) not in [x[0] for x in changelogs]:
        changelogs.insert(0, (
            package.version + '-' + str(pkgrel), (
                data['Date'],
                package.maintainers[0].name,
                package.maintainers[0].email
            )
        ))
    data['changelogs'] = changelogs
    # Summarize dependencies
    summarize_dependency_mapping(data, depends, build_depends, resolved_deps)

    def convertToUnicode(obj):
        if sys.version_info.major == 2:
            if isinstance(obj, str):
                return unicode(obj.decode('utf8'))
            elif isinstance(obj, unicode):
                return obj
        else:
            if isinstance(obj, bytes):
                return str(obj.decode('utf8'))
            elif isinstance(obj, str):
                return obj
        if isinstance(obj, list):
            for i, val in enumerate(obj):
                obj[i] = convertToUnicode(val)
            return obj
        elif isinstance(obj, type(None)):
            return None
        elif isinstance(obj, tuple):
            obj_tmp = list(obj)
            for i, val in enumerate(obj_tmp):
                obj_tmp[i] = convertToUnicode(obj_tmp[i])
            return tuple(obj_tmp)
        elif isinstance(obj, int):
            return obj
        elif isinstance(obj, int):
            return obj
        raise RuntimeError('need to deal with type %s' % (str(type(obj))))

    for item in data.items():
        data[item[0]] = convertToUnicode(item[1])

    return data
Exemple #36
0
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)
Exemple #37
0
def generate_ros_distro_diff(track, repository, distro):
    distribution_dict = get_distribution_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning("No packages found, will not generate 'package: path' entries for rosdistro.")
    # Get version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']
    release_inc = track_dict['release_inc']
    version = '{0}-{1}'.format(last_version, release_inc)
    # Create a repository if there isn't already one
    if repository not in distribution_dict['repositories']:
        global _user_provided_release_url
        distribution_dict['repositories'][repository] = {}
    # Create a release entry if there isn't already one
    if 'release' not in distribution_dict['repositories'][repository]:
        distribution_dict['repositories'][repository]['release'] = {
            'url': _user_provided_release_url
        }
    # Update the repository
    repo = distribution_dict['repositories'][repository]['release']
    if 'tags' not in repo:
        repo['tags'] = {}
    repo['tags']['release'] = 'release/%s/{package}/{version}' % distro
    repo['version'] = version
    if 'packages' not in repo:
        repo['packages'] = []
    for path, pkg in packages.items():
        if pkg.name not in repo['packages']:
            repo['packages'].append(pkg.name)
    # Remove any missing packages
    packages_being_released = [p.name for p in packages.values()]
    for pkg_name in list(repo['packages']):
        if pkg_name not in packages_being_released:
            repo['packages'].remove(pkg_name)
    repo['packages'].sort()

    # Do the diff
    distro_file_name = get_relative_distribution_file_path(distro)
    updated_distribution_file = rosdistro.DistributionFile(distro, distribution_dict)
    distro_dump = yaml_from_distribution_file(updated_distribution_file)
    distro_file_raw = load_url_to_file_handle(get_disitrbution_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        udiff = difflib.unified_diff(distro_file_raw.splitlines(), distro_dump.splitlines(),
                                     fromfile=distro_file_name, tofile=distro_file_name)
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir, repository + '-' + version + '.patch')
        udiff_raw = ''
        info("Unified diff for the ROS distro file located at '{0}':".format(udiff_file))
        for line in udiff:
            if line.startswith('@@'):
                udiff_raw += line
                line = fmt('@{cf}' + sanitize(line))
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{gf}' + sanitize(line))
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{rf}' + sanitize(line))
            if line.startswith(' '):
                line += '\n'
                udiff_raw += line
            info(line, use_prefix=False, end='')
        with open(udiff_file, 'w+') as f:
            f.write(udiff_raw)
        return updated_distribution_file
    else:
        warning("This release resulted in no changes to the ROS distro file...")
    return None
Exemple #38
0
def generate_ros_distro_diff(track, repository, distro):
    release_dict = get_release_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning("No packages found, will not generate 'package: path' entries for rosdistro.")
    # Get version
    track_dict = get_tracks_dict_raw()["tracks"][track]
    last_version = track_dict["last_version"]
    release_inc = track_dict["release_inc"]
    version = "{0}-{1}".format(last_version, release_inc)
    # Create a repository if there isn't already one
    if repository not in release_dict["repositories"]:
        global _user_provided_release_url
        release_dict["repositories"][repository] = {"url": _user_provided_release_url}
    # Update the repository
    repo = release_dict["repositories"][repository]
    if "tags" not in repo:
        repo["tags"] = {}
    repo["tags"]["release"] = "release/%s/{package}/{version}" % distro
    repo["version"] = version
    if "packages" not in repo:
        repo["packages"] = {}
    for path, pkg in packages.items():
        if pkg.name not in repo["packages"]:
            repo["packages"][pkg.name] = {}
        repo["packages"][pkg.name]["subfolder"] = path  # This will be shortened
    # Remove any missing packages
    for pkg_name in dict(repo["packages"]):
        if pkg_name not in [p.name for p in packages.values()]:
            if pkg_name in repo["packages"]:
                del repo["packages"][pkg_name]
    # Do the diff
    distro_file_name = get_relative_release_file_path(distro)
    updated_release_file = rosdistro.ReleaseFile("distro", release_dict)
    distro_dump = yaml_from_release_file(updated_release_file)
    distro_file_raw = load_url_to_file_handle(get_release_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        udiff = difflib.unified_diff(
            distro_file_raw.splitlines(), distro_dump.splitlines(), fromfile=distro_file_name, tofile=distro_file_name
        )
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir, repository + "-" + version + ".patch")
        udiff_raw = ""
        info("Unified diff for the ROS distro file located at '{0}':".format(udiff_file))
        for line in udiff:
            if line.startswith("@@"):
                udiff_raw += line
                line = fmt("@{cf}" + sanitize(line))
            if line.startswith("+"):
                if not line.startswith("+++"):
                    line += "\n"
                udiff_raw += line
                line = fmt("@{gf}" + sanitize(line))
            if line.startswith("-"):
                if not line.startswith("---"):
                    line += "\n"
                udiff_raw += line
                line = fmt("@{rf}" + sanitize(line))
            if line.startswith(" "):
                line += "\n"
                udiff_raw += line
            info(line, use_prefix=False, end="")
        with open(udiff_file, "w+") as f:
            f.write(udiff_raw)
        return updated_release_file
    else:
        warning("This release resulted in no changes to the ROS distro file...")
    return None
Exemple #39
0
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'))
Exemple #40
0
def generate_ros_distro_diff(track, repository, distro):
    distribution_dict = get_distribution_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning("No packages found, will not generate 'package: path' entries for rosdistro.")
    # Get version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']
    release_inc = track_dict['release_inc']
    version = '{0}-{1}'.format(last_version, release_inc).encode('utf-8')
    # Create a repository if there isn't already one
    if repository not in distribution_dict['repositories']:
        global _user_provided_release_url
        distribution_dict['repositories'][repository] = {}
    # Create a release entry if there isn't already one
    if 'release' not in distribution_dict['repositories'][repository]:
        distribution_dict['repositories'][repository]['release'.encode('utf-8')] = {
            'url'.encode('utf-8'): _user_provided_release_url
        }
    # Update the repository
    repo = distribution_dict['repositories'][repository]['release']
    if 'tags' not in repo:
        repo['tags'.encode('utf-8')] = {}
    repo['tags']['release'.encode('utf-8')] = generate_release_tag(distro)
    repo['version'.encode('utf-8')] = version
    if 'packages' not in repo:
        repo['packages'.encode('utf-8')] = []
    for path, pkg in packages.items():
        if pkg.name not in repo['packages']:
            repo['packages'].append(pkg.name)
    # Remove any missing packages
    packages_being_released = [p.name for p in packages.values()]
    for pkg_name in list(repo['packages']):
        if pkg_name not in packages_being_released:
            repo['packages'].remove(pkg_name)
    repo['packages'].sort()

    def get_repository_info_from_user():
        data = {}
        while True:
            vcs_type = safe_input('VCS type [git, svn, hg, bzr]: ')
            if vcs_type in ['git', 'svn', 'hg', 'bzr']:
                break
            error("'{0}' is not a valid vcs type.".format(vcs_type))
            if not maybe_continue(msg='Try again'):
                return {}
        data['type'] = vcs_type
        while True:
            url = safe_input('VCS url: ')
            if url:
                break
            error("Nothing entered for url.")
            if not maybe_continue(msg='Try again'):
                return {}
        data['url'] = url
        while True:
            version = safe_input('VCS version [commit, tag, branch, etc]: ')
            if version:
                break
            error("Nothing entered for version.")
            if not maybe_continue(msg='Try again'):
                return {}
        data['version'] = version
        return data

    # Ask for doc entry
    if 'BLOOM_DONT_ASK_FOR_DOCS' not in os.environ:
        docs = distribution_dict['repositories'][repository].get('doc', {})
        if not docs and maybe_continue(msg='Would you like to add documentation information for this repository?'):
            info("Please enter your repository information for the doc generation job.")
            info("This information should point to the repository from which documentation should be generated.")
            docs = get_repository_info_from_user()
        distribution_dict['repositories'][repository]['doc'] = docs

    # Ask for source entry
    if 'BLOOM_DONT_ASK_FOR_SOURCE' not in os.environ:
        source = distribution_dict['repositories'][repository].get('source', {})
        if not source and maybe_continue(msg='Would you like to add source information for this repository?'):
            info("Please enter information which points ot the active development branch for this repository.")
            info("This information is used to run continuous integration jobs and for developers to checkout from.")
            source = get_repository_info_from_user()
        distribution_dict['repositories'][repository]['source'] = source

    # Ask for maintainership information
    if 'BLOOM_DONT_ASK_FOR_MAINTENANCE_STATUS' not in os.environ:
        status = distribution_dict['repositories'][repository].get('status', None)
        description = distribution_dict['repositories'][repository].get('status_description', None)
        if status is None and maybe_continue(msg='Would you like to add a maintenance status for this repository?'):
            info("Please enter a maintenance status.")
            info("Valid maintenance statuses:")
            info("- developed: active development is in progress")
            info("- maintained: no new development, but bug fixes and pull requests are addressed")
            info("- end-of-life: should not be used, will disapear at some point")
            while True:
                status = safe_input('Status: ')
                if status in ['developed', 'maintained', 'end-of-life']:
                    break
                error("'{0}' is not a valid status.".format(status))
                if not maybe_continue(msg='Try again'):
                    status = None
                    break
            if status is not None:
                info("You can also enter a status description.")
                info("This is usually reserved for giving a reason when a status is 'end-of-life'.")
                if description is not None:
                    info("Current status description: {0}".format(description))
                description_in = safe_input('Status Description [press Enter for no change]: ')
                if description_in:
                    description = description_in
        if status is not None:
            distribution_dict['repositories'][repository]['status'] = status
            if description is not None:
                distribution_dict['repositories'][repository]['status_description'] = description

    # Do the diff
    distro_file_name = get_relative_distribution_file_path(distro)
    updated_distribution_file = rosdistro.DistributionFile(distro, distribution_dict)
    distro_dump = yaml_from_distribution_file(updated_distribution_file)
    distro_file_raw = load_url_to_file_handle(get_disitrbution_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        # Calculate the diff
        udiff = difflib.unified_diff(distro_file_raw.splitlines(), distro_dump.splitlines(),
                                     fromfile=distro_file_name, tofile=distro_file_name)
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir, repository + '-' + version + '.patch')
        udiff_raw = ''
        info("Unified diff for the ROS distro file located at '{0}':".format(udiff_file))
        for line in udiff:
            if line.startswith('@@'):
                udiff_raw += line
                line = fmt('@{cf}' + sanitize(line))
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{gf}' + sanitize(line))
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{rf}' + sanitize(line))
            if line.startswith(' '):
                line += '\n'
                udiff_raw += line
            info(line, use_prefix=False, end='')
        # Assert that only this repository is being changed
        distro_file_yaml = yaml.load(distro_file_raw)
        distro_yaml = yaml.load(distro_dump)
        if 'repositories' in distro_file_yaml:
            distro_file_repos = distro_file_yaml['repositories']
            for repo in distro_yaml['repositories']:
                if repo == repository:
                    continue
                if repo not in distro_file_repos or distro_file_repos[repo] != distro_yaml['repositories'][repo]:
                    error("This generated pull request modifies a repository entry other than the one being released.")
                    error("This likely occured because the upstream rosdistro changed during this release.")
                    error("This pull request will abort, please re-run this command with the -p option to try again.",
                          exit=True)
        # Write the diff out to file
        with open(udiff_file, 'w+') as f:
            f.write(udiff_raw)
        # Return the diff
        return updated_distribution_file
    else:
        warning("This release resulted in no changes to the ROS distro file...")
    return None