Ejemplo n.º 1
0
class PublishSpinnakerCommand(CommandProcessor):
    """"Implements the publish_spinnaker command."""

    # pylint: disable=too-few-public-methods

    def __init__(self, factory, options, **kwargs):
        super(PublishSpinnakerCommand, self).__init__(factory, options,
                                                      **kwargs)
        check_options_set(options, [
            'spinnaker_version', 'spinnaker_release_alias', 'bom_version',
            'changelog_gist_url', 'github_owner', 'min_halyard_version'
        ])

        major, minor, _ = self.options.spinnaker_version.split('.')
        self.__branch = 'release-{major}.{minor}.x'.format(major=major,
                                                           minor=minor)

        options_copy = copy.copy(options)
        self.__bom_scm = BomSourceCodeManager(options_copy,
                                              self.get_input_dir())
        self.__hal = HalRunner(options)
        self.__git = GitRunner(options)
        self.__hal.check_property('spinnaker.config.input.bucket',
                                  options.halyard_bom_bucket)
        if options.only_repositories:
            self.__only_repositories = options.only_repositories.split(',')
        else:
            self.__only_repositories = []

        options_copy.git_branch = self.__branch
        self.__branch_scm = BranchSourceCodeManager(options_copy,
                                                    self.get_input_dir())

    def push_branches_and_tags(self, bom):
        """Update the release branches and tags in each of the BOM repositires."""
        logging.info('Tagging each of the BOM service repos')

        bom_scm = self.__bom_scm
        branch_scm = self.__branch_scm

        # Run in two passes so we dont push anything if we hit a problem
        # in the tagging pass. Since we are spread against multiple repositiories,
        # we cannot do this atomically. The two passes gives us more protection
        # from a partial push due to errors in a repo.
        names_to_push = set([])
        for which in ['tag', 'push']:
            for name, spec in bom['services'].items():
                if name in ['monitoring-third-party', 'defaultArtifact']:
                    # Ignore this, it is redundant to monitoring-daemon
                    continue
                if name == 'monitoring-daemon':
                    name = 'spinnaker-monitoring'
                if self.__only_repositories and name not in self.__only_repositories:
                    logging.debug('Skipping %s because of --only_repositories',
                                  name)
                    continue
                if spec is None:
                    logging.warning('HAVE bom.services.%s = None', name)
                    continue

                repository = bom_scm.make_repository_spec(name)
                bom_scm.ensure_local_repository(repository)
                version = bom_scm.determine_repository_version(repository)
                if which == 'tag':
                    added = self.__branch_and_tag_repository(
                        repository, self.__branch, version)
                    if added:
                        names_to_push.add(name)
                else:
                    self.__push_branch_and_maybe_tag_repository(
                        repository, self.__branch, version, name
                        in names_to_push)

        additional_repositories = list(SPINNAKER_PROCESS_REPOSITORY_NAMES)
        for name in additional_repositories:
            if self.__only_repositories and name not in self.__only_repositories:
                logging.debug('Skipping %s because of --only_repositories',
                              name)
                continue
            repository = branch_scm.make_repository_spec(name)
            branch_scm.ensure_local_repository(repository)
            git_summary = self.__git.collect_repository_summary(
                repository.git_dir)
            version = git_summary.version
            if self.__branch_and_tag_repository(repository, self.__branch,
                                                version):
                self.__push_branch_and_maybe_tag_repository(
                    repository, self.__branch, version, True)

    def __already_have_tag(self, repository, tag):
        """Determine if we already have the tag in the repository."""
        git_dir = repository.git_dir
        existing_commit = self.__git.query_commit_at_tag(git_dir, tag)
        if not existing_commit:
            return False
        want_commit = self.__git.query_local_repository_commit_id(git_dir)
        if want_commit == existing_commit:
            logging.debug('Already have "%s" at %s', tag, want_commit)
            return True

        raise_and_log_error(
            ConfigError(
                '"{tag}" already exists in "{repo}" at commit {have}, not {want}'
                .format(tag=tag,
                        repo=git_dir,
                        have=existing_commit,
                        want=want_commit)))

    def __branch_and_tag_repository(self, repository, branch, version):
        """Create a branch and/or verison tag in the repository, if needed."""
        tag = 'version-' + version
        if self.__already_have_tag(repository, tag):
            return False

        self.__git.check_run(repository.git_dir, 'tag ' + tag)
        return True

    def __push_branch_and_maybe_tag_repository(self, repository, branch,
                                               version, also_tag):
        """Push the branch and verison tag to the origin."""
        tag = 'version-' + version
        self.__git.push_branch_to_origin(repository.git_dir, branch)
        if also_tag:
            self.__git.push_tag_to_origin(repository.git_dir, tag)
        else:
            logging.info('%s was already tagged with "%s" -- skip',
                         repository.git_dir, tag)

    def _do_command(self):
        """Implements CommandProcessor interface."""
        options = self.options
        spinnaker_version = options.spinnaker_version
        options_copy = copy.copy(options)
        options_copy.git_branch = 'master'  # push to master in spinnaker.github.io
        publish_changelog_command = PublishChangelogFactory().make_command(
            options_copy)
        changelog_gist_url = options.changelog_gist_url

        # Make sure changelog exists already.
        # If it does not then fail.
        try:
            logging.debug('Verifying changelog ready at %s',
                          changelog_gist_url)
            urlopen(changelog_gist_url)
        except HTTPError:
            logging.error(exception_to_message)
            raise_and_log_error(
                ConfigError(
                    'Changelog gist "{url}" must exist before publising a release.'
                    .format(url=changelog_gist_url),
                    cause='ChangelogMissing'))

        bom = self.__hal.retrieve_bom_version(self.options.bom_version)
        bom['version'] = spinnaker_version
        bom_path = os.path.join(self.get_output_dir(),
                                spinnaker_version + '.yml')
        write_to_path(yaml.safe_dump(bom, default_flow_style=False), bom_path)
        self.__hal.publish_bom_path(bom_path)
        self.push_branches_and_tags(bom)

        self.__hal.publish_spinnaker_release(spinnaker_version,
                                             options.spinnaker_release_alias,
                                             changelog_gist_url,
                                             options.min_halyard_version)

        logging.info('Publishing changelog')
        publish_changelog_command()
