def initialize_repo(worktree, gitdir=None): """Initialize a git repository for the given `worktree`. NB: The given `worktree` must contain at least one file which will be committed to form an initial commit. :param string worktree: The path to the git work tree. :param string gitdir: An optional path to the `.git` dir to use. :returns: A `Git` repository object that can be used to interact with the repo. :rtype: :class:`pants.scm.git.Git` """ @contextmanager def use_gitdir(): if gitdir: yield gitdir else: with temporary_dir() as d: yield d with use_gitdir() as git_dir, environment_as(GIT_DIR=git_dir, GIT_WORK_TREE=worktree): subprocess.check_call(['git', 'init']) subprocess.check_call( ['git', 'config', 'user.email', '*****@*****.**']) # TODO: This method inherits the global git settings, so if a developer has gpg signing on, this # will turn that off. We should probably just disable reading from the global config somehow: # https://git-scm.com/docs/git-config. subprocess.check_call(['git', 'config', 'commit.gpgSign', 'false']) subprocess.check_call(['git', 'config', 'user.name', 'Your Name']) subprocess.check_call(['git', 'add', '.']) subprocess.check_call(['git', 'commit', '-am', 'Add project files.']) yield Git(gitdir=git_dir, worktree=worktree)
def initialize_repo(worktree: str, *, gitdir: Optional[str] = None) -> Iterator[Git]: """Initialize a git repository for the given `worktree`. NB: The given `worktree` must contain at least one file which will be committed to form an initial commit. :param worktree: The path to the git work tree. :param gitdir: An optional path to the `.git` dir to use. :returns: A `Git` repository object that can be used to interact with the repo. """ @contextmanager def use_gitdir() -> Iterator[str]: if gitdir: yield gitdir else: with temporary_dir() as d: yield d with use_gitdir() as git_dir, environment_as(GIT_DIR=git_dir, GIT_WORK_TREE=worktree): subprocess.run(["git", "init"], check=True) subprocess.run(["git", "config", "user.email", "*****@*****.**"], check=True) # TODO: This method inherits the global git settings, so if a developer has gpg signing on, this # will turn that off. We should probably just disable reading from the global config somehow: # https://git-scm.com/docs/git-config. subprocess.run(["git", "config", "commit.gpgSign", "false"], check=True) subprocess.run(["git", "config", "user.name", "Your Name"], check=True) subprocess.run(["git", "add", "."], check=True) subprocess.run(["git", "commit", "-am", "Add project files."], check=True) yield Git(gitdir=git_dir, worktree=worktree)
def setUpClass(cls): cls.origin = safe_mkdtemp() with pushd(cls.origin): subprocess.check_call(['git', 'init', '--bare']) cls.gitdir = safe_mkdtemp() cls.worktree = safe_mkdtemp() cls.readme_file = os.path.join(cls.worktree, 'README') with environment_as(GIT_DIR=cls.gitdir, GIT_WORK_TREE=cls.worktree): cls.init_repo('depot', cls.origin) touch(cls.readme_file) subprocess.check_call(['git', 'add', 'README']) subprocess.check_call(['git', 'commit', '-am', 'initial commit with decode -> \x81b']) subprocess.check_call(['git', 'tag', 'first']) subprocess.check_call(['git', 'push', '--tags', 'depot', 'master']) subprocess.check_call(['git', 'branch', '--set-upstream', 'master', 'depot/master']) with safe_open(cls.readme_file, 'w') as readme: readme.write('Hello World.') subprocess.check_call(['git', 'commit', '-am', 'Update README.']) cls.clone2 = safe_mkdtemp() with pushd(cls.clone2): cls.init_repo('origin', cls.origin) subprocess.check_call(['git', 'pull', '--tags', 'origin', 'master:master']) with safe_open(os.path.realpath('README'), 'a') as readme: readme.write('--') subprocess.check_call(['git', 'commit', '-am', 'Update README 2.']) subprocess.check_call(['git', 'push', '--tags', 'origin', 'master']) cls.git = Git(gitdir=cls.gitdir, worktree=cls.worktree)
def initialize_repo(worktree, gitdir=None): """Initialize a git repository for the given `worktree`. NB: The given `worktree` must contain at least one file which will be committed to form an initial commit. :param string worktree: The path to the git work tree. :param string gitdir: An optional path to the `.git` dir to use. :returns: A `Git` repository object that can be used to interact with the repo. :rtype: :class:`pants.scm.git.Git` """ @contextmanager def use_gitdir(): if gitdir: yield gitdir else: with temporary_dir() as d: yield d with use_gitdir() as git_dir, environment_as(GIT_DIR=git_dir, GIT_WORK_TREE=worktree): subprocess.check_call(['git', 'init']) subprocess.check_call(['git', 'config', 'user.email', '*****@*****.**']) subprocess.check_call(['git', 'config', 'user.name', 'Your Name']) subprocess.check_call(['git', 'add', '.']) subprocess.check_call(['git', 'commit', '-am', 'Add project files.']) yield Git(gitdir=git_dir, worktree=worktree)
def setUp(self): self.origin = safe_mkdtemp() with pushd(self.origin): subprocess.check_call(['git', 'init', '--bare']) self.gitdir = safe_mkdtemp() self.worktree = safe_mkdtemp() self.readme_file = os.path.join(self.worktree, 'README') with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree): self.init_repo('depot', self.origin) touch(self.readme_file) subprocess.check_call(['git', 'add', 'README']) safe_mkdir(os.path.join(self.worktree, 'dir')) with open(os.path.join(self.worktree, 'dir', 'f'), 'w') as f: f.write("file in subdir") # Make some symlinks os.symlink('f', os.path.join(self.worktree, 'dir', 'relative-symlink')) os.symlink('no-such-file', os.path.join(self.worktree, 'dir', 'relative-nonexistent')) os.symlink('dir/f', os.path.join(self.worktree, 'dir', 'not-absolute\u2764')) os.symlink('../README', os.path.join(self.worktree, 'dir', 'relative-dotdot')) os.symlink('dir', os.path.join(self.worktree, 'link-to-dir')) os.symlink('README/f', os.path.join(self.worktree, 'not-a-dir')) os.symlink('loop1', os.path.join(self.worktree, 'loop2')) os.symlink('loop2', os.path.join(self.worktree, 'loop1')) subprocess.check_call(['git', 'add', 'README', 'dir', 'loop1', 'loop2', 'link-to-dir', 'not-a-dir']) subprocess.check_call(['git', 'commit', '-am', 'initial commit with decode -> \x81b']) self.initial_rev = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip() subprocess.check_call(['git', 'tag', 'first']) subprocess.check_call(['git', 'push', '--tags', 'depot', 'master']) subprocess.check_call(['git', 'branch', '--set-upstream-to', 'depot/master']) with safe_open(self.readme_file, 'w') as readme: readme.write('Hello World.\u2764'.encode('utf-8')) subprocess.check_call(['git', 'commit', '-am', 'Update README.']) self.current_rev = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip() self.clone2 = safe_mkdtemp() with pushd(self.clone2): self.init_repo('origin', self.origin) subprocess.check_call(['git', 'pull', '--tags', 'origin', 'master:master']) with safe_open(os.path.realpath('README'), 'a') as readme: readme.write('--') subprocess.check_call(['git', 'commit', '-am', 'Update README 2.']) subprocess.check_call(['git', 'push', '--tags', 'origin', 'master']) self.git = Git(gitdir=self.gitdir, worktree=self.worktree)
def __call__(self, manifest_entries=None): """Returns a dict suitable for passing to 'manifest_entries' in a 'jvm_binary() definition""" manifest_entries = manifest_entries or {} buildroot = get_buildroot() worktree = Git.detect_worktree( subdir=os.path.join(buildroot, self._parse_context.rel_path)) if worktree: git = Git(worktree=worktree) manifest_entries['Implementation-Version'] = git.commit_id manifest_entries['Built-By'] = pwd.getpwuid(os.getuid()).pw_name return manifest_entries
def test(self): self.assertEqual(set(), self.git.changed_files()) self.assertEqual(set(['README']), self.git.changed_files(from_commit='HEAD^')) tip_sha = self.git.commit_id self.assertTrue(tip_sha) self.assertTrue(tip_sha in self.git.changelog()) self.assertTrue(self.git.tag_name.startswith('first-'), msg='un-annotated tags should be found') self.assertEqual('master', self.git.branch_name) def edit_readme(): with open(self.readme_file, 'a') as readme: readme.write('More data.') edit_readme() with open(os.path.join(self.worktree, 'INSTALL'), 'w') as untracked: untracked.write('make install') self.assertEqual(set(['README']), self.git.changed_files()) self.assertEqual(set(['README', 'INSTALL']), self.git.changed_files(include_untracked=True)) try: # These changes should be rejected because our branch point from origin is 1 commit behind # the changes pushed there in clone 2. self.git.commit('API Changes.') except Scm.RemoteException: with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree): subprocess.check_call(['git', 'reset', '--hard', 'depot/master']) self.git.refresh() edit_readme() self.git.commit('''API '"' " Changes.''') self.git.tag('second', message='''Tagged ' " Changes''') with temporary_dir() as clone: with pushd(clone): self.init_repo('origin', self.origin) subprocess.check_call(['git', 'pull', '--tags', 'origin', 'master:master']) with open(os.path.realpath('README')) as readme: self.assertEqual('--More data.', readme.read()) git = Git() # Check that we can pick up committed and uncommitted changes. with safe_open(os.path.realpath('CHANGES'), 'w') as changes: changes.write('none') subprocess.check_call(['git', 'add', 'CHANGES']) self.assertEqual(set(['README', 'CHANGES']), git.changed_files(from_commit='first')) self.assertEqual('master', git.branch_name) self.assertEqual('second', git.tag_name, msg='annotated tags should be found')
def test_build_file_rev(self): # Test that the build_file_rev global option works. Because the # test framework does not yet support bootstrap options, this test # in fact just directly calls ScmBuildFile.set_rev. with pushd(self.root_dir): subprocess.check_call(['git', 'init']) subprocess.check_call( ['git', 'config', 'user.email', '*****@*****.**']) subprocess.check_call(['git', 'config', 'user.name', 'Your Name']) subprocess.check_call(['git', 'add', '.']) subprocess.check_call(['git', 'commit', '-m' 'initial commit']) subprocess.check_call([ 'rm', '-rf', 'path-that-does-exist', 'grandparent', 'BUILD', 'BUILD.twitter' ]) self._project_tree = ScmProjectTree(self.root_dir, Git(worktree=self.root_dir), 'HEAD') my_buildfile = self.create_buildfile('grandparent/parent/BUILD') buildfile = self.create_buildfile( 'grandparent/parent/BUILD.twitter') self.assertEquals( OrderedSet([my_buildfile, buildfile]), OrderedSet(self.get_build_files_family('grandparent/parent'))) self.assertEquals( OrderedSet([ self.create_buildfile( 'grandparent/parent/child2/child3/BUILD') ]), OrderedSet( self.get_build_files_family( 'grandparent/parent/child2/child3'))) buildfiles = self.scan_buildfiles('grandparent') self.assertEquals( OrderedSet([ self.create_buildfile('grandparent/parent/BUILD'), self.create_buildfile('grandparent/parent/BUILD.twitter'), self.create_buildfile('grandparent/parent/child1/BUILD'), self.create_buildfile( 'grandparent/parent/child1/BUILD.twitter'), self.create_buildfile( 'grandparent/parent/child2/child3/BUILD'), self.create_buildfile('grandparent/parent/child5/BUILD'), ]), buildfiles)
def initialize_repo(worktree): """Initialize git repository for the given worktree.""" gitdir = safe_mkdtemp() with environment_as(GIT_DIR=gitdir, GIT_WORK_TREE=worktree): subprocess.check_call(['git', 'init']) subprocess.check_call( ['git', 'config', 'user.email', '*****@*****.**']) subprocess.check_call(['git', 'config', 'user.name', 'Your Name']) subprocess.check_call(['git', 'add', '.']) subprocess.check_call(['git', 'commit', '-am', 'Add project files.']) yield Git(gitdir=gitdir, worktree=worktree) safe_rmtree(gitdir)
def get_scm(): """Returns the pants Scm if any.""" # TODO(John Sirois): Extract a module/class to carry the bootstrap logic. global _SCM if not _SCM: # We know about git, so attempt an auto-configure git_dir = os.path.join(get_buildroot(), '.git') if os.path.isdir(git_dir): from pants.scm.git import Git git = Git(worktree=get_buildroot()) try: log.info('Detected git repository on branch %s' % git.branch_name) set_scm(git) except git.LocalException: pass return _SCM
def get_scm(): """Returns the pants Scm if any.""" # TODO(John Sirois): Extract a module/class to carry the bootstrap logic. global _SCM if not _SCM: from pants.scm.git import Git # We know about git, so attempt an auto-configure worktree = Git.detect_worktree() if worktree and os.path.isdir(worktree): git = Git(worktree=worktree) try: log.info('Detected git repository at %s on branch %s' % (worktree, git.branch_name)) set_scm(git) except git.LocalException as e: log.info('Failed to load git repository at %s: %s' % (worktree, e)) return _SCM
def get_scm() -> Optional[Scm]: """Returns the pants Scm if any. :API: public """ # TODO(John Sirois): Extract a module/class to carry the bootstrap logic. global _SCM if _SCM: return _SCM from pants.scm.git import Git # We know about git, so attempt an auto-configure worktree = Git.detect_worktree() if worktree and os.path.isdir(worktree): git = Git(worktree=worktree) try: logger.debug(f'Detected git repository at {worktree} on branch {git.branch_name}') set_scm(git) except git.LocalException as e: logger.info(f'Failed to load git repository at {worktree}: {e!r}') return _SCM
def setUp(self): super(ScmBuildFileTest, self).setUp() ScmBuildFile.set_rev('HEAD') ScmBuildFile.set_scm(Git(worktree=self.root_dir))
def test_integration(self): self.assertEqual(set(), self.git.changed_files()) self.assertEqual({'README'}, self.git.changed_files(from_commit='HEAD^')) tip_sha = self.git.commit_id self.assertTrue(tip_sha) self.assertTrue(tip_sha in self.git.changelog()) merge_base = self.git.merge_base() self.assertTrue(merge_base) self.assertTrue(merge_base in self.git.changelog()) with self.assertRaises(Scm.LocalException): self.git.server_url with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree): with self.mkremote('origin') as origin_uri: # We shouldn't be fooled by remotes with origin in their name. with self.mkremote('temp_origin'): origin_url = self.git.server_url self.assertEqual(origin_url, origin_uri) self.assertTrue(self.git.tag_name.startswith('first-'), msg='un-annotated tags should be found') self.assertEqual('master', self.git.branch_name) def edit_readme(): with open(self.readme_file, 'a') as fp: fp.write('More data.') edit_readme() with open(os.path.join(self.worktree, 'INSTALL'), 'w') as untracked: untracked.write('make install') self.assertEqual({'README'}, self.git.changed_files()) self.assertEqual({'README', 'INSTALL'}, self.git.changed_files(include_untracked=True)) # Confirm that files outside of a given relative_to path are ignored self.assertEqual(set(), self.git.changed_files(relative_to='non-existent')) self.git.commit('API Changes.') try: # These changes should be rejected because our branch point from origin is 1 commit behind # the changes pushed there in clone 2. self.git.push() except Scm.RemoteException: with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree): subprocess.check_call( ['git', 'reset', '--hard', 'depot/master']) self.git.refresh() edit_readme() self.git.commit('''API '"' " Changes.''') self.git.push() # HEAD is merged into master self.assertEqual(self.git.commit_date(self.git.merge_base()), self.git.commit_date('HEAD')) self.assertEqual(self.git.commit_date('HEAD'), self.git.commit_date('HEAD')) self.git.tag('second', message='''Tagged ' " Changes''') with temporary_dir() as clone: with pushd(clone): self.init_repo('origin', self.origin) subprocess.check_call( ['git', 'pull', '--tags', 'origin', 'master:master']) with open(os.path.realpath('README'), 'r') as readme: self.assertEqual('--More data.', readme.read()) git = Git() # Check that we can pick up committed and uncommitted changes. with safe_open(os.path.realpath('CHANGES'), 'w') as changes: changes.write('none') subprocess.check_call(['git', 'add', 'CHANGES']) self.assertEqual({'README', 'CHANGES'}, git.changed_files(from_commit='first')) self.assertEqual('master', git.branch_name) self.assertEqual('second', git.tag_name, msg='annotated tags should be found')
def mk_project_tree(self, build_root_src): return ScmProjectTree(build_root_src, Git(worktree=build_root_src), 'HEAD')
def test_integration(self): self.assertEqual(set(), self.git.changed_files()) self.assertEqual({"README"}, self.git.changed_files(from_commit="HEAD^")) tip_sha = self.git.commit_id self.assertTrue(tip_sha) self.assertTrue(tip_sha in self.git.changelog()) merge_base = self.git.merge_base() self.assertTrue(merge_base) self.assertTrue(merge_base in self.git.changelog()) with self.assertRaises(Scm.LocalException): self.git.server_url with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree): with self.mkremote("origin") as origin_uri: # We shouldn't be fooled by remotes with origin in their name. with self.mkremote("temp_origin"): origin_url = self.git.server_url self.assertEqual(origin_url, origin_uri) self.assertTrue(self.git.tag_name.startswith("first-"), msg="un-annotated tags should be found") self.assertEqual("master", self.git.branch_name) def edit_readme(): with open(self.readme_file, "a") as fp: fp.write("More data.") edit_readme() with open(os.path.join(self.worktree, "INSTALL"), "w") as untracked: untracked.write("make install") self.assertEqual({"README"}, self.git.changed_files()) self.assertEqual({"README", "INSTALL"}, self.git.changed_files(include_untracked=True)) # Confirm that files outside of a given relative_to path are ignored self.assertEqual(set(), self.git.changed_files(relative_to="non-existent")) self.git.commit("API Changes.") try: # These changes should be rejected because our branch point from origin is 1 commit behind # the changes pushed there in clone 2. self.git.push() except Scm.RemoteException: with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree): subprocess.check_call( ["git", "reset", "--hard", "depot/master"]) self.git.refresh() edit_readme() self.git.commit("""API '"' " Changes.""") self.git.push() # HEAD is merged into master self.assertEqual(self.git.commit_date(self.git.merge_base()), self.git.commit_date("HEAD")) self.assertEqual(self.git.commit_date("HEAD"), self.git.commit_date("HEAD")) self.git.tag("second", message="""Tagged ' " Changes""") with temporary_dir() as clone: with pushd(clone): self.init_repo("origin", self.origin) subprocess.check_call( ["git", "pull", "--tags", "origin", "master:master"]) with open(os.path.realpath("README"), "r") as readme: self.assertEqual("--More data.", readme.read()) git = Git() # Check that we can pick up committed and uncommitted changes. with safe_open(os.path.realpath("CHANGES"), "w") as changes: changes.write("none") subprocess.check_call(["git", "add", "CHANGES"]) self.assertEqual({"README", "CHANGES"}, git.changed_files(from_commit="first")) self.assertEqual("master", git.branch_name) self.assertEqual("second", git.tag_name, msg="annotated tags should be found")
def setUp(self): self.origin = safe_mkdtemp() with pushd(self.origin): subprocess.check_call(["git", "init", "--bare"]) self.gitdir = safe_mkdtemp() self.worktree = safe_mkdtemp() self.readme_file = os.path.join(self.worktree, "README") with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree): self.init_repo("depot", self.origin) touch(self.readme_file) subprocess.check_call(["git", "add", "README"]) safe_mkdir(os.path.join(self.worktree, "dir")) with open(os.path.join(self.worktree, "dir", "f"), "w") as f: f.write("file in subdir") # Make some symlinks os.symlink("f", os.path.join(self.worktree, "dir", "relative-symlink")) os.symlink( "no-such-file", os.path.join(self.worktree, "dir", "relative-nonexistent")) os.symlink( "dir/f", os.path.join(self.worktree, "dir", "not-absolute\u2764")) os.symlink("../README", os.path.join(self.worktree, "dir", "relative-dotdot")) os.symlink("dir", os.path.join(self.worktree, "link-to-dir")) os.symlink("README/f", os.path.join(self.worktree, "not-a-dir")) os.symlink("loop1", os.path.join(self.worktree, "loop2")) os.symlink("loop2", os.path.join(self.worktree, "loop1")) subprocess.check_call([ "git", "add", "README", "dir", "loop1", "loop2", "link-to-dir", "not-a-dir" ]) subprocess.check_call([ "git", "commit", "-am", "initial commit with decode -> \x81b" ]) self.initial_rev = subprocess.check_output( ["git", "rev-parse", "HEAD"]).strip() subprocess.check_call(["git", "tag", "first"]) subprocess.check_call(["git", "push", "--tags", "depot", "master"]) subprocess.check_call( ["git", "branch", "--set-upstream-to", "depot/master"]) with safe_open(self.readme_file, "wb") as readme: readme.write("Hello World.\u2764".encode()) subprocess.check_call(["git", "commit", "-am", "Update README."]) self.current_rev = subprocess.check_output( ["git", "rev-parse", "HEAD"]).strip() self.clone2 = safe_mkdtemp() with pushd(self.clone2): self.init_repo("origin", self.origin) subprocess.check_call( ["git", "pull", "--tags", "origin", "master:master"]) with safe_open(os.path.realpath("README"), "a") as readme: readme.write("--") subprocess.check_call(["git", "commit", "-am", "Update README 2."]) subprocess.check_call( ["git", "push", "--tags", "origin", "master"]) self.git = Git(gitdir=self.gitdir, worktree=self.worktree)
def mk_project_tree(self, build_root, ignore_patterns=None): return ScmProjectTree(build_root, Git(worktree=build_root), 'HEAD', ignore_patterns)