示例#1
0
def test_incremental_config_dialog(prepare_config_file, monkeypatch, capsys):
    config, config_text = prepare_config_file
    new_value = "new_value"
    setup_input(monkeypatch, [new_value, "Y"])
    assert config_dialog(config, attributes=["new_path"], incremental=True)
    captured = capsys.readouterr()
    assert ("Current content" not in captured.out
            ), "incremental should suppress printing file altogether"
    with pytest.raises(Exception):
        config_dialog(config, attributes=["update_node"], incremental=True)
示例#2
0
def test_single_dialog_new_config(tmp_path, monkeypatch, save_agree):
    """Tests single run of config_dialog by populating a blank file"""
    path: Path = tmp_path / "config.toml"
    # File will be created as a result of the test
    file_created = save_agree or save_agree is None

    if save_agree:
        save_agree = "Y"
    elif save_agree is None:
        save_agree = ""
    else:
        save_agree = "N"

    # The monkey patched test cli_input. Should be the same length as the list of params fed to config_dialog later
    # Note: click provides validations for confirmation prompts, no need to test for garbage cli_input
    test_input = [
        "author name", "https://confluence.local", "page title", save_agree
    ]
    setup_input(monkeypatch, test_input)

    # In this scenario file should be created when and only when the function returned true
    assert (config_dialog(
        Path(path),
        ["author", "auth.url", "pages.page1.page_title"]) == path.exists())
    if file_created:
        assert (path.read_text() == """author = "author name"

[auth]
url = "https://confluence.local"

[pages]
[pages.page1]
page_title = "page title"
""")
示例#3
0
def test_single_dialog_existing_file_one_update(user_input,
                                                prepare_config_file,
                                                monkeypatch):
    """This test checks that key update in the config works:
    * User input:
        * 'n' -> no update
        * 'y' -> update
        * '' -> update
    * If update happens - key is really updated
    """
    config, config_text = prepare_config_file
    new_value = "new_value"
    test_input = [
        "Y",  # overwrite file
        user_input,  # whether the value should be updated
        new_value,  # new value for the parameter
        "Y",  # save the file
    ]
    setup_input(monkeypatch, test_input)

    assert config_dialog(config, ["update_node"])
    if user_input in ["Y", ""]:
        assert (parse(config.read_text())["update_node"] == new_value
                ), "Existing value was not updated"
    else:
        assert config.read_text() == config_text
示例#4
0
def test_sensitive_parameter_file_mode(tmp_path, monkeypatch, capsys):
    """Checks that if there is a parameter - the wizard will create file with 600 permissions and alert the user"""
    monkeypatch.setattr("getpass.getpass", lambda x: "password")
    setup_input(monkeypatch, ("password", "Y"))
    config_path: Path = tmp_path / "config.toml"
    assert config_dialog(
        config_path,
        attributes=[DialogParameter("hidden param", hide_input=True)])
    captured = capsys.readouterr()
    assert "sensitive parameter was passed" in captured.out
    assert config_path.stat().st_mode == 33152
示例#5
0
def test_single_dialog_existing_file_base(mode, user_agrees_to_overwrite_file,
                                          prepare_config_file, monkeypatch):
    config, config_text = prepare_config_file
    new_value = "new_value"

    if user_agrees_to_overwrite_file:
        user_input = ["Y", new_value, "Y"]
    else:
        user_input = ["N"]

    setup_input(monkeypatch, user_input)

    if user_agrees_to_overwrite_file:
        node_path = "new_node"
        assert config_dialog(config, [node_path])
        assert (parse(config.read_text())[node_path] == new_value
                ), "Value was not set to the new one"
    else:
        assert config_dialog(config, ["update"]) is None
        assert config.read_text() == config_text
示例#6
0
def test_dialog_converts_filename_to_path(tmp_path, monkeypatch):
    """Makes sure the dialog accepts both Path and strings for config file"""
    path_as_path: Path = tmp_path / "config_path.toml"
    path_as_string: str = str(tmp_path / "config_string.toml")

    # In this scenario file should be created when and only when the function returned true
    for tested_type in [path_as_path, path_as_string]:
        # Taken from previous test
        test_input = [
            "author name", "https://confluence.local", "page title", "Y"
        ]
        setup_input(monkeypatch, test_input)
        assert config_dialog(tested_type,
                             ["author", "auth.url", "pages.page1.page_title"])
        assert Path(tested_type).exists()
示例#7
0
def test_single_dialog_existing_file_multiple_updates(user_updates_values,
                                                      prepare_config_file,
                                                      monkeypatch):
    """In a scenario where there are more than 1 keys to update - make sure that permutations of user input are
    handled correctly"""
    new_value = "new_value"
    update_attrs = ["update_node", "parent.parent_update_node"]
    answer_1, answer_2 = user_updates_values
    config, config_text = prepare_config_file
    test_input = ["Y"]
    for user_answer in [answer_1, answer_2]:
        if user_answer:
            test_input += ["Y", new_value]
        else:
            test_input += ["N"]
    test_input += ["Y"]
    setup_input(monkeypatch, test_input)

    assert config_dialog(config, update_attrs)
    for user_answer, attr in zip([answer_1, answer_2], update_attrs):
        # The value should be updated <=> user said yes
        assert user_answer == (get_attribute_by_path(
            attribute_path=attr,
            config=parse(config.read_text())) == new_value)
