From c69bdec4c9a691ee8d65d018bc21b91e0bfbce2a Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Sat, 11 Apr 2020 22:47:16 +0200 Subject: [PATCH] Git status checks and more hacking --- autonomic/command/actions.py | 14 ++++----- autonomic/command/init.py | 18 +++++------ autonomic/settings.py | 25 ++++++++++++---- autonomic/utils.py | 15 ++++++++-- setup.cfg | 2 +- test/test_settings.py | 11 +++++++ test/test_utils.py | 58 ++++++++++++++++++++++++++++++++++++ test/test_version.py | 4 +-- test/test_yaml.py | 5 ++++ 9 files changed, 123 insertions(+), 29 deletions(-) create mode 100644 test/test_settings.py create mode 100644 test/test_utils.py create mode 100644 test/test_yaml.py diff --git a/autonomic/command/actions.py b/autonomic/command/actions.py index b81ea77..93f990a 100644 --- a/autonomic/command/actions.py +++ b/autonomic/command/actions.py @@ -3,17 +3,19 @@ from os import environ import click -from PyInquirer import prompt -from autonomic.config import ACTIONS_DIR +from autonomic.config import ACTIONS_DIR, INFRA_DIR from autonomic.infra import get_passwd, run_play -from autonomic.utils import qlist +from autonomic.utils import check_git, qlist +from PyInquirer import prompt @click.command() @click.pass_context def actions(ctx): """Run an Ansible action.""" + env = environ.copy() + choices = ["addusers", "newhetzner", "rmhetzner", "newdokku"] question = qlist("action", "Which Ansible action?", choices,) action = prompt(question)["action"] @@ -25,13 +27,9 @@ def actions(ctx): path = "logins/hetzner/{}/api_key".format(key) secret = get_passwd(path) - env = environ.copy() env["HCLOUD_TOKEN"] = secret play = "{}/{}.yml".format(ACTIONS_DIR, action) run_play(play, env=env) - # TODO(decentral1se): - # git commit and push on infrastructure if we: - # 1. ran an action that adds something new to the pass store - # 2. added another machine to the inventory + check_git(INFRA_DIR) diff --git a/autonomic/command/init.py b/autonomic/command/init.py index 17017f9..73a1777 100644 --- a/autonomic/command/init.py +++ b/autonomic/command/init.py @@ -20,8 +20,7 @@ from autonomic.utils import is_proc, qlist, run @click.pass_context def init(ctx): """Initialise the toolbelt.""" - create_configuration_directory() - create_settings_file() + create_configuration() clone_infrastructure_repo() store_username() install_dependencies() @@ -31,11 +30,15 @@ def init(ctx): log.success(emojize(msg, use_aliases=True)) -def create_configuration_directory(): +def create_configuration(): """Create toolbelt config directory.""" if not exists(CONFIG_DIR): mkdir(CONFIG_DIR) + if not exists(CONFIG_YAML): + with open(CONFIG_YAML, "w") as handle: + handle.write("---") + def clone_infrastructure_repo(): """Clone or update the infrastructure repository.""" @@ -58,13 +61,6 @@ def store_username(): log.success(emojize(msg, use_aliases=True)) -def create_settings_file(): - """Create settings file.""" - if not exists(CONFIG_YAML): - with open(CONFIG_YAML, "w") as handle: - handle.write("---") - - def install_dependencies(): """Install infrastructure dependencies.""" cmd = ["/usr/bin/python3", "-m", "venv", ".venv"] @@ -86,7 +82,7 @@ def install_dependencies(): def ssh_sanity_check(): """Try to recommend some SSH tips.""" if not is_proc("ssh-agent"): - msg = "ssh-agent is not running :sob:" + msg = "warning: ssh-agent is not running :sob:" log.warning(emojize(msg, use_aliases=True)) else: msg = "ssh-agent is running :rocket:" diff --git a/autonomic/settings.py b/autonomic/settings.py index 599e44e..5ec00be 100644 --- a/autonomic/settings.py +++ b/autonomic/settings.py @@ -9,21 +9,36 @@ from autonomic.config import CONFIG_YAML from autonomic.utils import yaml_dump, yaml_load -def add(data): - """Add values to the settings file.""" +def add(yaml): + """Add YAML to the settings file.""" + from autonomic.command.init import create_configuration + + create_configuration() settings = yaml_load(CONFIG_YAML) if settings is None: settings = {} - for key in data: - settings[key] = data[key] + for key in yaml: + settings[key] = yaml[key] + + yaml_dump(CONFIG_YAML, settings) + + +def remove(key): + """Remove key from the settings file.""" + settings = yaml_load(CONFIG_YAML) + + if settings is None: + return + + settings.pop(key, None) yaml_dump(CONFIG_YAML, settings) def get(key): - """Retrieve setting values.""" + """Retrieve settings key.""" settings = yaml_load(CONFIG_YAML) try: diff --git a/autonomic/utils.py b/autonomic/utils.py index 7154919..404cfef 100644 --- a/autonomic/utils.py +++ b/autonomic/utils.py @@ -8,10 +8,11 @@ things here. """ from os import chdir -from subprocess import CalledProcessError, check_output +from subprocess import check_output from psutil import process_iter +from autonomic.config import INFRA_DIR from autonomic.logger import log from autonomic.yaml import yaml @@ -29,7 +30,7 @@ def run(cmd, cwd=None, **kwargs): log.info("Changed directory to {}".format(cwd)) log.info("Running {}".format(" ".join(cmd))) return check_output(cmd, **kwargs) - except CalledProcessError as exception: + except Exception as exception: msg = "{} failed! Saw {}".format(" ".join(cmd), str(exception)) exit(msg) @@ -84,3 +85,13 @@ def is_proc(name): except Exception: pass return False + + +def git_status(fpath): + """Check if Git reports changes to be committed.""" + cmd = ["git", "status", "--porcelain"] + output = run(cmd, cwd=fpath) + if output is not None: + msg = "warning: git reports uncommitted changes in {}".format(fpath) + log.warning(msg) + log.warning(output) diff --git a/setup.cfg b/setup.cfg index db9806a..39e41ca 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,7 +6,7 @@ max-line-length = 80 [isort] known_first_party = autonomic -known_third_party = pytest +known_third_party = pytest, psutil line_length = 80 multi_line_output = 3 skip = .venv, .tox diff --git a/test/test_settings.py b/test/test_settings.py new file mode 100644 index 0000000..4701dc6 --- /dev/null +++ b/test/test_settings.py @@ -0,0 +1,11 @@ +from autonomic.settings import add, get, remove + + +def test_add_get_remove(): + add({"foo": "bar"}) + + assert get("doesnt-exist") is None + assert get("foo") == "bar" + + remove("foo") + assert get("foo") is None diff --git a/test/test_utils.py b/test/test_utils.py new file mode 100644 index 0000000..75a28ba --- /dev/null +++ b/test/test_utils.py @@ -0,0 +1,58 @@ +from subprocess import STDOUT + +from autonomic.utils import is_proc, qlist, run, yaml_dump, yaml_load + + +def test_run_kwargs(): + assert run(["whoami"], stderr=STDOUT) is not None + + +def test_run_cwd(tmp_path): + directory = tmp_path / "test" + directory.mkdir() + + testfile = directory / "testfile.txt" + testfile.write_text("hello, world") + + output = run(["ls"], cwd=directory.absolute()) + assert "testfile.txt" in output.decode() + + +def test_make_qlist(): + output = qlist("foo", "bar", ["bang"]) + + expected = { + "type": "list", + "name": "foo", + "message": "bar", + "choices": ["bang"], + } + + for key, val in expected.items(): + assert expected[key] == output[0][key] + + +def test_yaml_load(tmp_path): + directory = tmp_path / "test" + directory.mkdir() + + testfile = directory / "testfile.yml" + testfile.write_text("---\nusername: foobar") + + loaded = yaml_load(testfile.absolute()) + assert loaded["username"] == "foobar" + + +def test_yaml_dump(tmp_path): + directory = tmp_path / "test" + directory.mkdir() + + testfile = directory / "testfile.yml" + yaml_dump(testfile.absolute(), {"username": "foobar"}) + + loaded = yaml_load(testfile.absolute()) + assert loaded["username"] == "foobar" + + +def test_is_proc(): + assert is_proc("pytest") is True diff --git a/test/test_version.py b/test/test_version.py index 8752096..71859b1 100644 --- a/test/test_version.py +++ b/test/test_version.py @@ -2,9 +2,9 @@ def test_version_fails_gracefully(mocker): - target = 'pkg_resources.get_distribution' + target = "pkg_resources.get_distribution" mocker.patch(target, side_effect=Exception()) from autonomic.__init__ import __version__ - assert __version__ == 'unknown' + assert __version__ == "unknown" diff --git a/test/test_yaml.py b/test/test_yaml.py new file mode 100644 index 0000000..7481670 --- /dev/null +++ b/test/test_yaml.py @@ -0,0 +1,5 @@ +from autonomic.yaml import yaml + + +def test_yaml_config(): + assert yaml.explicit_start is True