示例#1
0
    def test_create_new_category(self):
        """Test that command can be added to a new category."""

        category = plug.cli.category("greetings", action_names=["hello"])

        class Hello(plug.Plugin, plug.cli.Command):
            __settings__ = plug.cli.command_settings(action=category.hello)
            name = plug.cli.positional()
            age = plug.cli.positional(converter=int)

            def command(self):
                return plug.Result(
                    name=self.__plugin_name__,
                    msg="Nice!",
                    status=plug.Status.SUCCESS,
                    data={
                        "name": self.name,
                        "age": self.age
                    },
                )

        name = "Bob"
        age = 24
        results_mapping = repobee.run(f"greetings hello {name} {age}".split(),
                                      plugins=[Hello])
        print(results_mapping)
        _, results = list(results_mapping.items())[0]
        result, *_ = results

        assert result.data["name"] == name
        assert result.data["age"] == age
示例#2
0
def run_repobee(cmd, workdir=pathlib.Path(".")):
    result = repobee.run(
        cmd,
        plugins=[sanitizer.SanitizeFile, sanitizer.SanitizeRepo],
        workdir=workdir,
    )
    return list(result.values())[0][0]
示例#3
0
    def test_raises_on_non_interactive_install_of_non_existing_version(self):
        """An error should be raised if one tries to install a version that
        does not exist, but the plugin does.
        """
        plugin_name = "junit4"
        plugin_version = "v0.32.0"
        cmd = [
            *pluginmanager.plugin_category.install.as_name_tuple(),
            "--plugin-spec",
            f"{plugin_name}{pluginmanager.PLUGIN_SPEC_SEP}{plugin_version}",
        ]

        with pytest.raises(plug.PlugError) as exc_info:
            repobee.run(cmd)

        assert (f"plugin '{plugin_name}' has no version '{plugin_version}'"
                in str(exc_info.value))
示例#4
0
    def test_raises_on_malformed_plugin_spec(self):
        """An error should be raised if a plugin spec is malformed."""
        malformed_spec = pluginmanager.PLUGIN_SPEC_SEP.join(
            ["too", "many", "parts"]
        )
        cmd = [
            *pluginmanager.plugin_category.install.as_name_tuple(),
            "--plugin-spec",
            malformed_spec,
        ]

        with pytest.raises(plug.PlugError) as exc_info:
            repobee.run(cmd)

        assert f"malformed plugin spec '{malformed_spec}'" in str(
            exc_info.value
        )
示例#5
0
def with_student_repos():
    command = re.sub(
        r"\s+",
        " ",
        f"""
repos setup --bu https://localhost:3000/api/v1
    --token {giteamanager.TEACHER_TOKEN}
    --user {giteamanager.TEACHER_USER}
    --org-name {giteamanager.TARGET_ORG_NAME}
    --template-org-name {giteamanager.TEMPLATE_ORG_NAME}
    --students {' '.join([t.members[0] for t in giteamanager.STUDENT_TEAMS])}
    --assignments {' '.join(template_helpers.TEMPLATE_REPO_NAMES)}
    --tb
""",
    )

    repobee.run(shlex.split(command), plugins=[gitea])
示例#6
0
    def test_non_interactive_deactivate_of_builtin_plugin(self, install_dir):
        # arrange
        plugin_name = "ghclassroom"
        cmd = [
            *pluginmanager.plugin_category.activate.as_name_tuple(),
            "--plugin-name",
            plugin_name,
        ]
        repobee.run(cmd)

        # act
        repobee.run(cmd)

        # assert
        assert plugin_name not in disthelpers.get_active_plugins(
            install_dir / "installed_plugins.json"
        )
示例#7
0
    def test_add_required_option_to_config_show(self, capsys, tmpdir,
                                                config_file):
        """Tests adding a required option to ``config show``."""
        class ConfigShowExt(plug.Plugin, plug.cli.CommandExtension):
            __settings__ = plug.cli.command_extension_settings(
                actions=[plug.cli.CoreCommand.config.show])

            silly_new_option = plug.cli.option(help="your name", required=True)

        with pytest.raises(SystemExit):
            repobee.run(
                "config show".split(),
                config_file=config_file,
                plugins=[ConfigShowExt],
            )

        assert ("the following arguments are required: --silly-new-option"
                in capsys.readouterr().err)
