コード例 #1
0
ファイル: test_configwizard.py プロジェクト: repobee/repobee
def test_skips_empty_values(
    empty_config_mock, defaults_options, select_repobee_section
):
    """Test that empty values are not written to the configuration file."""
    defaults_options = collections.OrderedDict(
        (option, c * 10)
        for option, c in zip(
            get_configurable_default_argnames(),
            string.ascii_lowercase,
        )
    )
    empty_option = list(defaults_options.keys())[3]
    defaults_options[empty_option] = ""

    with patch(
        "builtins.input", side_effect=list(defaults_options.values())
    ), patch("pathlib.Path.exists", autospec=True, return_value=False):
        configwizard.callback(None, plug.Config(empty_config_mock))

    del defaults_options[empty_option]
    confparser = configparser.ConfigParser()
    confparser.read(str(empty_config_mock))

    assert empty_option not in confparser[plug.Config.CORE_SECTION_NAME]
    for key, value in defaults_options.items():
        assert confparser[plug.Config.CORE_SECTION_NAME][key] == value
コード例 #2
0
ファイル: test_configwizard.py プロジェクト: repobee/repobee
def test_creates_directory(defaults_options, select_repobee_section, tmp_path):
    config_file = tmp_path / "path" / "to" / "config.ini"

    with patch("builtins.input", side_effect=list(defaults_options.values())):
        configwizard.callback(None, plug.Config(config_file))

    assert config_file.exists()
コード例 #3
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
コード例 #4
0
def create_parser_for_docs() -> argparse.ArgumentParser:
    """Create a parser showing all options for the default CLI
    documentation.

    Returns:
        The primary parser, specifically for generating documentation.
    """
    plugin.initialize_default_plugins()
    plugin.initialize_dist_plugins(force=True)
    return create_parser(
        config=plug.Config(_repobee.constants.DEFAULT_CONFIG_FILE))
コード例 #5
0
ファイル: test_configwizard.py プロジェクト: repobee/repobee
def test_retains_values_that_are_not_specified(
    config_mock, defaults_options, select_repobee_section
):
    """Test that previous default values are retained if the option is skipped,
    and that plugin sections are not touched.
    """
    # arrange
    confparser = configparser.ConfigParser()
    confparser.read(str(config_mock))

    # add plugin section
    plugin_section = "junit4"
    plugin_options = collections.OrderedDict(
        (option, c)
        for option, c in zip(
            ["hamcrest_path", "junit_path"],
            ["/path/to/hamcrest", "/path/to/junit"],
        )
    )
    confparser.add_section(plugin_section)
    for option, value in plugin_options.items():
        confparser[plugin_section][option] = value
    with open(
        str(config_mock), "w", encoding=sys.getdefaultencoding()
    ) as file:
        confparser.write(file)

    # remove an option and save expected retained value
    empty_option = list(defaults_options.keys())[3]
    defaults_options[empty_option] = ""
    expected_retained_default = confparser[plug.Config.CORE_SECTION_NAME][
        empty_option
    ]

    # act
    with patch("builtins.input", side_effect=list(defaults_options.values())):
        configwizard.callback(None, plug.Config(config_mock))

    # assert
    del defaults_options[empty_option]
    parser = configparser.ConfigParser()
    parser.read(str(config_mock))

    assert (
        parser[plug.Config.CORE_SECTION_NAME][empty_option]
        == expected_retained_default
    )
    for option, value in defaults_options.items():
        assert parser[plug.Config.CORE_SECTION_NAME][option] == value
    for option, value in plugin_options.items():
        assert parser[plugin_section][option] == value
コード例 #6
0
ファイル: test_configwizard.py プロジェクト: repobee/repobee
def test_enters_values_if_config_file_exists(
    config_mock, defaults_options, select_repobee_section
):
    """If the config file exists, a prompt should appear, and if the user
    enters yes the wizard should proceed as usuall.
    """
    with patch("builtins.input", side_effect=list(defaults_options.values())):
        configwizard.callback(None, plug.Config(config_mock))

    confparser = configparser.ConfigParser()
    confparser.read(str(config_mock))

    for key, value in defaults_options.items():
        assert confparser[plug.Config.CORE_SECTION_NAME][key] == value