Ejemplo n.º 2
0
class PublishSpinnakerCommand(CommandProcessor):
    """"Implements the publish_spinnaker command."""

    # pylint: disable=too-few-public-methods

    def __init__(self, factory, options, **kwargs):
        super(PublishSpinnakerCommand, self).__init__(factory, options,
                                                      **kwargs)
        check_options_set(options, [
            'spinnaker_version', 'bom_version', 'changelog_gist_url',
            'github_owner', 'min_halyard_version'
        ])

        options_copy = copy.copy(options)
        self.__scm = BomSourceCodeManager(options_copy, self.get_input_dir())
        self.__hal = HalRunner(options)
        self.__git = GitRunner(options)
        self.__hal.check_property('spinnaker.config.input.bucket',
                                  options.halyard_bom_bucket)
        self.__only_repositories = options.only_repositories.split(',')

    def push_branches_and_tags(self, bom):
        """Update the release branches and tags in each of the BOM repositires."""
        major, minor, _ = self.options.spinnaker_version.split('.')
        branch = 'release-{major}.{minor}.x'.format(major=major, minor=minor)
        logging.info('Tagging each of the BOM service repos')

        # Run in two passes so we dont push anything if we hit a problem
        # in the tagging pass. Since we are spread against multiple repositiories,
        # we cannot do this atomically. The two passes gives us more protection
        # from a partial push due to errors in a repo.
        for which in ['tag', 'push']:
            for name, spec in bom['services'].items():
                if name in ['monitoring-third-party', 'defaultArtifact']:
                    # Ignore this, it is redundant to monitoring-daemon
                    continue
                if name == 'monitoring-daemon':
                    name = 'spinnaker-monitoring'
                if self.__only_repositories and name not in self.__only_repositories:
                    logging.debug('Skipping %s because of --only_repositories',
                                  name)
                    continue
                if spec is None:
                    logging.warning('HAVE bom.services.%s = None', name)
                    continue

                repository = self.__scm.make_repository_spec(name)
                self.__scm.ensure_local_repository(repository)
                if which == 'tag':
                    self.__branch_and_tag_repository(repository, branch)
                else:
                    self.__push_branch_and_tag_repository(repository, branch)

    def __branch_and_tag_repository(self, repository, branch):
        """Create a branch and/or verison tag in the repository, if needed."""
        version = self.__scm.determine_repository_version(repository)
        tag = 'version-' + version
        self.__git.check_run(repository.git_dir, 'tag ' + tag)

    def __push_branch_and_tag_repository(self, repository, branch):
        """Push the branch and verison tag to the origin."""
        source_info = self.__scm.lookup_source_info(repository)
        tag = 'version-' + source_info.summary.version
        self.__git.push_branch_to_origin(repository.git_dir, branch)
        self.__git.push_tag_to_origin(repository.git_dir, tag)

    def _do_command(self):
        """Implements CommandProcessor interface."""
        options = self.options
        spinnaker_version = options.spinnaker_version
        publish_changelog_command = PublishChangelogFactory().make_command(
            options)
        changelog_gist_url = options.changelog_gist_url

        # Make sure changelog exists already.
        # If it does not then fail.
        try:
            logging.debug('Verifying changelog ready at %s',
                          changelog_gist_url)
            urllib2.urlopen(changelog_gist_url)
        except urllib2.HTTPError as error:
            logging.error(error.message)
            raise_and_log_error(
                ConfigError(
                    'Changelog gist "{url}" must exist before publising a release.'
                    .format(url=changelog_gist_url),
                    cause='ChangelogMissing'))

        bom = self.__hal.retrieve_bom_version(self.options.bom_version)
        bom['version'] = spinnaker_version
        bom_path = os.path.join(self.get_output_dir(),
                                spinnaker_version + '.yml')
        write_to_path(yaml.dump(bom, default_flow_style=False), bom_path)
        self.push_branches_and_tags(bom)

        self.__hal.publish_spinnaker_release(spinnaker_version,
                                             options.spinnaker_release_alias,
                                             changelog_gist_url,
                                             options.min_halyard_version)

        logging.info('Publishing changelog')
        publish_changelog_command()