示例#8
0
    def test_install_local_plugin_package(self):
        plugin_version = "1.0.0"

        with tempfile.TemporaryDirectory() as tmpdir:
            workdir = pathlib.Path(tmpdir)
            junit4_local = workdir / "repobee-junit4"
            repo = git.Repo.clone_from(
                "https://github.com/repobee/repobee-junit4",
                to_path=junit4_local,
            )
            repo.git.checkout(f"v{plugin_version}")

            repobee.run(shlex.split(f"plugin install --local {junit4_local}"))

            install_info = disthelpers.get_installed_plugins()["junit4"]
            assert install_info["version"] == "local"
            assert install_info["path"] == str(junit4_local)
            assert get_pkg_version("repobee-junit4") == plugin_version
示例#9
0
    def test_truncates_urls_to_fit_terminal_width(self, capsys, mocker):
        """When the terminal is too narrow, the URLs in the plugins table are
        the first to be truncated.
        """
        cols = 120  # URLs need ~140 cols to fit
        mocker.patch(
            "os.get_terminal_size",
            autospec=True,
            return_value=collections.namedtuple("TermSize",
                                                "columns lines")(columns=cols,
                                                                 lines=100),
        )

        repobee.run("plugin list".split())

        out_err = capsys.readouterr()
        assert "truncating: 'URL'" in out_err.err
        assert "https://github.com" not in out_err.out
示例#10
0
    def test_install_local_plugin_file(self, capsys, tmp_path):
        plugin_content = """
import repobee_plug as plug
class Hello(plug.Plugin, plug.cli.Command):
    def command(self):
        return plug.Result(
            name='hello',
            status=plug.Status.SUCCESS,
            msg='Best message'
        )
"""
        hello_py = tmp_path / "hello.py"
        hello_py.write_text(plugin_content, encoding="utf8")

        repobee.run(shlex.split(f"plugin install --local {hello_py}"))

        install_info = disthelpers.get_installed_plugins()[str(hello_py)]
        assert install_info["version"] == "local"
        assert install_info["path"] == str(hello_py)
示例#11
0
    def test_config_parent_path_is_relative_to_config_path(
            self, tmp_path_factory):
        """Tests that the parent path in a config file is relative to that
        that configs own path (as opposed to the current working directory).
        """
        # arrange
        root_dir = tmp_path_factory.mktemp("configs")
        parent_config_dir = root_dir / "parent_config_dir"
        child_config_dir = root_dir / "child_config_dir"

        parent_config_dir.mkdir()
        child_config_dir.mkdir()

        key = "darth"
        value = "vader"

        parent_config = plug.Config(parent_config_dir / "base-config.ini")
        parent_config[plug.Config.CORE_SECTION_NAME][key] = value
        parent_config.store()

        child_config = plug.Config(child_config_dir / "config.ini")
        child_config[plug.Config.CORE_SECTION_NAME][
            plug.Config.PARENT_CONFIG_KEY] = str(
                pathlib.Path("..") / parent_config.path.relative_to(root_dir))
        child_config.store()

        fetched_value = None

        class HandleConfig(plug.Plugin):
            def handle_config(self, config: plug.Config) -> None:
                nonlocal fetched_value
                fetched_value = config.get(plug.Config.CORE_SECTION_NAME, key)

        # act
        repobee.run(
            list(plug.cli.CoreCommand.config.show.as_name_tuple()),
            config_file=child_config.path,
            plugins=[HandleConfig],
        )

        # assert
        assert fetched_value == value
示例#12
0
    def test_cannot_downgrade_repobee_version(self, mocker):
        """Test that installing a version of a plugin that requires an older
        version of RepoBee does fails. In other words, the plugin should not be
        installed and RepoBee should not be downgraded.
        """
        current_version = str(version.Version(_repobee.__version__))
        if get_pkg_version("repobee") != current_version:
            pytest.skip("unreleased version, can't run downgrade test")

        # this version of sanitizer requires repobee==3.0.0-alpha.5
        sanitizer_version = "2110de7952a75c03f4d33e8f2ada78e8aca29c57"
        mocker.patch(
            "bullet.Bullet.launch",
            side_effect=["sanitizer", sanitizer_version],
        )
        repobee_initial_version = get_pkg_version("repobee")

        with pytest.raises(disthelpers.DependencyResolutionError):
            repobee.run("plugin install".split())

        assert get_pkg_version("repobee") == repobee_initial_version
