예제 #1
0
    def test_skip(self):
        """Do not run fix if the Rez package does not define a Python package / module."""
        root = os.path.join(tempfile.mkdtemp(), "test_folder")
        os.makedirs(root)
        self.delete_item_later(root)

        package = package_common.make_package(
            "project_a", root, package_common.make_source_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)
        package = packages[0]

        expected = (
            set(),
            [],
            [
                worker.Skip(
                    package,
                    os.path.join(repository.working_dir, "project_a"),
                    "Rez Package does not define Python packages / modules.",
                )
            ],
        )

        with rez_configuration.patch_packages_path([repository.working_dir]):
            self._test(expected)
예제 #2
0
    def test_no_change(self, _create_pull_request):
        """Successfully run a command but have that command do nothing.

        In this case, no PR should be submitted (because nothing was changed).

        """
        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)
        ]
        repository, packages, remote_root = package_common.make_fake_repository(
            packages, root)
        self.delete_item_later(repository.working_dir)
        self.delete_item_later(remote_root)

        paths = [repository.working_dir]

        with rez_configuration.patch_packages_path(paths):
            unfixed, invalids, skips = self._test_unhandled(paths=paths)
            self.assertEqual(["project_a"],
                             [package.name for package, _ in unfixed])
            self.assertEqual([], invalids)
            self.assertEqual([], skips)
예제 #3
0
    def test_no_remote(self):
        """Check that a fix will not run if the package's repository has no git remote."""
        root = os.path.join(tempfile.mkdtemp(), "test_folder")
        os.makedirs(root)
        self.delete_item_later(root)

        package = package_common.make_package("project_a", root,
                                              self._make_source_with_no_remote)

        invalids = [
            exceptions.NoRepositoryRemote(
                package,
                os.path.join(root, "project_a"),
                "No remote origin could be found for",
            )
        ]

        paths = [inspection.get_packages_path_from_package(package)]

        with rez_configuration.patch_packages_path(paths):
            unfixed, invalids, skips = self._test_unhandled()

        self.assertEqual(set(), unfixed)
        self.assertEqual([], skips)

        invalid = next(iter(invalids))

        self.assertTrue(
            str(invalid).startswith(
                "Generic error: No remote origin could be found for"))
예제 #4
0
    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)
예제 #5
0
    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)
예제 #6
0
def _test(request, directory, build_directory=""):
    """Test a CLI command for `rez_test_env` and get its resolved packages back.

    This function is a bit intense so let's break it down.

    The goal of this function is to

    - Get resolved Rez packages
    - Make a test environment that will work regardless of the user's
      actual Rez environment.
    - Be as quiet (not-spammy) as possible

    Args:
        request (str): User-provided test which would be sent directly to the CLI.
        directory (str): The folder on-disk where the fake Rez package(s) for the test live.
        build_directory (str, optional): If provided, this path is added to resolves. Default: "".

    Returns:
        set[str]: The resolved Rez packages/versions.

    """
    packages_path = [directory]

    if build_directory:
        packages_path += [build_directory]

    with _override_context_command():
        with rez_configuration.patch_packages_path(packages_path):
            try:
                with wurlitzer.pipes() as (
                    stdout,
                    stderr,
                ):  # wurlitzer will capture stdout
                    cli.main(shlex.split(request))
            except SystemExit as error:
                # Since `rez_test_env` literally runs the `rez-env` CLI
                # as part of its work, it always raises a `SystemExit`
                # exception. So we catch that and only re-raise if there
                # was actually an error.
                #
                if error.code != 0:
                    raise

    data = set(stdout.read().strip().split())

    stdout.close()
    stderr.close()

    return data
예제 #7
0
    def test_source_no_variant(self, run_command):
        """Create a source (non-built) Rez package 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.

        """
        packages = self._setup_test(run_command,
                                    package_common.make_source_python_package)
        path_root = inspection.get_packages_path_from_package(packages[0])
        paths = [path_root]

        with rez_configuration.patch_packages_path(paths):
            self._test((set(), [], []), [path_root])

        self.assertEqual(1, run_command.call_count)
예제 #8
0
    def test_no_repository(self):
        """Check that a fix will not run if the package has no destination repository."""
        def _make_package_with_no_repository(text, name, _, root):
            return package_common.make_source_python_package(
                text, name, None, root)

        root = os.path.join(tempfile.mkdtemp(), "test_folder")
        os.makedirs(root)
        self.delete_item_later(root)

        package = package_common.make_package(
            "project_a", root, _make_package_with_no_repository)

        invalids = [
            exceptions.NoGitRepository(package,
                                       os.path.join(root, "project_a"),
                                       "is not in a Git repository.")
        ]
        expected = (set(), invalids, [])

        with rez_configuration.patch_packages_path([root]):
            self._test(expected, [root])