Ejemplo n.º 3
0
class PublishSpinnakerCommand(CommandProcessor):
    """"Implements the publish_spinnaker command."""

    # pylint: disable=too-few-public-methods

    def __init__(self, factory, options, **kwargs):
        super(PublishSpinnakerCommand, self).__init__(factory, options,
                                                      **kwargs)
        check_options_set(options, [
            'spinnaker_version', 'bom_version', 'github_owner',
            'min_halyard_version'
        ])

        options_copy = copy.copy(options)
        self.__scm = BomSourceCodeManager(options_copy, self.get_input_dir())
        self.__hal = HalRunner(options)
        self.__git = GitRunner(options)
        self.__hal.check_property('spinnaker.config.input.bucket',
                                  options.halyard_bom_bucket)

    def push_branches_and_tags(self, bom):
        """Update the release branches and tags in each of the BOM repositires."""
        major, minor, _ = self.options.spinnaker_version.split('.')
        branch = 'release-{major}.{minor}.x'.format(major=major, minor=minor)
        logging.info('Tagging each of the BOM service repos')

        # Run in two passes so we dont push anything if we hit a problem
        # in the tagging pass. Since we are spread against multiple repositiories,
        # we cannot do this atomically. The two passes gives us more protection
        # from a partial push due to errors in a repo.
        for which in ['tag', 'push']:
            for name, spec in bom['services'].items():
                if name in ['monitoring-third-party', 'defaultArtifact']:
                    # Ignore this, it is redundant to monitoring-daemon
                    continue
                if spec is None:
                    logging.warning('HAVE bom.services.%s = None', name)
                    continue
                if name == 'monitoring-daemon':
                    name = 'spinnaker-monitoring'
                repository = self.__scm.make_repository_spec(name)
                self.__scm.ensure_local_repository(repository)
                if which == 'tag':
                    self.__branch_and_tag_repository(repository, branch)
                else:
                    self.__push_branch_and_tag_repository(repository, branch)

    def __branch_and_tag_repository(self, repository, branch):
        """Create a branch and/or verison tag in the repository, if needed."""
        source_info = self.__scm.lookup_source_info(repository)
        tag = 'version-' + source_info.summary.version
        self.__git.check_run(repository.git_dir, 'tag ' + tag)

    def __push_branch_and_tag_repository(self, repository, branch):
        """Push the branch and verison tag to the origin."""
        source_info = self.__scm.lookup_source_info(repository)
        tag = 'version-' + source_info.summary.version
        self.__git.push_branch_to_origin(repository.git_dir, branch)
        self.__git.push_tag_to_origin(repository.git_dir, tag)

    def _do_command(self):
        """Implements CommandProcessor interface."""
        options = self.options
        spinnaker_version = options.spinnaker_version
        bom = self.__hal.retrieve_bom_version(self.options.bom_version)
        bom['version'] = spinnaker_version

        self.push_branches_and_tags(bom)
        bom_path = os.path.join(self.get_output_dir(),
                                spinnaker_version + '.yml')
        changelog_base_url = 'https://www.spinnaker.io/%s' % options.github_owner
        changelog_filename = '%s-changelog' % spinnaker_version.replace(
            '.', '-')
        changelog_uri = '%s/community/releases/versions/%s' % (
            changelog_base_url, changelog_filename)

        write_to_path(yaml.dump(bom, default_flow_style=False), bom_path)
        self.__hal.publish_spinnaker_release(spinnaker_version,
                                             options.spinnaker_release_alias,
                                             changelog_uri,
                                             options.min_halyard_version)