示例#13
0
    def test_handle_config_hook_recieves_config_with_inherited_properties(
            self, tmp_path_factory):
        first_tmpdir = tmp_path_factory.mktemp("configs")
        second_tmpdir = tmp_path_factory.mktemp("other-configs")

        section_name = "repobee"
        parent_key = "template_org_name"
        parent_value = "some-value"
        child_key = "org_name"
        child_value = "something"

        parent_config = plug.Config(second_tmpdir / "base-config.ini")
        parent_config[section_name][parent_key] = parent_value
        parent_config.store()

        child_config = plug.Config(first_tmpdir / "config.ini")
        child_config[section_name][child_key] = child_value
        child_config.parent = parent_config
        child_config.store()

        fetched_child_value = None
        fetched_parent_value = None

        class HandleConfig(plug.Plugin):
            def handle_config(self, config: plug.Config) -> None:
                nonlocal fetched_child_value, fetched_parent_value
                fetched_child_value = config.get(section_name, child_key)
                fetched_parent_value = config.get(section_name, parent_key)

        repobee.run(
            list(plug.cli.CoreCommand.config.show.as_name_tuple()),
            config_file=child_config.path,
            plugins=[HandleConfig],
        )

        assert fetched_child_value == child_value
        assert fetched_parent_value == parent_value
示例#14
0
    def test_auto_updates_pip(self):
        """Installing a plugin should automatically update pip if it's
        out-of-date.
        """
        # arrange
        old_pip_version = "20.0.1"
        assert (
            subprocess.run(
                [
                    disthelpers.get_pip_path(),
                    "install",
                    "-U",
                    f"pip=={old_pip_version}",
                ]
            ).returncode
            == 0
        )
        assert version.Version(get_pkg_version("pip")) == version.Version(
            old_pip_version
        )

        plugin_name = "junit4"
        plugin_version = "v1.0.0"
        cmd = [
            *pluginmanager.plugin_category.install.as_name_tuple(),
            "--plugin-spec",
            f"{plugin_name}{pluginmanager.PLUGIN_SPEC_SEP}{plugin_version}",
        ]

        # act
        repobee.run(cmd)

        # assert
        assert version.Version(get_pkg_version("pip")) > version.Version(
            old_pip_version
        )
示例#15
0
    def test_install_plugin_version_incompatible_with_repobee_version_error_message(
        self, tmp_path
    ):
        old_repobee_version = "3.4.0"
        current_repobee_version = get_pkg_version("repobee")
        plugin_version = "1.0.0"
        plugin_dir = tmp_path / "repobee-bogus"
        plugin_dir.mkdir()

        self._setup_bogus_plugin(
            old_repobee_version, plugin_version, plugin_dir
        )

        with pytest.raises(plug.PlugError) as exc_info:
            repobee.run(shlex.split(f"plugin install --local {plugin_dir}"))

        assert (
            f"Selected plugin is incompatible with "
            f"RepoBee v{current_repobee_version}" in str(exc_info.value)
        )
        assert (
            "Try upgrading RepoBee and then install the plugin again"
            in str(exc_info.value)
        )
示例#16
0
def run_repobee(cmd: Union[str, List[str]],
                **kwargs) -> Mapping[str, List[plug.Result]]:
    """Helper function to call :py:class:`repobee.run` when using the
    :py:class:`fakeapi.FakeAPI` platform API.

    This function will by default use a config file that sets appropriate
    values for ``students_file``, ``user``, ``org_name`` and
    ``template_org_name`` for use with the :py:class:`~fakeapi.FakeAPI`
    platform API. If you wish to use a different config, simply pass
    ``config_file="/path/to/your/config"`` to the function, or
    ``config_file=""`` to not use a config file at all.

    The :py:class:`~fakeapi.FakeAPI` plugin is always loaded last, so it is the
    not possible to use another platform API with this function. If you wish
    to do so, you should use :py:class`repobee.run` directly instead.

    Args:
        cmd: A string or list of strings with a RepoBee command.
        kwargs: Keyword arguments for :py:func:`repobee.run`.
    Returns:
        The results mapping returned by :py:func:`repobee.run`
    """
    cmd = shlex.split(cmd) if isinstance(cmd, str) else cmd
    kwargs = dict(kwargs)  # copy to not mutate input
    plugins = (kwargs.get("plugins") or []) + [localapi]
    kwargs["plugins"] = plugins

    students_file = (pathlib.Path(__file__).parent / "resources" /
                     "students.txt")

    with tempfile.NamedTemporaryFile() as tmp:
        config_file = pathlib.Path(tmp.name)
        config_file.write_text(f"""[repobee]
students_file = {students_file}
org_name = {const.TARGET_ORG_NAME}
user = {const.TEACHER}
template_org_name = {const.TEMPLATE_ORG_NAME}
token = {const.TOKEN}
""")
        kwargs.setdefault("config_file", config_file)

        return repobee.run(cmd, **kwargs)
示例#17
0
def install_plugin(name: str, version: str) -> None:
    # arrange
    with mock.patch("bullet.Bullet.launch", side_effect=[name, version]):
        repobee.run("plugin install".split())
    assert get_pkg_version(f"repobee-{name}")