コード例 #7
0
def execute_config_hooks(config_file: Union[str, pathlib.Path]) -> None:
    """Execute all config hooks.

    Args:
        config_file: path to the config file.
    """
    config_file = pathlib.Path(config_file)
    plug.manager.hook.handle_config(config=plug.Config(config_file))
    if not config_file.is_file():
        return
    config_parser = _read_config(config_file)
    plug.manager.hook.config_hook(
        config_parser=config_parser
    )  # TODO remove by 3.8.0
コード例 #8
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
コード例 #9
0
ファイル: test_configwizard.py プロジェクト: repobee/repobee
def test_enters_values_if_no_config_exists(
    config_mock, defaults_options, select_repobee_section
):
    """If no config mock can be found (ensured by the nothing_exists fixture),
    then the config wizard chould proceed without prompting for a continue.
    """
    with patch(
        "builtins.input", side_effect=list(defaults_options.values())
    ), patch("pathlib.Path.exists", autospec=True, return_value=False):
        configwizard.callback(None, plug.Config(config_mock))

    confparser = configparser.ConfigParser()
    confparser.read(str(config_mock))

    for key, value in defaults_options.items():
        assert confparser[plug.Config.CORE_SECTION_NAME][key] == value
コード例 #10
0
    def test_respects_config_file_argument(self, platform_url, tmp_path):
        # arrange
        config_file = tmp_path / "repobee.ini"
        unlikely_value = "badabimbadabum"

        # act
        with mock.patch(
                "bullet.Bullet.launch",
                autospec=True,
                return_value=_repobee.constants.CORE_SECTION_HDR,
        ), mock.patch("builtins.input", return_value=unlikely_value):
            _repobee.main.main(
                shlex.split(
                    f"repobee --config-file {config_file} config wizard"))

        # assert
        config = plug.Config(config_file)
        assert (config.get(_repobee.constants.CORE_SECTION_HDR,
                           "students_file") == unlikely_value)
コード例 #11
0
 def test_with_no_config_file(self, unused_path, plugin_manager_mock):
     config.execute_config_hooks(config=plug.Config(unused_path))
     assert not plugin_manager_mock.hook.config_hook.called
コード例 #12
0
ファイル: conftest.py プロジェクト: repobee/repobee
def full_config(config_mock):
    # TODO remove use of config_mock here
    return plug.Config(pathlib.Path(config_mock))
コード例 #13
0
ファイル: conftest.py プロジェクト: repobee/repobee
def config_for_tests(empty_config_mock):
    """Returns the Config used in the tests and by other fixtures."""
    return plug.Config(empty_config_mock)
コード例 #14
0
ファイル: test_pluginmeta.py プロジェクト: repobee/repobee
def empty_config(tmp_path_factory):
    path = tmp_path_factory.mktemp("dir") / "config.ini"
    return plug.Config(path)
コード例 #15
0
def _to_config(config_file: pathlib.Path) -> plug.Config:
    if config_file.is_file():
        _repobee.config.check_config_integrity(config_file)
    return plug.Config(config_file)
