Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for "instance" to "ggshield config get", "unset", and "list" #678

Merged
merged 4 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
### Added

- It is now possible to define the default instance using `ggshield config set instance <THE_INSTANCE_URL>`.
- It is now possible to manipulate the default instance using `ggshield config`: `ggshield config set instance <THE_INSTANCE_URL>` defines the default instance, `ggshield config unset instance` removes the previously defined instance. The default instance can be printed with `ggshield config get instance` and `ggshield config list`.
31 changes: 19 additions & 12 deletions ggshield/cmd/config/config_get.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import click

from ggshield.cmd.common_options import add_common_options
from ggshield.cmd.config.constants import FIELD_NAMES
from ggshield.cmd.config.constants import FIELD_NAMES, FIELDS
from ggshield.core.config import Config
from ggshield.core.errors import UnknownInstanceError

Expand All @@ -28,19 +28,26 @@ def config_get_cmd(
If --instance is passed, retrieve the value for this specific instance.
"""
config: Config = ctx.obj["config"]
field = FIELDS[field_name]

if instance_url is None:
value = getattr(config.auth_config, field_name, None)
if value is None:
try:
instance_config = config.auth_config.get_instance(config.instance_name)
except UnknownInstanceError:
pass
else:
value = getattr(instance_config, field_name, None)
if field.auth_config:
if instance_url:
instance_config = config.auth_config.get_instance(instance_url)
value = getattr(instance_config, field_name, None)
else:
value = getattr(config.auth_config, field_name, None)
if value is None and field.per_instance_ok:
# No value, try to get the one from the default instance
try:
instance_config = config.auth_config.get_instance(
config.instance_name
)
except UnknownInstanceError:
pass
else:
value = getattr(instance_config, field_name, None)
else:
instance_config = config.auth_config.get_instance(instance_url)
value = getattr(instance_config, field_name, None)
value = getattr(config.user_config, field_name, None)

if value is None:
value = "not set"
Expand Down
43 changes: 28 additions & 15 deletions ggshield/cmd/config/config_list.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Any
from typing import Any, Tuple

import click

from ggshield.cmd.common_options import add_common_options
from ggshield.core.config import Config

from .constants import DATETIME_FORMAT
from .constants import DATETIME_FORMAT, FIELDS


@click.command()
Expand All @@ -18,7 +18,20 @@ def config_list_cmd(ctx: click.Context, **kwargs: Any) -> int:
config: Config = ctx.obj["config"]
default_token_lifetime = config.auth_config.default_token_lifetime

message = ""
message_lines = []

def add_entries(*entries: Tuple[str, Any]):
for key, value in entries:
message_lines.append(f"{key}: {value}")

# List global values
for field in FIELDS.values():
config_obj = config.auth_config if field.auth_config else config.user_config
value = getattr(config_obj, field.name)
add_entries((field.name, value))
message_lines.append("")

# List instance values
for instance in config.auth_config.instances:
instance_name = instance.name or instance.url

Expand All @@ -41,16 +54,16 @@ def config_list_cmd(ctx: click.Context, **kwargs: Any) -> int:
else default_token_lifetime
)

message_lines = [
f"[{instance_name}]",
f"default_token_lifetime: {_default_token_lifetime}",
f"workspace_id: {workspace_id}",
f"url: {instance.url}",
f"token: {token}",
f"token_name: {token_name}",
f"expiry: {expiry}",
]
message += ("\n".join(message_lines)) + "\n\n"

click.echo(message[:-2])
message_lines.append(f"[{instance_name}]")
add_entries(
("default_token_lifetime", _default_token_lifetime),
("workspace_id", workspace_id),
("url", instance.url),
("token", token),
("token_name", token_name),
("expiry", expiry),
)
message_lines.append("")

click.echo("\n".join(message_lines).strip())
return 0
14 changes: 9 additions & 5 deletions ggshield/cmd/config/config_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@
from ggshield.core.config.user_config import UserConfig
from ggshield.core.config.utils import find_global_config_path

from .constants import FIELD_NAMES, FIELDS
from .constants import FIELD_NAMES, FIELDS, ConfigField


def set_user_config_field(field: ConfigField, value: Any) -> None:
config_path = find_global_config_path(to_write=True)
user_config, _ = UserConfig.load(config_path)
setattr(user_config, field.name, value)
user_config.save(config_path)


@click.command()
Expand Down Expand Up @@ -55,8 +62,5 @@ def config_set_cmd(
setattr(config.auth_config, field.name, value)
config.auth_config.save()
else:
config_path = find_global_config_path(to_write=True)
user_config, _ = UserConfig.load(config_path)
setattr(user_config, field.name, value)
user_config.save(config_path)
set_user_config_field(field, value)
return 0
27 changes: 16 additions & 11 deletions ggshield/cmd/config/config_unset.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from ggshield.cmd.common_options import add_common_options
from ggshield.core.config import Config

from .constants import FIELD_NAMES
from .config_set import set_user_config_field
from .constants import FIELD_NAMES, FIELDS


@click.command()
Expand Down Expand Up @@ -33,18 +34,22 @@ def config_unset_cmd(
If --all is passed, it iterates over all instances.
"""
config: Config = ctx.obj["config"]
field = FIELDS[field_name]

if all_:
setattr(config.auth_config, field_name, None)
for instance in config.auth_config.instances:
setattr(instance, field_name, None)
if field.auth_config:
if all_:
setattr(config.auth_config, field_name, None)
for instance in config.auth_config.instances:
setattr(instance, field_name, None)

elif instance_url is None:
setattr(config.auth_config, field_name, None)
elif instance_url is None:
setattr(config.auth_config, field_name, None)

else:
instance = config.auth_config.get_instance(instance_url)
setattr(instance, field_name, None)
else:
instance = config.auth_config.get_instance(instance_url)
setattr(instance, field_name, None)

config.auth_config.save()
config.auth_config.save()
else:
set_user_config_field(field, None)
return 0
54 changes: 53 additions & 1 deletion tests/unit/cmd/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@

DEFAULT_INSTANCE_URL = "https://dashboard.gitguardian.com"

EXPECTED_OUTPUT = """[https://dashboard.gitguardian.com]
EXPECTED_OUTPUT = """instance: None
default_token_lifetime: None

[https://dashboard.gitguardian.com]
default_token_lifetime: None
workspace_id: 1
url: https://dashboard.gitguardian.com
Expand Down Expand Up @@ -342,6 +345,27 @@ def test_unset_lifetime_invalid_instance(self, cli_fs_runner):
config.auth_config.default_token_lifetime == default_value
), "The instance config should remain unchanged"

def test_unset_instance(self, cli_fs_runner):
"""
GIVEN a default instance previously set
WHEN running `ggshield config unset instance`
THEN the default instance is removed
"""
# update global user config
assert find_global_config_path() is None
config_path = find_global_config_path(to_write=True)
config = UserConfig()
config.instance = "https://example.com"
config.save(config_path)

exit_code, output = self.run_cmd(cli_fs_runner, param="instance")

assert exit_code == ExitCode.SUCCESS, output
assert output == ""

config, _ = UserConfig.load(config_path)
assert config.instance is None

@staticmethod
def run_cmd(
cli_fs_runner, param="default_token_lifetime", instance_url=None, all_=False
Expand Down Expand Up @@ -449,6 +473,34 @@ def test_get_invalid_field_name(self, cli_fs_runner):
exit_code, output = self.run_cmd(cli_fs_runner, param="invalid_field_name")
assert exit_code == ExitCode.USAGE_ERROR, output

@pytest.mark.parametrize(
["default_value", "expected_value"],
[
(None, "not set"),
("https://example.com", "https://example.com"),
],
)
def test_get_instance(self, default_value, expected_value, cli_fs_runner):
"""
GIVEN a default instance previously set
WHEN running `config get instance`
THEN it should display the value for this specific config
OR display "not set" if no value is found
"""

# update global user config
assert find_global_config_path() is None
if default_value:
config_path = find_global_config_path(to_write=True)
config = UserConfig()
config.instance = default_value
config.save(config_path)

exit_code, output = self.run_cmd(cli_fs_runner, param="instance")

assert output == f"instance: {expected_value}\n"
assert exit_code == ExitCode.SUCCESS

@staticmethod
def run_cmd(cli_fs_runner, param="default_token_lifetime", instance_url=None):
cmd = ["config", "get", param]
Expand Down
Loading