示例#8
0
def create_config(
    local_only: Optional[bool] = typer.Option(
        False,
        "--local-only",
        show_default=False,
        help="Create config only in the local folder.",
    ),
    home_only: Optional[bool] = typer.Option(
        False,
        "--home-only",
        show_default=False,
        help="Create config only in the $XDG_CONFIG_HOME.",
    ),
):
    """Runs configuration wizard. The wizard guides through setting up values for configuration file."""
    import xdg.BaseDirectory
    from confluence_poster.config_wizard import (
        config_dialog,
        get_filled_attributes_from_file,
        print_config_with_hidden_attrs,
        page_add_dialog,
    )
    from functools import partial

    echo = state.print_function
    confirm = state.confirm_function
    prompt = state.prompt_function

    home_config_location = (Path(xdg.BaseDirectory.xdg_config_home) /
                            "confluence_poster/config.toml")

    all_params = (
        DialogParameter(
            "author",
            comment=
            "If the page was not updated by the username specified here, throw an error."
            "\nIf this setting is omitted - username from auth section "
            "is used for checks",
            required=False,
        ),
        # auth:
        DialogParameter("auth.confluence_url",
                        comment="URL of confluence instance"),
        DialogParameter("auth.username",
                        comment="Username for authentication in Confluence"),
        DialogParameter(
            "auth.password",
            comment=
            "Password for authentication. May be supplied through runtime option or "
            "environment",
            required=False,
            hide_input=True,
        ),
        DialogParameter(
            "auth.is_cloud",
            comment="Whether the confluence instance is a cloud one",
            type=bool,
        ),
        # pages:
        DialogParameter(
            "pages.default.page_space",
            comment=
            "Space key (e.g. LOC for 'local-dev' space). If defined here - will be used "
            "if a page does not redefine it",
            required=False,
        ),
    ) + generate_page_dialog_params(1)
    home_only_params = (
        "author",
        "auth.confluence_url",
        "auth.username",
        "auth.password",
        "auth.is_cloud",
    )
    # To hide password in prompts
    _print_config_file = partial(print_config_with_hidden_attrs,
                                 hidden_attributes=["auth.password"])
    config_dialog = partial(config_dialog,
                            config_print_function=_print_config_file)
    page_add_dialog = partial(page_add_dialog,
                              config_print_function=_print_config_file)

    # Initial prompt
    echo("Starting config wizard.")
    echo(
        "This wizard will guide you through creating the configuration files.")
    answer = ""
    if not any([local_only, home_only]):
        echo(
            "Since neither '--local-only' nor '--home-only' were specified, wizard will guide you through creating "
            f"config files in {home_config_location.parent}(XDG_CONFIG_HOME) and {Path.cwd()}(local directory)"
        )

        answer = prompt(
            f"Create config in {home_config_location.parent}? [Y/n/q]"
            "\n* 'n' skips to config in the local directory"
            "\n* 'q' will exit the wizard\n",
            type=str,
            default="y",
        ).lower()

        if answer == "q":
            raise typer.Exit()

    if (answer == "y" and not local_only) or home_only:
        # Create config in home
        while True:
            dialog_result = config_dialog(
                filename=home_config_location,
                attributes=[_ for _ in all_params if _ in home_only_params],
            )
            if dialog_result is None or dialog_result:
                # None means the user does not want to overwrite the file
                break

    if home_only:
        # If --home-only is specified - no need to create another one in local folder
        echo(
            "--home-only specified, not attempting to create any more configs."
        )
        raise typer.Exit()

    if not local_only:
        # If local-only is passed - no need to ask for confirmation of creating a local only config
        local_answer = confirm(f"Proceed to create config in {Path.cwd()}?",
                               default=True)
        if not local_answer:
            echo("Exiting.")
            raise typer.Exit()

    # Create config in current working directory
    echo("Creating config in local directory.")
    local_config_name = prompt("Please provide the name of local config",
                               type=str,
                               default=default_config_name)

    home_parameters = get_filled_attributes_from_file(home_config_location)
    local_config_parameters = [
        _ for _ in all_params if _ not in home_parameters
    ]

    while True:
        dialog_result = config_dialog(filename=Path.cwd() / local_config_name,
                                      attributes=local_config_parameters)
        if dialog_result is None or dialog_result:
            # None means the user does not want to overwrite the file
            break

    while confirm("Add more pages?", default=False):
        page_add_dialog(Path.cwd() / local_config_name)

    echo(
        "Configuration wizard finished. Consider running the `validate` command to check the generated config"
    )