コード例 #16
0
    def command(self):
        """The RepoBee "init-course" command hook method."""
        inform("Initializing a Canvas course for use with RepoBee")

        # Step 1. Collecting information about the course on Canvas and Git.
        if _valid_git_setup(self._config):
            repobee_user = self._config[REPOBEE][REPOBEE_USER]
            repobee_base_url = self._config[REPOBEE][REPOBEE_BASE_URL]
            repobee_token = self._config[REPOBEE][REPOBEE_TOKEN]
            repobee_template_org_name = self._config[REPOBEE][
                REPOBEE_TEMPLATE_ORG_NAME]
            repobee_org_name = self._config[REPOBEE][REPOBEE_ORG_NAME]

            if ask_closed(
                    f"Use existing Git setup for user '{repobee_user}'? "):
                repobee_token = self._config[REPOBEE][REPOBEE_TOKEN]
            else:
                repobee_base_url = ask_open("Enter the Git base URL: ",
                                            repobee_base_url)
                repobee_user = ask_open("Enter your Git username: "******"Enter your Git access token: ")

        else:
            raise ValueError(
                ("Cannot find a working Git setup in your RepoBee "
                 "configuration. Please, run `repobee config wizard` to "
                 "configure git. See "
                 "https://docs.repobee.org/en/stable/getting_started.html "
                 "for more information."))

        repobee_template_org_name = ask_open(
            ("Enter the template organization containing the "
             "template repositories used in this course: "),
            default=repobee_template_org_name)
        repobee_org_name = ask_open(
            ("Enter the target organization that is to contain the "
             "student repositories used in this course's instance: "),
            default=repobee_org_name)

        course_id = _extract_course_id(self.course_url)
        canvas_api_url = _extract_api_url(self.course_url)

        if _valid_canvas_setup(self._config, canvas_api_url):
            canvas_access_token = self._config[CANVAS][CANVAS_TOKEN]
        else:
            canvas_access_token = ask_open("Enter your Canvas access token: ")

        CanvasAPI().setup(canvas_api_url, canvas_access_token)
        course = Course.load(course_id)

        course_dir = ask_dir("Enter course directory name: ",
                             str_to_path(course.name))
        mapping_table = canvas_git_map_table_wizard(course)

        if mapping_table.empty():
            warn("Canvas-Git mapping table CSV file is not created.")

        invalid_rows = [
            r for r in mapping_table.rows()
            if not r[CANVAS_ID] or not r[GIT_ID]
        ]

        if len(invalid_rows) > 0:
            warn((f"{len(invalid_rows)} students do not have a Canvas or "
                  "Git login ID. Please resolve this issue before using "
                  "RepoBee to manage assignments for this course."))

        # Step 2. Creating and filling a course directory with a Canvas-Git mapping
        # table and a RepoBee configuration file.
        inform("")
        inform(f"Created directory : {course_dir}")
        Path(course_dir).mkdir()

        if not mapping_table.empty():
            path = f"{course_dir}/{CANVAS_GIT_MAP_FILENAME}"
            inform(
                f"Created file      : {path}     ⇝  the Canvas-Git mapping table CSV file"
            )
            mapping_table.write(Path(path))

        path = f"{course_dir}/{REPOBEE_CONFIG_FILENAME}"
        inform(
            f"Created file      : {path}     ⇝  the RepoBee configuration file"
        )
        repobee_config = plug.Config(Path(path))

        try:
            repobee_config.create_section(REPOBEE)
        except Exception as err:
            print(err)

        repobee_config[REPOBEE][REPOBEE_BASE_URL] = repobee_base_url
        repobee_config[REPOBEE][REPOBEE_USER] = repobee_user
        repobee_config[REPOBEE][REPOBEE_TOKEN] = repobee_token
        repobee_config[REPOBEE][
            REPOBEE_TEMPLATE_ORG_NAME] = repobee_template_org_name
        repobee_config[REPOBEE][REPOBEE_ORG_NAME] = repobee_org_name

        try:
            repobee_config.create_section(CANVAS)
        except Exception as err:
            print(err)

        repobee_config[CANVAS][CANVAS_TOKEN] = canvas_access_token
        repobee_config[CANVAS][CANVAS_API_URL] = urlunparse(canvas_api_url)
        repobee_config[CANVAS][CANVAS_COURSE_ID] = str(course_id)
        repobee_config[CANVAS][CANVAS_GIT_MAP] = CANVAS_GIT_MAP_FILENAME

        repobee_config.store()

        inform(f"\nInitialization course '{course.name}' complete!")