Ejemplo n.º 4
0
class PublishSpinnakerCommand(CommandProcessor):
  """"Implements the publish_spinnaker command."""
  # pylint: disable=too-few-public-methods

  def __init__(self, factory, options, **kwargs):
    super(PublishSpinnakerCommand, self).__init__(factory, options, **kwargs)
    check_options_set(options, [
        'spinnaker_version',
        'spinnaker_release_alias',
        'bom_version',
        'changelog_gist_url',
        'github_owner',
        'min_halyard_version'
    ])

    major, minor, _ = self.options.spinnaker_version.split('.')
    self.__branch = 'release-{major}.{minor}.x'.format(
        major=major, minor=minor)

    options_copy = copy.copy(options)
    self.__bom_scm = BomSourceCodeManager(options_copy, self.get_input_dir())
    self.__hal = HalRunner(options)
    self.__git = GitRunner(options)
    self.__hal.check_property(
        'spinnaker.config.input.bucket', options.halyard_bom_bucket)
    if options.only_repositories:
      self.__only_repositories = options.only_repositories.split(',')
    else:
      self.__only_repositories = []

    options_copy.git_branch = self.__branch
    self.__branch_scm = BranchSourceCodeManager(
        options_copy, self.get_input_dir())

  def push_branches_and_tags(self, bom):
    """Update the release branches and tags in each of the BOM repositires."""
    logging.info('Tagging each of the BOM service repos')

    bom_scm = self.__bom_scm
    branch_scm = self.__branch_scm

    # Run in two passes so we dont push anything if we hit a problem
    # in the tagging pass. Since we are spread against multiple repositiories,
    # we cannot do this atomically. The two passes gives us more protection
    # from a partial push due to errors in a repo.
    names_to_push = set([])
    for which in ['tag', 'push']:
      for name, spec in bom['services'].items():
        if name in ['monitoring-third-party', 'defaultArtifact']:
          # Ignore this, it is redundant to monitoring-daemon
          continue
        if name == 'monitoring-daemon':
          name = 'spinnaker-monitoring'
        if self.__only_repositories and name not in self.__only_repositories:
          logging.debug('Skipping %s because of --only_repositories', name)
          continue
        if spec is None:
          logging.warning('HAVE bom.services.%s = None', name)
          continue

        repository = bom_scm.make_repository_spec(name)
        bom_scm.ensure_local_repository(repository)
        version = bom_scm.determine_repository_version(repository)
        if which == 'tag':
          added = self.__branch_and_tag_repository(
              repository, self.__branch, version)
          if added:
            names_to_push.add(name)
        else:
          self.__push_branch_and_maybe_tag_repository(
              repository, self.__branch, version, name in names_to_push)

    additional_repositories = list(SPINNAKER_PROCESS_REPOSITORY_NAMES)
    for name in additional_repositories:
      if self.__only_repositories and name not in self.__only_repositories:
        logging.debug('Skipping %s because of --only_repositories', name)
        continue
      repository = branch_scm.make_repository_spec(name)
      branch_scm.ensure_local_repository(repository)
      git_summary = self.__git.collect_repository_summary(repository.git_dir)
      version = git_summary.version
      if self.__branch_and_tag_repository(
          repository, self.__branch, version):
        self.__push_branch_and_maybe_tag_repository(
            repository, self.__branch, version, True)

  def __already_have_tag(self, repository, tag):
    """Determine if we already have the tag in the repository."""
    git_dir = repository.git_dir
    existing_commit = self.__git.query_commit_at_tag(git_dir, tag)
    if not existing_commit:
      return False
    want_commit = self.__git.query_local_repository_commit_id(git_dir)
    if want_commit == existing_commit:
      logging.debug('Already have "%s" at %s', tag, want_commit)
      return True

    raise_and_log_error(
        ConfigError(
            '"{tag}" already exists in "{repo}" at commit {have}, not {want}'
            .format(tag=tag, repo=git_dir,
                    have=existing_commit, want=want_commit)))
    return False  # not reached

  def __branch_and_tag_repository(self, repository, branch, version):
    """Create a branch and/or version tag in the repository, if needed."""
    tag = 'version-' + version
    if self.__already_have_tag(repository, tag):
      return False

    self.__git.check_run(repository.git_dir, 'tag ' + tag)
    return True

  def __push_branch_and_maybe_tag_repository(self, repository, branch, version,
                                             also_tag):
    """Push the branch and version tag to the origin."""
    tag = 'version-' + version
    self.__git.push_branch_to_origin(repository.git_dir, branch)
    if also_tag:
      self.__git.push_tag_to_origin(repository.git_dir, tag)
    else:
      logging.info('%s was already tagged with "%s" -- skip',
                   repository.git_dir, tag)

  def _do_command(self):
    """Implements CommandProcessor interface."""
    options = self.options
    spinnaker_version = options.spinnaker_version
    options_copy = copy.copy(options)
    options_copy.git_branch = 'master'  # push to master in spinnaker.github.io
    publish_changelog_command = PublishChangelogFactory().make_command(
        options_copy)
    changelog_gist_url = options.changelog_gist_url

    # Make sure changelog exists already.
    # If it does not then fail.
    try:
      logging.debug('Verifying changelog ready at %s', changelog_gist_url)
      urlopen(changelog_gist_url)
    except HTTPError:
      logging.error(exception_to_message)
      raise_and_log_error(
          ConfigError(
              'Changelog gist "{url}" must exist before publising a release.'
              .format(url=changelog_gist_url),
              cause='ChangelogMissing'))

    bom = self.__hal.retrieve_bom_version(self.options.bom_version)
    bom['version'] = spinnaker_version
    bom_path = os.path.join(self.get_output_dir(), spinnaker_version + '.yml')
    write_to_path(yaml.safe_dump(bom, default_flow_style=False), bom_path)
    self.__hal.publish_bom_path(bom_path)
    self.push_branches_and_tags(bom)

    self.__hal.publish_spinnaker_release(
        spinnaker_version, options.spinnaker_release_alias, changelog_gist_url,
        options.min_halyard_version)

    logging.info('Publishing changelog')
    publish_changelog_command()