def test_pull_bom(self): input_dir = self.test_root scm = BomSourceCodeManager(self.options, input_dir, bom=self.golden_bom) for repo_name in ALL_STANDARD_TEST_BOM_REPO_NAMES: repository = scm.make_repository_spec(repo_name) self.assertFalse(os.path.exists(repository.git_dir)) scm.ensure_local_repository(repository) self.assertTrue(os.path.exists(repository.git_dir)) git_dir = repository.git_dir spec = scm.git.determine_git_repository_spec(git_dir) self.assertEqual(repository.name, spec.name) self.assertEqual(repository.git_dir, spec.git_dir) self.assertEqual(repository.origin, spec.origin) self.assertIsNone(spec.upstream_or_none()) repo_name = repository.name at_commit = scm.git.query_local_repository_commit_id(git_dir) self.assertEqual( self.repo_commit_map[repo_name]['ORIGIN'], repository.origin) self.assertEqual( self.repo_commit_map[repo_name][PATCH_BRANCH], at_commit) summary = scm.git.collect_repository_summary(git_dir) semver = SemanticVersion.make(BASE_VERSION_TAG) expect_version = semver.next( SemanticVersion.PATCH_INDEX).to_version() self.assertEqual(expect_version, summary.version)
def test_pull_bom(self): input_dir = self.test_root scm = BomSourceCodeManager(self.options, input_dir, bom=self.golden_bom) for repo_name in ALL_STANDARD_TEST_BOM_REPO_NAMES: repository = scm.make_repository_spec(repo_name) self.assertFalse(os.path.exists(repository.git_dir)) scm.ensure_local_repository(repository) self.assertTrue(os.path.exists(repository.git_dir)) git_dir = repository.git_dir spec = scm.git.determine_git_repository_spec(git_dir) self.assertEquals(repository.name, spec.name) self.assertEquals(repository.git_dir, spec.git_dir) self.assertEquals(repository.origin, spec.origin) self.assertIsNone(spec.upstream_or_none()) repo_name = repository.name at_commit = scm.git.query_local_repository_commit_id(git_dir) self.assertEquals( self.repo_commit_map[repo_name]['ORIGIN'], repository.origin) self.assertEquals( self.repo_commit_map[repo_name][PATCH_BRANCH], at_commit) summary = scm.git.collect_repository_summary(git_dir) semver = SemanticVersion.make(BASE_VERSION_TAG) expect_version = semver.next( SemanticVersion.PATCH_INDEX).to_version() self.assertEquals(expect_version, summary.version)
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.__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.__process_scm = BranchSourceCodeManager( options_copy, self.get_input_dir())
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 init_argparser(self, parser, defaults): super(PublishSpinCommandFactory, self).init_argparser( parser, defaults) self.add_argument( parser, 'spin_bucket', defaults, None, help='The bucket to publish spin binaries to.') self.add_argument( parser, 'spin_credentials_path', defaults, None, help='The credentials to use to authenticate with the bucket.') self.add_argument( parser, 'spin_version', defaults, None, help='The semantic version of the release to publish.') # BomSourceCodeManager adds bom_version and bom_path arguments to fetch BOMs. BomSourceCodeManager.add_parser_args(parser, defaults)
def init_argparser(self, parser, defaults): """Adds command-specific arguments.""" super(BuildSpinCommandFactory, self).init_argparser(parser, defaults) self.add_argument( parser, 'build_number', defaults, DEFAULT_BUILD_NUMBER, help='The the build number to use when building spin.') self.add_argument( parser, 'spin_bucket', defaults, None, help='The bucket to publish spin binaries to.') self.add_argument( parser, 'spin_credentials_path', defaults, None, help='The credentials to use to authenticate with the bucket.') # BomSourceCodeManager adds bom_version and bom_path arguments to fetch BOMs. BomSourceCodeManager.add_parser_args(parser, defaults)
def init_argparser(self, parser, defaults): """Adds command-specific arguments.""" super(BuildSpinCommandFactory, self).init_argparser(parser, defaults) self.add_argument( parser, 'build_number', defaults, DEFAULT_BUILD_NUMBER, help='The the build number to use when building spin.') self.add_argument( parser, 'spin_bucket', defaults, None, help='The bucket to publish spin binaries to.') self.add_argument( parser, 'spin_credentials_path', defaults, None, help='The credentials to use to authenticate with the bucket.') # BomSourceCodeManager adds bom_version and bom_path arguments to fetch BOMs. BomSourceCodeManager.add_parser_args(parser, defaults)
def init_argparser(self, parser, defaults): GitRunner.add_parser_args(parser, defaults) GitRunner.add_publishing_parser_args(parser, defaults) super(PublishSpinCommandFactory, self).init_argparser( parser, defaults) self.add_argument( parser, 'spin_bucket', defaults, None, help='The bucket to publish spin binaries to.') self.add_argument( parser, 'spin_credentials_path', defaults, None, help='The credentials to use to authenticate with the bucket.') self.add_argument( parser, 'spin_version', defaults, None, help='The semantic version of the release to publish.') # BomSourceCodeManager adds bom_version and bom_path arguments to fetch BOMs. BomSourceCodeManager.add_parser_args(parser, defaults)
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 __init__(self, factory, options, **kwargs): super(BuildSpinCommand, self).__init__( factory, options, source_repository_names=['spin'], **kwargs) self.__gcs_uploader = SpinGcsUploader(options) self.__build_version = None # recorded after build bom_contents = BomSourceCodeManager.load_bom(options) gate_entry = bom_contents.get('services', {}).get('gate', {}) if not gate_entry: raise_and_log_error( ConfigError('No gate service entry found in bom {}'.format(bom_contents))) self.__gate_version = gate_entry['version']
def __init__(self, factory, options, **kwargs): super(BuildSpinCommand, self).__init__( factory, options, source_repository_names=SPIN_REPOSITORY_NAMES, **kwargs) options_copy = copy.copy(options) self.__gcs_uploader = SpinGcsUploader(options) self.__scm = BranchSourceCodeManager(options_copy, self.get_input_dir()) self.__build_version = None # recorded after build bom_contents = BomSourceCodeManager.load_bom(options) gate_entry = bom_contents.get('services', {}).get('gate', {}) if not gate_entry: raise_and_log_error( ConfigError('No gate service entry found in bom {}'.format(bom_contents))) self.__gate_version = gate_entry['version']
def __init__(self, factory, options, **kwargs): options_copy = copy.copy(options) options_copy.git_branch = 'master' options_copy.github_hostname = 'github.com' super(PublishSpinCommand, self).__init__(factory, options_copy, **kwargs) check_options_set(options, ['spin_version']) # Ensure we have a version to promote. bom_contents = BomSourceCodeManager.load_bom(options_copy) gate_entry = bom_contents.get('services', {}).get('gate', {}) if not gate_entry: raise_and_log_error( ConfigError('No gate service entry found in bom {}'.format(bom_contents))) self.__spinnaker_version = options.bom_version or bom_contents['version'] self.__gate_version = gate_entry['version'] self.__stable_version = None # Set after promote_spin. self.__no_changes = False # Set after promote_spin. self.__scm = BranchSourceCodeManager(options_copy, self.get_input_dir()) self.__gcs_uploader = SpinGcsUploader(options)
def __init__(self, factory, options, **kwargs): options_copy = copy.copy(options) options_copy.git_branch = 'master' options_copy.github_hostname = 'github.com' super(PublishSpinCommand, self).__init__(factory, options_copy, **kwargs) check_options_set(options, ['spin_version']) # Ensure we have a version to promote. bom_contents = BomSourceCodeManager.load_bom(options_copy) gate_entry = bom_contents.get('services', {}).get('gate', {}) if not gate_entry: raise_and_log_error( ConfigError('No gate service entry found in bom {}'.format(bom_contents))) self.__spinnaker_version = options.bom_version or bom_contents['version'] self.__gate_version = gate_entry['version'] self.__stable_version = None # Set after promote_spin. self.__no_changes = False # Set after promote_spin. self.__scm = BranchSourceCodeManager(options_copy, self.get_input_dir()) self.__gcs_uploader = SpinGcsUploader(options)
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' ]) 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) if options.only_repositories: self.__only_repositories = options.only_repositories.split(',') else: self.__only_repositories = [] 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. 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 = self.__scm.make_repository_spec(name) self.__scm.ensure_local_repository(repository) if which == 'tag': added = self.__branch_and_tag_repository( repository, branch) if added: names_to_push.add(name) else: self.__push_branch_and_maybe_tag_repository( repository, branch, name in names_to_push) 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): """Create a branch and/or verison tag in the repository, if needed.""" version = self.__scm.determine_repository_version(repository) 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, also_tag): """Push the branch and verison tag to the origin.""" tag = 'version-' + self.__scm.determine_repository_version(repository) 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 as error: 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()
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)