예제 #9
0
    def test_one(self, run_command):
        """Run command on a single Rez package.

        Unlike :meth:`Fix.test_two` which has special logic for dealing
        with source vs release packages, this test will just run on a
        single source Rez package.

        In other words, this test is intentionally simpler than
        :meth:`Fix.test_two`.

        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)
        ]
        repository, packages, remote_root = package_common.make_fake_repository(
            packages, root)
        self.delete_item_later(repository.working_dir)
        self.delete_item_later(remote_root)

        paths = [repository.working_dir]

        with rez_configuration.patch_packages_path(paths):
            self._test((set(), [], []), paths)

        self.assertEqual(1, run_command.call_count)
예제 #10
0
    def test_versioned_source(self, run_command):
        """Make sure a Rez source package directory which resembles an installed Rez package works.

        Basically if the source Rez package has a parent version folder
        BUT the version folder isn't an exact match to what is written
        in the package.py file then we need to handle that scenario
        correctly.

        """
        def _make_version_package(path, text):
            directory = os.path.dirname(path)

            if not os.path.isdir(directory):
                os.makedirs(directory)

            with open(path, "w") as handler:
                handler.write(text)

            os.makedirs(os.path.join(directory, "python"))
            open(os.path.join(directory, "python", "some_module.py"),
                 "a").close()

            with open(os.path.join(directory, "rezbuild.py"), "w") as handler:
                handler.write(
                    textwrap.dedent("""\
                        import os
                        import shutil

                        def main(source, install):
                            shutil.copytree(
                                os.path.join(source, "python"),
                                os.path.join(install, "python"),
                            )

                        main(
                            os.environ["REZ_BUILD_SOURCE_PATH"],
                            os.environ["REZ_BUILD_INSTALL_PATH"],
                        )
                        """))

            return finder.get_nearest_rez_package(directory)

        run_command.return_value = ""
        root = os.path.join(tempfile.mkdtemp(), "test_versioned_source")

        packages = [
            _make_version_package(
                os.path.join(root, "rez_package_a", "1.2.0", "package.py"),
                textwrap.dedent("""\
                    name = "rez_package_a"

                    version = "1.2.0"

                    build_command = "python {root}/rezbuild.py"


                    def commands():
                        import os

                        env.PYTHONPATH.append(os.path.join("{root}", "python"))
                    """),
            ),
            _make_version_package(
                os.path.join(root, "rez_package_a", "1.3.0", "package.py"),
                textwrap.dedent("""\
                    name = "rez_package_a"

                    version = "1.3.0"

                    build_command = "python {root}/rezbuild.py"


                    def commands():
                        import os

                        env.PYTHONPATH.append(os.path.join("{root}", "python"))
                    """),
            ),
            _make_version_package(
                os.path.join(root, "rez_package_b", "2", "package.py"),
                textwrap.dedent("""\
                    name = "rez_package_b"

                    version = "2.5.0"

                    build_command = "python {root}/rezbuild.py"


                    def commands():
                        import os

                        env.PYTHONPATH.append(os.path.join("{root}", "python"))
                    """),
            ),
        ]

        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)

        paths = [release_path]

        with rez_configuration.patch_packages_path(paths):
            self._test((set(), [], []), paths)

        self.assertEqual(2, run_command.call_count)
예제 #11
0
    def _test_release(self, run_command, builder):
        """Build a Rez package, release it, and then test it.

        This is a convenience function to keep unittests a bit more concise.

        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.
            builder (callable[str, str, str, str] -> str): The function that
                is used to generate the "contents" of the Rez package.
                This function is only responsible for creating the
                package.py/rezbuild.py files, it doesn't create a Python
                package, for example. This parameter is responsible for
                creating the rest of the files of the package.

        """
        packages = self._setup_test(run_command,
                                    builder,
                                    variants=[["project_b-1"]])

        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)
        build_paths = [build_root]

        release_path = _release_packages(
            packages,
            search_paths=build_paths + config.packages_path,  # pylint: disable=no-member
        )
        self.delete_item_later(release_path)

        packages = [
            packages_.get_developer_package(
                os.path.join(release_path, package.name, str(package.version)))
            for package in packages
        ]

        paths = build_paths + [release_path]

        with rez_configuration.patch_packages_path(paths):
            self._test(
                (
                    set(),
                    [],
                    [
                        worker.Skip(
                            build_package,
                            finder.get_package_root(build_package),
                            "Python package already has documentation.",
                        )
                    ],
                ),
                paths,
            )

        self.assertEqual(1, run_command.call_count)
예제 #12
0
 def test_empty(self):
     """Check that zero packages does not error."""
     with rez_configuration.patch_packages_path([]):
         self._test((set(), [], []), [])
예제 #13
0
    def test_multiple(self, run_command):
        """Run command on Rez packages with more than one repository.

        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)

        repository_a, packages_a, remote_root = package_common.make_fake_repository(
            [
                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"},
                ),
            ],
            root,
        )
        self.delete_item_later(repository_a.working_dir)
        self.delete_item_later(remote_root)
        release_path_a = _release_packages(packages_a)
        self.delete_item_later(release_path_a)

        repository_b, packages_b, remote_root = package_common.make_fake_repository(
            [
                package_common.make_package(
                    "project_c", root,
                    package_common.make_source_python_package),
                package_common.make_package(
                    "project_d",
                    root,
                    package_common.make_source_python_package,
                    dependencies={"project_a-1+<2"},
                ),
                package_common.make_package(
                    "project_e", root,
                    package_common.make_source_python_package),
            ],
            root,
        )
        self.delete_item_later(repository_b.working_dir)
        self.delete_item_later(remote_root)
        release_path_b = _release_packages(packages_b,
                                           search_paths=[release_path_a])
        self.delete_item_later(release_path_b)

        self._test((set(), [], []), [release_path_a])

        self.assertEqual(2, run_command.call_count)

        with rez_configuration.patch_packages_path(
            [release_path_b, release_path_a]):
            self._test((set(), [], []), [release_path_b, release_path_a])

        self.assertEqual(7, run_command.call_count)