def make_fake_repository(packages, root): """Create a new git repository that contains the given Rez packages. This function is a bit hacky. It creates a git repository, which is fine, but Rez packages create "in-memory" packages based on actual package.py files on-disk. So the packages need to copied to the folder where the repository was created and "re-queried" in order to be "true" developer Rez packages. If there was a way to easily create a developer Rez package, I'd do that. But meh, too much work. Args: packages (iter[:class:`rez.developer_package.DeveloperPackage`]): The Rez packages that will be copied into the new git repository. root (str): The folder on-disk that represents the top-level folder for every Rez package in `packages`. Returns: tuple[:class:`git.Repo`, list[:class:`rez.developer_package.DeveloperPackage`]]: The newly created repository + the Rez packages that got copied into it. """ repository_root = os.path.join( tempfile.mkdtemp(suffix="_clone_repository"), "test_folder") os.makedirs(repository_root) initialized_packages = [] for package in packages: package_root = finder.get_package_root(package) relative = os.path.relpath(package_root, root) destination = os.path.join(repository_root, relative) parent = os.path.dirname(destination) if not os.path.isdir(parent): os.makedirs(parent) shutil.copytree(package_root, destination) initialized_packages.append( packages_.get_developer_package(destination)) remote_root = tempfile.mkdtemp(suffix="_remote_bare_repository") # `git.Repo.init` needs to build from a non-existent folder. So we `shutil.rmtree` here shutil.rmtree(remote_root) remote_root += ".git" # bare repositories, by convention, end in ".git" remote = git.Repo.init(remote_root, bare=True) repository = git.Repo.init(repository_root) repository.index.add( [item for item in os.listdir(repository_root) if item != ".git"]) repository.index.commit("initial commit") repository.create_remote("origin", url=remote.working_dir) origin = repository.remotes.origin origin.push(refspec="master:master") repository.heads.master.set_tracking_branch( origin.refs.master) # set local "master" to track remote "master return repository, initialized_packages, remote_root
def _run_and_catch(function, package): known_issues = ( # :func:`is_not_a_python_package` can potentially raise any of these exceptions rez_exceptions.PackageNotFoundError, rez_exceptions.ResolvedContextError, # :func:`has_documentation` raises this exception exceptions.NoGitRepository, ) try: return function(package), [] except known_issues as error: path = finder.get_package_root(package) return ( False, [ exceptions.InvalidPackage(package, os.path.normpath(path), str(error)) ], ) except Exception as error: # pylint: disable=broad-except path, message = worker.handle_generic_exception(error, package) return ( False, [ exceptions.InvalidPackage(package, path, "Generic error: " + message, full_message=str(error)) ], )
def get_repository(package): """Get the git repository of a Rez package. Args: package (:class:`rez.packages_.Package`): The object that should either have a git repository defined or is itself inside of a git repository. Raises: ValueError: If `package` is broken or not in a Git repository. Returns: :class:`git.Repo`: The git repository, if found. This function will either always return something or error out. """ path = finder.get_package_root(package) if not path: raise ValueError( 'Package "{package}" has no path on-disk.'.format(package=package)) try: return git.Repo(path, search_parent_directories=True) except exc.InvalidGitRepositoryError: # pylint: disable=no-member try: return _guess_repository_from_symlinks(path) except ( RuntimeError, exc.InvalidGitRepositoryError, # pylint: disable=no-member ): raise ValueError( 'Package "{package}" in "{path}" has no Git repository.'. format(package=package, path=path))
def run(cls, package, _): """Find a README.md file using a Rez package. Args: package (:class:`rez.packages_.DeveloperPackage`): The Rez package whose root directory will be used to search for a README file. Returns: list[:class:`.Description`]: If no issues are found, return an empty list. Otherwise, return one description of each found issue. """ root = finder.get_package_root(package) if cls._file_name in [ os.path.splitext(name)[0] for name in os.listdir(root) ]: return [] code = base_checker.Code(short_name="E", long_name=cls.get_long_code()) location = message_description.Location( path=root, row=0, column=0, text="", ) return [ message_description.Description([cls._summary], location, code=code), ]
def handle_generic_exception(error, package): """Get a printable strin for an error get the path to the Rez package that triggered it. This function is mainly used for handling exceptions. Args: error (:class:`Exception`): Some Python exception. package (:class:`rez.packages_.DeveloperPackage`): The package that triggered the error. Returns: tuple[str, str]: The found path and the exception message. """ # Plugin functions can raise any exception so they must be caught, here path = finder.get_package_root(package) if hasattr(error, "message"): message = error.message else: message = str(error) if not message: try: message = error.value.short_msg except AttributeError: pass return path, str(message)
def test_source_variant(self, run_command, has_documentation): """Create a source (non-built) Rez package that has 1+ variants and run a command on it. Args: run_command (:class:`mock.MagicMock`): A replacement for the function that would normally run as part of the commands that run on a Rez package. If this function gets run, we know that this test passes. """ has_documentation.side_effect = [False, True] packages = self._setup_test( run_command, package_common.make_source_variant_python_package) roots = list( set( inspection.get_packages_path_from_package(package) for package in packages)) directory = tempfile.mkdtemp(suffix="_some_build_location") self.delete_item_later(directory) build_package = package_common.make_build_python_package( textwrap.dedent("""\ name = "project_b" version = "2.0.0" revision = { "push_url": "fake_git_repo", } """), "project_b", "2.0.0", directory, ) build_package = finder.get_nearest_rez_package( os.path.join(build_package)) build_root = inspection.get_packages_path_from_package(build_package) paths = roots + [build_root] with rez_configuration.patch_packages_path(paths): self._test( ( set(), [], [ # Important note: "project_b" doesn't actually already # have documentation. It's a result of `side_effect`, above. # worker.Skip( build_package, finder.get_package_root(build_package), "Python package already has documentation.", ) ], ), paths, ) self.assertEqual(1, run_command.call_count)
def _is_definition(package, format_, search=True): """Check for if a package defines a Rez package file. Except if we've already checked the Rez package's repository and still haven't found a good answer, stop searching and just return False, to avoid a cyclic loop. """ if not inspection.is_built_package(package): path = finder.get_package_root(package) try: packages_.get_developer_package(path, format=format_) except rez_exceptions.PackageMetadataError: return False return True if not search: return False repository = get_repository(package) repository_package = get_package(repository.working_dir, package.name) return _is_definition(repository_package, format_=format_, search=False)
def run(cls, package, _): """Check a Rez package for the ``help`` attribute. Args: package (:class:`rez.packages_.DeveloperPackage`): The Rez package that will be checked for help links. _: An unused argument. """ if package.help: return [] summary = "The help attribute is undefined or empty" full = [ summary, "Every Rez package should always point to some documentation.", "Reference: https://github.com/nerdvegas/rez/wiki/Package-Definition-Guide#help", ] root = finder.get_package_root(package) code = base_checker.Code(short_name="E", long_name=cls.get_long_code()) location = message_description.Location(path=root, row=0, column=0, text="") return [ message_description.Description([summary], location, code=code, full=full), ]
def _run_command_on_package(package): """Run the user-provided command on the given Rez package. Args: package (:class:`rez.developer_package.DeveloperPackage`): The Rez package that presumably is a package.yaml file that needs to be changed. Raises: :class:`.InvalidPackage: If `package` is not a package.yaml file. Returns: str: Any error message that occurred from this command, if any. """ if not package.filepath.endswith(".yaml"): raise exceptions.InvalidPackage( package, finder.get_package_root(package), 'Package "{package}" is not a YAML file.'.format( package=package), ) buffer_ = io.StringIO() package.print_info(format_=serialise.FileFormat.py, buf=buffer_) code = buffer_.getvalue() path = os.path.join(finder.get_package_root(package), "package.py") _LOGGER.info('Now creating "%s".', path) # Writing to DeveloperPackage objects is currently bugged. # So instead, we disable caching during write. # # Reference: https://github.com/nerdvegas/rez/issues/857 # with filesystem.make_path_writable( os.path.dirname(os.path.dirname(path))): with serialise.open_file_for_write(path) as handler: handler.write(code) _LOGGER.info('Now removing the old "%s".', package.filepath) os.remove(package.filepath) return ""
def _has_versioned_parent_package_folder(): """bool: Check if this unittest suite is being run from a built Rez package.""" package = finder.get_nearest_rez_package(_CURRENT_DIRECTORY) root = finder.get_package_root(package) folder = os.path.basename(root) return folder == os.environ["REZ_{name}_VERSION".format( name=package.name.upper())]
def _get_missing_documentation_packages(paths=None): packages, invalids, skips = conditional.get_default_latest_packages( paths=paths) invalids = [] output = [] for package in packages: result, invalids_ = _run_and_catch(conditional.is_not_a_python_package, package) if result: skips.append( worker.Skip( package, os.path.normpath(finder.get_package_root(package)), "Rez Package does not define Python packages / modules.", )) continue if invalids_: invalids.extend(invalids_) continue result, invalids_ = _run_and_catch(conditional.has_documentation, package) if result: skips.append( worker.Skip( package, finder.get_package_root(package), "Python package already has documentation.", )) continue if invalids_: invalids.extend(invalids_) continue output.append(package) return output, invalids, skips
def _get_packages_which_must_be_changed(paths=None): """Get every Rez package that has imports to replace. Args: paths (list[str], optional): The directories to search for Rez package families, Default: :attr:`rez.config.config.packages_path`. Returns: tuple[:class:`rez.packages_.Package`, list, list]: All of the found Rez packages and a list of any Rez package that was considered invalid or any Rez packages that were valid but must be skipped, for some reason. """ packages, invalids, skips = conditional.get_default_latest_packages( paths=paths) user_provided_namespaces = _get_user_provided_namespaces() expected_existing_namespaces = {old for old, _ in user_provided_namespaces} output = [] for package in packages: if not repository_area.is_definition(package, serialise.FileFormat.py): skips.append( worker.Skip( package, finder.get_package_root(package), "does not define a package.py file.", )) continue if not _needs_replacement(package, expected_existing_namespaces): skips.append( worker.Skip( package, finder.get_package_root(package), "No namespaces need to be replaced.", )) continue output.append(package) return output, invalids, skips
def _run_command(package, arguments): """Run the user-provided command on the given Rez package. Args: package (:class:`rez.developer_package.DeveloperPackage`): The Rez package that will be used changed. Any command run by this function will do so while cd'ed into the directory of this package. arguments (:class:`argparse.Namespace`): The user-provided, plug-in specific arguments. Specifically, this should bring in - The command that the user wants to run, per-package - The name of the ticket that will be used for git branches - The option to "raise an exception if any error occurs" or whether it's OK to continue. Raises: :class:`.CoreException`: If ``exit_on_error`` is enabled and the user-provided command fails, for any reason. Returns: str: Any error message that occurred from this command, if any. """ command = 'cd "{root}";{arguments.command}'.format( root=finder.get_package_root(package), arguments=arguments) _LOGGER.debug('Command to run "%s".', command) process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() _LOGGER.debug('stdout "%s".', stdout) if stderr: message = ('Package "{package.name}" raised an error when ' '"{command}" command was run. The command may ' "not have been added correctly.".format( package=package, command=command)) _LOGGER.error("Found error.") _LOGGER.error(stderr) if arguments.exit_on_error: raise exceptions.CoreException(message + "\n\n" + stderr) return message if not has_changes(package): return ( 'Command "{arguments.command}" ran but nothing on-disk changed. ' "No PR is needed!".format(arguments=arguments)) return ""
def run(cls, package, _): """Find every URL in a Rez package that points to a bad web address. If the Internet is down, this method returns empty and is skipped. Args: package (:class:`rez.packages_.Package`): A Rez package that may have a ``help`` attribute/function defined. This attribute will be checked for issues. _: An un-used argument. """ if not package.help: return [] if not website.is_internet_on(): _LOGGER.warning( "User has no internet. Checking for help URLs will be skipped." ) return [] urls = url_help.get_invalid_help_urls(package) if not urls: return [] urls = cls._filter_existing_paths(urls, finder.get_package_root(package)) if not urls: return [] summary = "Package help has an un-reachable URL" urls = sorted([(label, url) if label else url for _, label, url in urls]) full = [ summary, 'Found URLs are un-reachable "{urls}".'.format(urls=urls), ] row = package_parser.get_definition_row(package.filepath, "help") location = message_description.Location( path=package.filepath, row=row, column=0, text="", ) code = base_checker.Code(short_name="D", long_name=cls.get_long_code()) return [ message_description.Description([summary], location, code=code, full=full), ]
def test_mix(self, run_command): """Run command on only to the Rez packages that need it. Args: run_command (:class:`mock.MagicMock`): A replacement for the function that would normally run as part of the commands that run on a Rez package. If this function gets run, we know that this test passes. """ run_command.return_value = "" root = os.path.join(tempfile.mkdtemp(), "test_folder") os.makedirs(root) self.delete_item_later(root) packages = [ package_common.make_package("project_a", root, package_common.make_source_package), package_common.make_package( "project_b", root, package_common.make_source_python_package, dependencies={"project_a-1+<2"}, ), ] repository, packages, remote_root = package_common.make_fake_repository( packages, root) self.delete_item_later(repository.working_dir) self.delete_item_later(remote_root) release_path = _release_packages(packages) self.delete_item_later(release_path) package = finder.get_nearest_rez_package( os.path.join(release_path, "project_a", "1.0.0")) self._test( ( set(), [], [ worker.Skip( package, finder.get_package_root(package), "Rez Package does not define Python packages / modules.", ) ], ), [release_path], ) self.assertEqual(1, run_command.call_count)
def _make_generic_installed_package(self): package = self._make_installed_package( "some_package", textwrap.dedent( """\ name = "some_package" version = "1.0.0" build_command = "echo 'foo'" """ ), ) return finder.get_package_root(package)
def test_released_dependency_missing(self, run_command): """Fail to resolve a package because "project_a" could not be found. Args: run_command (:class:`mock.MagicMock`): A replacement for the function that would normally run as part of the commands that run on a Rez package. If this function gets run, we know that this test passes. """ run_command.return_value = "" root = os.path.join(tempfile.mkdtemp(), "test_folder") os.makedirs(root) self.delete_item_later(root) packages = [ package_common.make_package( "project_a", root, package_common.make_source_python_package), package_common.make_package( "project_b", root, package_common.make_source_python_package, dependencies={"project_a-1+<2"}, ), ] repository, packages, remote_root = package_common.make_fake_repository( packages, root) self.delete_item_later(repository.working_dir) self.delete_item_later(remote_root) package = packages[1] package_root = finder.get_package_root(package) with rez_configuration.patch_packages_path([repository.working_dir]): self._test( ( set(), [ exceptions.InvalidPackage( package, package_root, "Package could not be found: project_a-1+<2", ) ], [], ), [repository.working_dir], ) self.assertEqual(1, run_command.call_count)
def _make_test_case(self, name, text, extra_paths=None): """Create a Rez package that has some Python files inside of it. This method exists to make unittesting a bit easier to understand. Note: This method creates Python files whether `text` actually appends to PYTHONPATH or not. They just get ignored by unittests, in that case. Args: name (str): The name of the Rez package family to make. text (str): The source code used for the package.py file. extra_paths (list[str], optional): A list of paths used to search for Rez packages during the Rez resolve that this function calls. If no paths are given, Rez will default to :attr:`rez.config.packages_path` instead. Default is None. Returns: tuple[set[str], str]: The found Python files (excluding __init__.py files) and the parent folder where the created package.py goes. """ if not extra_paths: extra_paths = [] package = self._make_fake_rez_source_package(name, text) root = finder.get_package_root(package) python_root = os.path.join(root, "python") os.makedirs(python_root) open(os.path.join(python_root, "thing.py"), "w").close() open(os.path.join(python_root, "another.py"), "w").close() context = resolved_context.ResolvedContext( ["{package.name}==".format(package=package)], package_paths=[inspection.get_packages_path_from_package(package)] + extra_paths + config.packages_path, # pylint: disable=no-member ) paths = inspection.get_package_python_paths( package, context.get_environ().get("PYTHONPATH", "").split(os.pathsep)) return paths, root
def _needs_replacement(package, user_namespaces): """Figure out if the Rez package has Python files in it that :class:`MoveImports` can act upon. The logic goes like this: - A Rez source python package is assumed to have all its files available - Return whether namespaces are found - If the Rez python package is a released package though, we can't just assume all Python files are available. - The built Rez package may output an .egg or .whl file, for example - So if namespaces are found, then return True - If no namespaces are found, clone the package's repository and try again Args: package (:class:`rez.packages_.Package`): Some Rez package (source or released package) to check for Python imports. user_namespaces (set[str]): Python dot-separated namespaces which a user is trying to replace. If any of the found namespaces match these then it means `package` must have at least one of its modules replaced. Returns: bool: If any of the user-provided Python namespaces were found inside of the given `package`. """ root = finder.get_package_root(package) package = finder.get_nearest_rez_package(root) namespaces = set() for path in move_break_api.expand_paths(root): if path == package.filepath: continue namespaces.update(move_break_api.get_namespaces(path)) if namespaces.intersection(user_namespaces): return True if not inspection.is_built_package(package): return False repository = repository_area.get_repository(package) repository_package = repository_area.get_package(repository.working_dir, package.name) return _needs_replacement(repository_package, user_namespaces)
def _make_symlinkable_source_package(self): """Make a Rez package that builds using symlinks. Returns: :class:`rez.developer_package.DeveloperPackage`: The generated Rez package. """ root = tempfile.mkdtemp(suffix="_source_root") self.delete_item_later(root) package = package_common.make_package( "package_name", root, package_common.make_source_python_package) package_root = finder.get_package_root(package) rezbuild_file = os.path.join(package_root, "rezbuild.py") with open(rezbuild_file, "w") as handler: handler.write( textwrap.dedent('''\ #!/usr/bin/env python # -*- coding: utf-8 -*- """The main module which installs Maya onto the user's system.""" # IMPORT STANDARD LIBRARIES import os import shutil import sys def build(source_path, install_path): for folder in ("python", ): destination = os.path.join(install_path, folder) if os.path.isdir(destination): shutil.rmtree(destination) elif os.path.isfile(destination): os.remove(destination) source = os.path.join(source_path, folder) os.symlink(source, destination) if __name__ == "__main__": build( source_path=os.environ["REZ_BUILD_SOURCE_PATH"], install_path=os.environ["REZ_BUILD_INSTALL_PATH"], ) ''')) return package
def _test(self, package): """Get documentation URL links that are missing for a given Rez package file. Args: package (:class:`rez.packages_.Package`): The Rez package to test. Returns: set[tuple[int, str, str]]: The position, help command label, and URL for each invalid URL found. """ self.delete_item_later(finder.get_package_root(package)) self._fake_package_root() return cli.find_intersphinx_links(package.requires or [])
def test_recursive(self): """Make sure that getting plugins recursively works.""" package = finder.get_nearest_rez_package(_CURRENT_DIRECTORY) found, invalids = cli._find_rez_packages( # pylint: disable=protected-access finder.get_package_root(package), recursive=True, ) found_package = next(iter((found))) self.assertEqual(1, len(found)) self.assertTrue(bool(found)) self.assertEqual(found_package.name, package.name) self.assertEqual(found_package.filepath, package.filepath) self.assertEqual(found_package.version, package.version) self.assertEqual(set(), invalids)
def _bump(package, increment, new_dependencies): rez_bump_api.bump(package, **{increment: 1}) with open(package.filepath, "r") as handler: code = handler.read() new_code = api.add_to_attribute("requires", new_dependencies, code) with filesystem.make_path_writable( os.path.dirname(os.path.dirname(package.filepath))): with serialise.open_file_for_write(package.filepath) as handler: handler.write(new_code) root = finder.get_package_root(package) return finder.get_nearest_rez_package(root)
def add_build_file(package, name): """Change a Rez package so it's "buildable" by Rez again. Specifically, give the package a rezbuild.py file. Args: package (:class:`rez.packages_.Package`): A rez-pip generated Rez package which will be modified. name (str): The name which will be used for the build file. Usually this is "rezbuild.py". """ root = finder.get_package_root(package) with open(os.path.join(root, name), "w") as handler: handler.write(_get_build_command())
def test_normal(self): """Release a package and make sure it is valid.""" def _make_fake_git_repository_at_directory(root): repository = git.Repo.init(root) repository.index.add(".") repository.index.commit("initial commit") source_path = tempfile.mkdtemp(suffix="_rez_package_source_path") self.delete_item_later(source_path) with open(os.path.join(source_path, "package.py"), "w") as handler: handler.write( textwrap.dedent("""\ name = "some_package" version = "1.0.0" build_command = "echo 'foo'" """)) _make_fake_git_repository_at_directory(source_path) package = packages_.get_developer_package(source_path) options = mock.MagicMock() options.cmd = "release" options.debug = False options.message = "Fake release message" options.no_message = False options.process = "local" options.variants = None options.vcs = None parser = mock.MagicMock() parser.prog = "rez release" release_path = tempfile.mkdtemp(suffix="_rez_package_release_path") self.delete_item_later(release_path) with wurlitzer.pipes(): creator.release(finder.get_package_root(package), options, parser, release_path) release_package = packages_.get_developer_package( os.path.join(release_path, "some_package", "1.0.0")) self.assertIsNotNone(release_package)
def _wrap_in_repository(self, package): """Copy the given Rez package into a git repository and re-return it. Args: package (:class:`rez.packages_.Package`): The Rez package that will be copied. Returns: :class:`rez.packages_.Package`: The newly copied Rez package, located inside of the git repository. """ root = os.path.dirname(finder.get_package_root(package)) repository, packages, remote_root = package_common.make_fake_repository( [package], root) self.delete_item_later(repository.working_dir) self.delete_item_later(remote_root) return packages[0]
def run(cls, package, context): """Find a documentation for the Rez package. Args: package (:class:`rez.packages_.DeveloperPackage`): The Rez package that may or may not need documentation. context (:class:`.Context`): A data instance that knows whether `package` has a Python package. If there's no Python package, this checker is cancelled. Returns: list[:class:`.Description`]: If no issues are found, return an empty list. Otherwise, return one description of each found issue. """ if not _has_context_python_package(context): return [] root = finder.get_package_root(package) if conf_manager.get_conf_file(root): return [] # pragma: no cover summary = "No documentation found" full = [ summary, "Consider adding documentation to your Python package.", "Reference: https://www.sphinx-doc.org/en/master/usage/quickstart.html", ] code = base_checker.Code(short_name="E", long_name=cls.get_long_code()) location = message_description.Location(path=root, row=0, column=0, text="") return [ message_description.Description([summary], location, code=code, full=full), ]
def get_repository_url(package): """Get the git repository location (url or file path) of a Rez package. Args: package (:class:`rez.packages_.Package`): The object that should either have a git repository defined or is itself inside of a git repository. Raises: :class:`.exceptions.NoRepositoryRemote`: If `package` is a valid Rez package but doesn't point to a remote repository. Returns: str: The git repository url, if found. Usually, this function will either always return or error out. """ try: url = package.revision["push_url"] # If the package was released, it should have a URL if url: return url except KeyError: # Very old Rez packages don't have push information raise exceptions.InvalidPackage( package, finder.get_package_root(package), 'Package "{package}" has no repository URL.'.format(package=package), ) except ( # Happens when `package` is not the expected type AttributeError, TypeError, ): pass repository = get_repository(package) return get_repository_url_from_repository(repository)
def test_partial_errors(self, find_api_documentation): """Allow other keys in the intersphinx mapping that may not be in the found requirements.""" dependency1 = "foo_bar" dependency2 = "another_one" url = "https://some_path.com" find_api_documentation.return_value = url existing_intersphinx = { "fake_environment": ("http:/some_url.com", None) } package = self._make_fake_package_with_intersphinx_mapping( textwrap.dedent("""\ name = "thing" version = "1.0.0" requires = [ "another_one", "foo_bar", ] """), existing_intersphinx, ) dependency1 = self._make_dependency_package("foo_bar", "1.0.0") dependency2 = self._make_dependency_package("another_one", "2.0.0") config.packages_path.append( # pylint: disable=no-member inspection.get_packages_path_from_package(dependency1)) config.packages_path.append( # pylint: disable=no-member inspection.get_packages_path_from_package(dependency2)) root = finder.get_package_root(package) self.assertEqual(existing_intersphinx, cli.get_existing_intersphinx_links(root)) expected = { dependency1.name: (url, None), dependency2.name: (url, None), } self.assertEqual(expected, cli.find_intersphinx_links(package.requires or []))
def _test_package(self, packages): """Make sure that the given `packages` get "fixed" properly. This method works by setting the "run" command to create a file in the user's source Rez package. If the file exists, it ran successfully. If it doesn't, then the command must have failed. Args: packages (iter[:class:`rez.packages_.Package`]): The Rez packages to run a command on. e.g. adding documentation. """ name = "{base}.txt".format(base=uuid.uuid4()) arguments = _make_arguments(name) command = registry.get_command("shell") runner = functools.partial(command.run, arguments=arguments) with mock.patch( "rez_batch_process.core.gitter.git_registry.get_remote_adapter" ) as patch: patch.create_pull_request = lambda *args, **kwargs: None ran, un_ran, invalids = worker.run(runner, packages) self.assertEqual((set(), []), (un_ran, invalids)) package = next(iter(ran)) package_root = finder.get_package_root(package) git_repository_root = os.path.dirname(package_root) git_repository = git.Repo(git_repository_root) for branch in git_repository.branches: if branch.name.startswith(arguments.pull_request_name): branch.checkout() break test_file = os.path.join(package_root, name) self.assertTrue(os.path.isfile(test_file)) self.assertFalse(inspection.is_built_package(package))