def add_fetch_parser_args(parser, defaults): """Public method for adding standard "fetch" related arguments. This is intended to be used by other commands wanting to be consistent. """ add_argument = FetchSourceCommandFactory.add_argument GitRunner.add_git_parser_args(parser, defaults, pull=True) add_argument( parser, 'fetch_bom_version', defaults, None, help='Pull this BOM version rather than --git_branch.' ' This requires halyard is installed to retrieve the BOM.') add_argument( parser, 'fetch_bom_path', defaults, None, help='Pull versions from this BOM rather than --git_branch.') add_argument(parser, 'git_refresh', defaults, None, help='Refresh existing source from this branch.')
def make_default_options(): """Helper function for creating default options for runner.""" parser = argparse.ArgumentParser() parser.add_argument('--scratch_dir', default=os.path.join('/tmp', 'gittest.%d' % os.getpid())) GitRunner.add_git_parser_args(parser, {}) return parser.parse_args([])
def _do_init_argparser(self, parser, defaults): """Adds command-specific arguments.""" super(PullRequestCommandFactory, self)._do_init_argparser(parser, defaults) GitRunner.add_git_parser_args(parser, defaults, pull_request=True) self.add_argument(parser, 'spinnaker_version', defaults, None, required=True, help='The spinnaker version to publish for.')
def __init__(self, factory, options, repository, branch_decorator, **kwargs): super(PullRequestCommandProcessor, self).__init__(factory, options, **kwargs) self.__repository = repository name = repository.name self.__named_scratch_dir = os.path.join(options.scratch_dir, name) self.__git_dir = os.path.join(options.root_path, name) self.__git = GitRunner(options) self.__branch_decorator = branch_decorator self.__head_branch = '{version}-{decorator}'.format( version=options.spinnaker_version, decorator=self.__branch_decorator)
def setUpClass(cls): cls.git = GitRunner(make_default_options()) cls.base_temp_dir = tempfile.mkdtemp(prefix='git_test') cls.git_dir = os.path.join(cls.base_temp_dir, UPSTREAM_USER, TEST_REPO_NAME) os.makedirs(cls.git_dir) git_dir = cls.git_dir gitify = lambda args: 'git -C "{dir}" {args}'.format(dir=git_dir, args=args) check_subprocess_sequence([ gitify('init'), 'touch "{dir}/base_file"'.format(dir=git_dir), gitify('add "{dir}/base_file"'.format(dir=git_dir)), gitify('commit -a -m "feat(test): added file"'), gitify( 'tag {base_version} HEAD'.format(base_version=VERSION_BASE)), gitify( 'checkout -b {base_branch}'.format(base_branch=BRANCH_BASE)), gitify('checkout -b {a_branch}'.format(a_branch=BRANCH_A)), 'touch "{dir}/a_file"'.format(dir=git_dir), gitify('add "{dir}/a_file"'.format(dir=git_dir)), gitify('commit -a -m "feat(test): added a_file"'), gitify('tag {a_version} HEAD'.format(a_version=VERSION_A)), gitify('checkout -b {b_branch}'.format(b_branch=BRANCH_B)), 'touch "{dir}/b_file"'.format(dir=git_dir), gitify('add "{dir}/b_file"'.format(dir=git_dir)), gitify('commit -a -m "feat(test): added b_file"'), gitify('tag {b_version} HEAD'.format(b_version=VERSION_B)) ])
def main(): """The main command dispatcher.""" GitRunner.stash_and_clear_auth_env_vars() import buildtool.source_commands import buildtool.build_commands import buildtool.bom_commands import buildtool.changelog_commands import buildtool.apidocs_commands import buildtool.image_commands command_modules = [ buildtool.source_commands, buildtool.build_commands, buildtool.bom_commands, buildtool.changelog_commands, buildtool.apidocs_commands, buildtool.image_commands ] options, command_registry = init_options_and_registry( sys.argv[1:], command_modules) logging.basicConfig( format='%(levelname).1s %(asctime)s.%(msecs)03d' ' [%(threadName)s.%(process)d] %(message)s', datefmt='%H:%M:%S', level=STANDARD_LOG_LEVELS[options.log_level]) logging.debug( 'Running with options:\n %s', '\n '.join(yaml.dump(vars(options), default_flow_style=False) .split('\n'))) factory = command_registry.get(options.command) if not factory: logging.error('Unknown command "%s"', options.command) return -1 MetricsManager.startup_metrics(options) try: command = factory.make_command(options) command() finally: MetricsManager.shutdown_metrics() return 0
def __determine_repo_install_args(self): """Determine --spinnaker_dev-github_[owner|user] args for install script.""" options = self.options branch = options.git_branch owner = ('spinnaker' if options.github_user in ('default', 'upstream') else options.github_user) git_dir = os.path.dirname(__file__) if not branch: branch = GitRunner(options).query_local_repository_branch(git_dir) if not owner: url = (GitRunner(options).determine_remote_git_repository( git_dir).url) owner = re.search('github.com/(.+)/spinnaker', url).group(1) return [ '--spinnaker_dev_github_owner', owner, '--spinnaker_dev_github_branch', branch ]
def setUpClass(cls): cls.git = GitRunner(make_default_options()) cls.base_temp_dir = tempfile.mkdtemp(prefix='scm_test') origin_root = os.path.join(cls.base_temp_dir, 'origin_repos') repository_list = [ RemoteGitRepository.make_from_url(url) for url in [ os.path.join(origin_root, SCM_USER, 'RepoOne'), os.path.join(origin_root, SCM_USER, 'RepoTwo'), os.path.join(origin_root, TEST_USER, 'RepoTest') ] ] cls.TEST_SOURCE_REPOSITORIES = { repo.name: repo for repo in repository_list } for repo in repository_list: os.makedirs(repo.url) base_file = os.path.join(repo.url, '{name}-base.txt'.format(name=repo.name)) unique_file = os.path.join( repo.url, '{name}-unique.txt'.format(name=repo.name)) untagged_file = os.path.join( repo.url, '{name}-untagged.txt'.format(name=repo.name)) logging.debug('Initializing repository %s', repo.url) git_prefix = 'git -C "{dir}" '.format(dir=repo.url) run_git = lambda cmd: git_prefix + cmd check_subprocess_sequence([ # BASE_VERSION 'touch "{file}"'.format(file=base_file), run_git(' init'), run_git( 'add "{file}"'.format(file=os.path.basename(base_file))), run_git('commit -a -m "feat(first): first commit"'), run_git('tag {base_version} HEAD'.format( base_version=BASE_VERSION)), # Add Unique branch name per repo run_git('checkout -b {name}-branch'.format(name=repo.name)), 'touch "{file}"'.format(file=unique_file), run_git( 'add "{file}"'.format(file=os.path.basename(unique_file))), run_git('commit -a -m "chore(uniq): unique commit"'), # Add a common branch name, but without a tag on HEAD run_git('checkout master'), run_git('checkout -b {branch}'.format(branch=UNTAGGED_BRANCH)), 'touch "{file}"'.format(file=untagged_file), run_git('add "{file}"'.format( file=os.path.basename(untagged_file))), run_git('commit -a -m "chore(uniq): untagged commit"'), run_git('checkout master') ])
def test_different_repo(self): variants = [ 'http://github.com/user/spinnaker', 'http://github.com/path/user/spinnaker', 'http://github.com/user/spinnaker/path', 'http://github.com/user/spinnaker.github', 'http://github/user/spinnaker', 'http://mydomain.com/user/spinnaker', 'path/user/spinnaker' ] for url in variants[1:]: self.assertFalse(GitRunner.is_same_repo(variants[0], url))
def test_is_same_repo(self): variants = [ 'http://github.com/user/spinnaker', 'http://github.com/user/spinnaker.git', 'https://github.com/user/spinnaker', 'https://github.com/user/spinnaker.git', '[email protected]:user/spinnaker.git', '[email protected]:user/spinnaker.git' ] for url in variants: self.assertTrue(GitRunner.is_same_repo(variants[0], url))
def __init__(self, factory, options, **kwargs): source_repos = kwargs.pop('source_repositories', None) self.__max_threads = kwargs.pop('max_threads', 64) self.__git = kwargs.pop('git', None) or GitRunner(options) self.__scm = None if options.one_at_a_time: logging.debug('Limiting %s to one thread.', factory.name) self.__max_threads = 1 super(RepositoryCommandProcessor, self).__init__(factory, options, **kwargs) # filter needs the options, so this is after our super init call. self.__source_repositories = (self.filter_repositories(source_repos) if source_repos is not None else None)
def setUpClass(cls): cls.git = GitRunner(make_default_options()) cls.base_temp_dir = tempfile.mkdtemp(prefix='git_test') cls.git_dir = os.path.join(cls.base_temp_dir, 'commit_message_test') os.makedirs(cls.git_dir) git_dir = cls.git_dir gitify = lambda args: 'git -C "{dir}" {args}'.format(dir=git_dir, args=args) check_subprocess_sequence([ gitify('init'), 'touch "{dir}/base_file"'.format(dir=git_dir), gitify('add "{dir}/base_file"'.format(dir=git_dir)), gitify('commit -a -m "feat(test): added file"'), gitify( 'tag {base_version} HEAD'.format(base_version=VERSION_BASE)), gitify('checkout -b {patch_branch}'.format( patch_branch=cls.PATCH_BRANCH)), 'touch "{dir}/patch_file"'.format(dir=git_dir), gitify('add "{dir}/patch_file"'.format(dir=git_dir)), gitify('commit -a -m "fix(testA): added patch_file"'), gitify('checkout -b {minor_branch}'.format( minor_branch=cls.MINOR_BRANCH)), 'touch "{dir}/minor_file"'.format(dir=git_dir), gitify('add "{dir}/minor_file"'.format(dir=git_dir)), gitify('commit -a -m "chore(testB): added minor_file"'), gitify('checkout -b {major_branch}'.format( major_branch=cls.MAJOR_BRANCH)), 'touch "{dir}/major_file"'.format(dir=git_dir), gitify('add "{dir}/major_file"'.format(dir=git_dir)), gitify('commit -a -m' ' "feat(testC): added major_file\n' '\nInterestingly enough, this is a BREAKING CHANGE.' '"'), gitify('checkout -b {merged_branch}'.format( merged_branch=cls.MERGED_BRANCH)), gitify('reset --hard HEAD~3'), gitify('merge --squash HEAD@{1}') ]) env = dict(os.environ) if os.path.exists('/bin/true'): env['EDITOR'] = '/bin/true' elif os.path.exists('/usr/bin/true'): env['EDITOR'] = '/usr/bin/true' else: raise NotImplementedError('platform not supported for this test') check_subprocess('git -C "{dir}" commit'.format(dir=git_dir), env=env)
class PullRequestCommandProcessor(CommandProcessor): """Base class for commands that issue pull requests.""" @property def repository(self): """The repository to submit the PR to.""" return self.__repository @property def git_dir(self): """The local repository to push changes from.""" return self.__git_dir @property def named_scratch_dir(self): """The scratch dir associated with the local repository.""" return self.__named_scratch_dir @property def git(self): """Return GitRunner""" return self.__git @property def base_branch(self): """The branch we are sending the pull request to.""" return self.options.git_branch @property def head_branch(self): """The branch we are sending the pull request from.""" return self.__head_branch def __init__(self, factory, options, repository, branch_decorator, **kwargs): super(PullRequestCommandProcessor, self).__init__(factory, options, **kwargs) self.__repository = repository name = repository.name self.__named_scratch_dir = os.path.join(options.scratch_dir, name) self.__git_dir = os.path.join(options.root_path, name) self.__git = GitRunner(options) self.__branch_decorator = branch_decorator self.__head_branch = '{version}-{decorator}'.format( version=options.spinnaker_version, decorator=self.__branch_decorator) def _do_get_commit_message(self): """Returns the commit message to use for the local repository commit.""" raise NotImplementedError() def _do_add_local_repository_files(self): """Returns a list of files we want to push.""" raise NotImplementedError() def _do_command(self): """Write changelog to the origin repository. Open PR against upstream.""" self._ensure_local_repo() git_dir = self.git_dir self.__git.check_git(git_dir, 'checkout ' + self.base_branch) self.__git.delete_local_branch_if_exists(git_dir, self.head_branch) files_added = self._do_add_local_repository_files() message = self._do_get_commit_message() git_commands = [ # These commands are accomodating to a branch already existing # because the branch is on the version, not build. A rejected # build for some reason that is re-tried will have the same version # so the branch may already exist from the earlier attempt. 'checkout -b {head}'.format(head=self.head_branch), 'add {path}'.format( path=' '.join([os.path.abspath(path) for path in files_added])), 'commit -m "{msg}"'.format(msg=message), 'push origin -f {head}'.format(head=self.head_branch) ] origin = self.__git.determine_remote_git_repository(git_dir) logging.info('Pushing branch %s to %s', self.head_branch, origin.url) self.__git.check_git_sequence(git_dir, git_commands) if self.options.no_pr: logging.warning('--no_pr set; NOT creating a pull request.') return self.__git.initiate_github_pull_request(git_dir, message, head=self.head_branch, base=self.base_branch) def _ensure_local_repo(self): """Make sure there's a local repository and fetch one if not.""" if os.path.exists(self.git_dir): return options = self.options name = self.repository.name user = ('spinnaker' if options.github_user in ('default', 'upstream') else options.github_user) url = 'https://github.com/{user}/{name}'.format(user=user, name=name) self.git.clone_repository_to_path(url, self.git_dir, upstream_url=self.repository.url, branch=options.git_branch)
def make_default_options(): """Helper function for creating default options for runner.""" parser = argparse.ArgumentParser() GitRunner.add_git_parser_args(parser, {}) return parser.parse_args([])