diff --git a/CHANGES.md b/CHANGES.md index 19fe3958..bb826459 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,11 @@ Revision History ================ +0.10 (2016/04/14) +----------------- + +- Added `show` command to display dependency and internal paths. + 0.9 (2016/03/31) ---------------- diff --git a/Makefile b/Makefile index a5fadade..02383623 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ endif # Test settings UNIT_TEST_COVERAGE := 73 -INTEGRATION_TEST_COVERAGE := 52 +INTEGRATION_TEST_COVERAGE := 79 COMBINED_TEST_COVERAGE := 97 # System paths @@ -119,7 +119,7 @@ depends: depends-ci depends-doc depends-dev .PHONY: depends-ci depends-ci: env Makefile $(DEPENDS_CI_FLAG) $(DEPENDS_CI_FLAG): Makefile - $(PIP) install --upgrade pep8 pep257 pylint coverage pytest pytest-describe pytest-expecter pytest-cov pytest-random + $(PIP) install --upgrade pep8 pep257 pylint coverage pytest pytest-describe pytest-expecter pytest-cov pytest-random freezegun @ touch $(DEPENDS_CI_FLAG) # flag to indicate dependencies are installed .PHONY: depends-doc diff --git a/docs/interfaces/api.md b/docs/interfaces/api.md index 6633b730..13ff949e 100644 --- a/docs/interfaces/api.md +++ b/docs/interfaces/api.md @@ -66,7 +66,7 @@ with optional arguments: ## Uninstall -To delete all source dependencies, call: +To delete all dependencies, call: ```python gitman.uninstall(root=None, force=False) diff --git a/docs/interfaces/cli.md b/docs/interfaces/cli.md index 319153d7..5470aadc 100644 --- a/docs/interfaces/cli.md +++ b/docs/interfaces/cli.md @@ -13,7 +13,7 @@ gitman install or filter the dependency list by directory name: ```sh -gitman install +gitman install ``` or limit the traversal of nested dependencies: @@ -51,7 +51,7 @@ gitman update or filter the dependency list by directory name: ```sh -gitman update +gitman update ``` or limit the traversal of nested dependencies: @@ -86,6 +86,8 @@ or exit with an error if there are any uncommitted changes: gitman list --no-dirty ``` +The `list` command will also record versions in the log file. + ## Lock To manually record the exact version of each dependency, run: @@ -97,7 +99,7 @@ gitman lock or lock down specific dependencies: ```sh -gitman lock +gitman lock ``` This can be combined with updating dependencies by running: @@ -114,7 +116,7 @@ gitman install ## Uninstall -To delete all source dependencies, run: +To delete all dependencies, run: ```sh gitman uninstall @@ -126,6 +128,32 @@ If any dependencies contain uncommitted changes, instead run: gitman uninstall --force ``` +## Show + +To display the path to the dependency storage location: + +```sh +gitman show +``` + +To display the path to a dependency: + +```sh +gitman show +``` + +To display the path to the configuration file: + +```sh +gitman show --config +``` + +To display the path to the log file: + +```sh +gitman show --log +``` + ## Edit To open the existing configuration file: diff --git a/docs/interfaces/plugin.md b/docs/interfaces/plugin.md index 93f88d8b..54652fce 100644 --- a/docs/interfaces/plugin.md +++ b/docs/interfaces/plugin.md @@ -58,7 +58,7 @@ git deps --list ## Uninstall -To delete all source dependencies, run: +To delete all dependencies, run: ```sh git deps --uninstall diff --git a/docs/use-cases/build-integration.md b/docs/use-cases/build-integration.md new file mode 100644 index 00000000..8d77603e --- /dev/null +++ b/docs/use-cases/build-integration.md @@ -0,0 +1,60 @@ +# Build System Integration + +GitMan can be invoked from your build system or continuous integration environment. It provides a convenient way to access its internal file and directory paths using the [`show`](../interfaces/cli.md#show) command. + +## Makefile + +The following example shows one way you might want to call `gitman` from within a Makefile: + +```makefile +.PHONY: all +all: depends + +.PHONY: depends +depends: $(shell gitman show --log) +$(shell gitman show --log): $(shell gitman show --config) + gitman install + make -C $(shell gitman show lib_foo) configure all install + make -C $(shell gitman show lib_bar) configure all install + gitman list + +.PHONY: clean +clean: + gitman uninstall +``` + +using a configuration file similar to: + +```yaml +location: sources +sources: +- dir: lib_foo + repo: https://github.com/example/lib_foo + rev: develop +- dir: lib_bar + repo: https://github.com/example/lib_bar + rev: master +sources_locked: +- dir: lib_foo + repo: https://github.com/example/lib_foo + rev: 73cb3668d4c9c3388fb21de16c9c3f6217cc0e1c +- dir: lib_bar + repo: https://github.com/example/lib_bar + rev: 560ea99953a4b3e393e170e07895d14904eb032c +``` + +## Workflow + +Running `make depends` performs the following actions: + +1. Check the modification times of the configuration and log files +2. If the configuration file is newer, continue +3. Install the locked dependency versions +4. Run `make` inside of each dependency's folder +5. Update the log file with the current versions of all dependencies + +To update your dependencies: + +1. Run `gitman update` +2. Run `make depends` +3. If the new build passes your tests, commit the new configuration file diff --git a/gitman/__init__.py b/gitman/__init__.py index ff453aaa..2881ddfa 100644 --- a/gitman/__init__.py +++ b/gitman/__init__.py @@ -3,7 +3,7 @@ import sys __project__ = 'GitMan' -__version__ = '0.9' +__version__ = '0.10' CLI = 'gitman' PLUGIN = 'deps' @@ -14,7 +14,7 @@ PYTHON_VERSION = 3, 4 if sys.version_info < PYTHON_VERSION: # pragma: no cover (manual test) - exit("Python {}.{}+ is required.".format(*PYTHON_VERSION)) + sys.exit("Python {}.{}+ is required.".format(*PYTHON_VERSION)) try: # pylint: disable=wrong-import-position diff --git a/gitman/cli.py b/gitman/cli.py index bc98546c..e89a3e40 100644 --- a/gitman/cli.py +++ b/gitman/cli.py @@ -40,8 +40,7 @@ def main(args=None, function=None): # Main parser parser = argparse.ArgumentParser(prog=CLI, description=DESCRIPTION, - parents=[debug, project], **shared) - + parents=[debug], **shared) subs = parser.add_subparsers(help="", dest='command', metavar="") # Install parser @@ -50,7 +49,7 @@ def main(args=None, function=None): help=info, parents=[debug, project, depth, options], **shared) sub.add_argument('name', nargs='*', - help="list of dependencies (`dir` values) to install") + help="list of dependencies names to install") sub.add_argument('-e', '--fetch', action='store_true', help="always fetch the latest branches") @@ -60,7 +59,7 @@ def main(args=None, function=None): help=info, parents=[debug, project, depth, options], **shared) sub.add_argument('name', nargs='*', - help="list of dependencies (`dir` values) to update") + help="list of dependencies names to update") sub.add_argument('-a', '--all', action='store_true', dest='recurse', help="update all nested dependencies, recursively") group = sub.add_mutually_exclusive_group() @@ -84,7 +83,7 @@ def main(args=None, function=None): sub = subs.add_parser('lock', description=info.capitalize() + '.', help=info, parents=[debug, project], **shared) sub.add_argument('name', nargs='*', - help="list of dependencies (`dir` values) to lock") + help="list of dependency names to lock") # Uninstall parser info = "delete all installed dependencies" @@ -93,6 +92,17 @@ def main(args=None, function=None): sub.add_argument('-f', '--force', action='store_true', help="delete uncommitted changes in dependencies") + # Show parser + info = "display the path of a dependency or internal file" + sub = subs.add_parser('show', description=info.capitalize() + '.', + help=info, parents=[debug, project], **shared) + sub.add_argument('name', nargs='*', + help="display the path of this dependency") + sub.add_argument('-c', '--config', action='store_true', + help="display the path of the config file") + sub.add_argument('-l', '--log', action='store_true', + help="display the path of the log file") + # Edit parser info = "open the configuration file in the default editor" sub = subs.add_parser('edit', description=info.capitalize() + '.', @@ -114,13 +124,14 @@ def main(args=None, function=None): def _get_command(function, namespace): args = [] - kwargs = dict(root=namespace.root) + kwargs = {} exit_msg = "" - if namespace.command in ('install', 'update'): + if namespace.command in ['install', 'update']: function = getattr(commands, namespace.command) args = namespace.name - kwargs.update(depth=namespace.depth, + kwargs.update(root=namespace.root, + depth=namespace.depth, force=namespace.force, clean=namespace.clean) if namespace.command == 'install': @@ -129,19 +140,36 @@ def _get_command(function, namespace): kwargs.update(recurse=namespace.recurse, lock=namespace.lock) exit_msg = "\n" + "Run again with '--force' to overwrite" + elif namespace.command == 'list': function = commands.display - kwargs.update(dict(depth=namespace.depth, - allow_dirty=namespace.allow_dirty)) + kwargs.update(root=namespace.root, + depth=namespace.depth, + allow_dirty=namespace.allow_dirty) + elif namespace.command == 'lock': function = getattr(commands, namespace.command) args = namespace.name + kwargs.update(root=namespace.root) + elif namespace.command == 'uninstall': function = commands.delete - kwargs.update(force=namespace.force) + kwargs.update(root=namespace.root, + force=namespace.force) exit_msg = "\n" + "Run again with '--force' to ignore" + + elif namespace.command == 'show': + function = commands.show + args = namespace.name + kwargs.update(root=namespace.root) + if namespace.config: + args.append('__config__') + if namespace.log: + args.append('__log__') + elif namespace.command == 'edit': function = commands.edit + kwargs.update(root=namespace.root) return function, args, kwargs, exit_msg diff --git a/gitman/commands.py b/gitman/commands.py index e8d59e5d..7dce45e0 100644 --- a/gitman/commands.py +++ b/gitman/commands.py @@ -2,6 +2,7 @@ import os import functools +import datetime import logging from . import common, system @@ -93,7 +94,7 @@ def update(*names, root=None, depth=None, @restore_cwd -def display(root=None, depth=None, allow_dirty=True): +def display(*, root=None, depth=None, allow_dirty=True): """Display installed dependencies for a project. Optional arguments: @@ -112,7 +113,12 @@ def display(root=None, depth=None, allow_dirty=True): if config: common.show("Displaying current dependency versions...", log=False) common.show() - count = len(list(config.get_deps(depth=depth, allow_dirty=allow_dirty))) + config.log(datetime.datetime.now().strftime("%F %T")) + count = 0 + for identity in config.get_deps(depth=depth, allow_dirty=allow_dirty): + count += 1 + config.log("{}: {} @ {}", *identity) + config.log() return _display_result("display", "Displayed", count) @@ -143,7 +149,7 @@ def lock(*names, root=None): @restore_cwd -def delete(root=None, force=False): +def delete(*, root=None, force=False): """Delete dependencies for a project. Optional arguments: @@ -170,8 +176,28 @@ def delete(root=None, force=False): return _display_result("delete", "Deleted", count, allow_zero=True) -@restore_cwd -def edit(root=None): +def show(*names, root=None): + """Display the path of an installed dependency or internal file. + + - `name`: dependency name or internal file keyword + - `root`: specifies the path to the root working tree + + """ + log.info("Finding paths...") + + root = _find_root(root) + config = load_config(root) + if not config: + log.error("No configuration found") + return False + + for name in names or [None]: + common.show(config.get_path(name)) + + return True + + +def edit(*, root=None): """Open the confuration file for a project. Optional arguments: @@ -183,27 +209,27 @@ def edit(root=None): root = _find_root(root) config = load_config(root) - - if config: - return system.launch(config.path) - else: + if not config: log.error("No configuration found") return False + return system.launch(config.path) -def _find_root(root, cwd=None): + +def _find_root(base, cwd=None): if cwd is None: cwd = os.getcwd() log.info("Current directory: %s", cwd) - if root: - root = os.path.abspath(root) + if base: + root = os.path.abspath(base) log.info("Specified root: %s", root) + else: + log.info("Searching for root...") path = cwd prev = None - - log.info("Searching for root...") + root = None while path != prev: log.debug("Checking path: %s", path) if '.git' in os.listdir(path): diff --git a/gitman/models/config.py b/gitman/models/config.py index d102041e..38f525f9 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -16,10 +16,12 @@ @yorm.attr(location=String) @yorm.attr(sources=SortedList.of_type(Source)) @yorm.attr(sources_locked=SortedList.of_type(Source)) -@yorm.sync("{self.root}/{self.filename}") +@yorm.sync("{self.root}/{self.filename}", auto_save=False) class Config: """A dictionary of dependency configuration options.""" + LOG = "gitman.log" + def __init__(self, root, filename="gitman.yml", location="gdm_sources"): super().__init__() self.root = root @@ -29,15 +31,33 @@ def __init__(self, root, filename="gitman.yml", location="gdm_sources"): self.sources_locked = [] @property - def path(self): + def config_path(self): """Get the full path to the configuration file.""" return os.path.join(self.root, self.filename) + path = config_path + + @property + def log_path(self): + """Get the full path to the log file.""" + return os.path.join(self.location_path, self.LOG) @property def location_path(self): """Get the full path to the sources location.""" return os.path.join(self.root, self.location) + def get_path(self, name=None): + """Get the full path to a dependency or internal file.""" + base = self.location_path + if name == '__config__': + return self.path + elif name == '__log__': + return self.log_path + elif name: + return os.path.join(base, name) + else: + return base + def install_deps(self, *names, depth=None, update=True, recurse=False, force=False, fetch=False, clean=True): @@ -119,7 +139,8 @@ def lock_deps(self, *names, obey_existing=True): shell.cd(self.location_path, _show=False) if count: - yorm.update_file(self) + yorm.save(self) + return count def uninstall_deps(self): @@ -158,6 +179,11 @@ def get_deps(self, depth=None, allow_dirty=True): common.dedent() + def log(self, message="", *args): + """Append a message to the log file.""" + with open(self.log_path, 'a') as outfile: + outfile.write(message.format(*args) + '\n') + def _get_sources(self, *, use_locked=None): """Merge source lists using requested section as the base.""" if use_locked is True: diff --git a/gitman/test/test_cli.py b/gitman/test/test_cli.py index 06031d1b..e6e05dc4 100644 --- a/gitman/test/test_cli.py +++ b/gitman/test/test_cli.py @@ -1,16 +1,16 @@ -# pylint: disable=no-self-use +# pylint: disable=no-self-use,unused-variable,expression-not-assigned from unittest.mock import Mock, patch import logging import pytest +from expecter import expect from gitman import cli from gitman.common import _Config class TestMain: - """Unit tests for the top-level arguments.""" def test_main(self): @@ -19,7 +19,7 @@ def test_main(self): cli.main([], mock_function) - mock_function.assert_called_once_with(root=None) + mock_function.assert_called_once_with() def test_main_fail(self): """Verify error in commands are detected.""" @@ -48,7 +48,6 @@ def test_main_error(self): class TestInstall: - """Unit tests for the `install` command.""" @patch('gitman.commands.install') @@ -119,7 +118,6 @@ def test_install_with_depth_invalid(self): class TestUpdate: - """Unit tests for the `update` command.""" @patch('gitman.commands.update') @@ -183,7 +181,6 @@ def test_update_with_depth(self, mock_update): class TestList: - """Unit tests for the `list` command.""" @patch('gitman.commands.display') @@ -220,7 +217,6 @@ def test_update_with_depth(self, mock_update): def describe_lock(): - # pylint: disable=unused-variable @patch('gitman.commands.lock') def with_no_arguments(lock): @@ -234,7 +230,6 @@ def with_dependencies(lock): class TestUninstall: - """Unit tests for the `uninstall` command.""" @patch('gitman.commands.delete') @@ -262,12 +257,51 @@ def test_uninstall_force(self, mock_uninstall): root=None, force=True) -class TestLogging: +def describe_show(): + + @patch('gitman.commands.show') + def with_no_arguments(show): + cli.main(['show']) + show.assert_called_once_with(root=None) + + @patch('gitman.commands.show') + def with_root(show): + cli.main(['show', '--root', "mock/root"]) + show.assert_called_once_with(root="mock/root") + + @patch('gitman.commands.show') + def with_names(show): + cli.main(['show', 'foo', 'bar']) + show.assert_called_once_with('foo', 'bar', root=None) + + @patch('gitman.commands.show') + def with_config(show): + cli.main(['show', '--config']) + show.assert_called_once_with('__config__', root=None) - """Unit tests for logging.""" + @patch('gitman.commands.show') + def with_log(show): + cli.main(['show', '--log']) + show.assert_called_once_with('__log__', root=None) - arg_verbosity = [ - ('', 0), + +def describe_edit(): + + @patch('gitman.commands.edit') + def with_no_arguments(edit): + cli.main(['edit']) + edit.assert_called_once_with(root=None) + + @patch('gitman.commands.edit') + def with_root(edit): + cli.main(['edit', '--root', "mock/root"]) + edit.assert_called_once_with(root="mock/root") + + +def describe_logging(): + + argument_verbosity = [ + (None, 0), ('-v', 1), ('-vv', 2), ('-vvv', 3), @@ -276,17 +310,15 @@ class TestLogging: ('-q', -1), ] - @staticmethod - def mock_function(*args, **kwargs): - """Placeholder logic for logging tests.""" - logging.debug(args) - logging.debug(kwargs) - logging.warning("warning") - logging.error("error") - return True - - @pytest.mark.parametrize("arg,verbosity", arg_verbosity) - def test_level(self, arg, verbosity): - """Verify verbose level can be set.""" - cli.main([arg] if arg else [], self.mock_function) - assert verbosity == _Config.verbosity + @pytest.mark.parametrize("argument,verbosity", argument_verbosity) + def at_each_level(argument, verbosity): + + def function(*args, **kwargs): + logging.debug(args) + logging.debug(kwargs) + logging.warning("warning") + logging.error("error") + return True + + cli.main([argument] if argument else [], function) + expect(_Config.verbosity) == verbosity diff --git a/gitman/test/test_models_config.py b/gitman/test/test_models_config.py index d1608317..6174ea17 100644 --- a/gitman/test/test_models_config.py +++ b/gitman/test/test_models_config.py @@ -1,6 +1,7 @@ -# pylint: disable=no-self-use,redefined-outer-name +# pylint: disable=no-self-use,redefined-outer-name,unused-variable,expression-not-assigned import pytest +from expecter import expect from gitman.models import Config, load_config @@ -101,6 +102,27 @@ def test_install_with_depth_2(self): assert 5 == count +def describe_config(): + + @pytest.fixture + def config(): + return Config('m/root', 'm.ext', 'm/location') + + def describe_get_path(): + + def it_defaults_to_sources_location(config): + expect(config.get_path()) == "m/root/m/location" + + def it_can_get_the_config_path(config): + expect(config.get_path('__config__')) == "m/root/m.ext" + + def it_can_get_log_path(config): + expect(config.get_path('__log__')) == "m/root/m/location/gitman.log" + + def it_can_get_dependency_path(config): + expect(config.get_path('foobar')) == "m/root/m/location/foobar" + + class TestLoad: def test_load_from_directory_with_config_file(self): diff --git a/mkdocs.yml b/mkdocs.yml index c251e067..c8043d64 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -18,6 +18,7 @@ pages: - 'Replacing Submodules': 'use-cases/submodules.md' - 'Tracking Branches': 'use-cases/branch-tracking.md' - 'Linking Feature Branches': 'use-cases/linked-features.md' + - 'Build System Integration': 'use-cases/build-integration.md' - About: - 'Release Notes': 'about/changes.md' - Contributing: 'about/contributing.md' diff --git a/requirements.txt b/requirements.txt index 2c849ef1..9faa8628 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -YORM ~= 0.7.2 +YORM ~= 0.8 sh ~= 1.11 diff --git a/tests/test_api.py b/tests/test_api.py index 801efaf0..41bab24c 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -7,6 +7,7 @@ import pytest from expecter import expect +from freezegun import freeze_time import gitman from gitman.models import Config @@ -55,7 +56,7 @@ def config(root="/tmp/gitman-shared"): def describe_install(): - def it_should_create_missing_directories(config): + def it_creates_missing_directories(config): expect(os.path.isdir(config.location)) == False expect(gitman.install('gitman_1', depth=1)) == True @@ -67,7 +68,7 @@ def it_should_not_modify_config(config): expect(config.__mapper__.text) == CONFIG - def it_should_merge_sources(config): + def it_merges_sources(config): config.__mapper__.text = strip(""" location: deps sources: @@ -124,18 +125,18 @@ def config_with_link(config): return config - def it_should_create(config_with_link): + def it_should_create_links(config_with_link): expect(gitman.install(depth=1)) == True expect(os.listdir()).contains('my_link') - def it_should_not_overwrite(config_with_link): + def it_should_not_overwrite_files(config_with_link): os.system("touch my_link") with pytest.raises(RuntimeError): gitman.install(depth=1) - def it_should_overwrite_with_force(config_with_link): + def it_overwrites_files_with_force(config_with_link): os.system("touch my_link") expect(gitman.install(depth=1, force=True)) == True @@ -143,7 +144,7 @@ def it_should_overwrite_with_force(config_with_link): def describe_uninstall(): - def it_should_delete_dependencies_when_they_exist(config): + def it_deletes_dependencies_when_they_exist(config): gitman.install('gitman_1', depth=1) expect(os.path.isdir(config.location)) == True @@ -156,6 +157,14 @@ def it_should_not_fail_when_no_dependnecies_exist(config): expect(gitman.uninstall()) == True + def it_deletes_the_log_file(config): + gitman.install('gitman_1', depth=1) + gitman.list() + expect(os.path.exists(config.log_path)) == True + + gitman.uninstall() + expect(os.path.exists(config.log_path)) == False + def describe_update(): @@ -164,7 +173,7 @@ def it_should_not_modify_config(config): expect(config.__mapper__.text) == CONFIG - def it_should_lock_previously_locked_dependnecies(config): + def it_locks_previously_locked_dependnecies(config): config.__mapper__.text = strip(""" location: deps sources: @@ -242,7 +251,7 @@ def it_should_not_lock_dependnecies_when_disabled(config): rev: (old revision) """) - def it_should_lock_all_when_enabled(config): + def it_should_lock_all_dependencies_when_enabled(config): gitman.update(depth=1, lock=True) expect(config.__mapper__.text) == CONFIG + strip(""" @@ -262,9 +271,29 @@ def it_should_lock_all_when_enabled(config): """) +def describe_list(): + + @freeze_time("2012-01-14 12:00:01") + def it_updates_the_log(config): + gitman.install() + gitman.list() + with open(config.log_path) as fin: + contents = fin.read().replace("/private", "") + expect(contents) == strip(""" + 2012-01-14 12:00:01 + /tmp/gitman-shared/deps/gitman_1: https://github.com/jacebrowning/gitman-demo @ eb37743011a398b208dd9f9ef79a408c0fc10d48 + /tmp/gitman-shared/deps/gitman_1/gdm_sources/gdm_3: https://github.com/jacebrowning/gdm-demo @ ddbe17ef173538d1fda29bd99a14bab3c5d86e78 + /tmp/gitman-shared/deps/gitman_1/gdm_sources/gdm_3/gdm_sources/gdm_3: https://github.com/jacebrowning/gdm-demo @ fb693447579235391a45ca170959b5583c5042d8 + /tmp/gitman-shared/deps/gitman_1/gdm_sources/gdm_3/gdm_sources/gdm_4: https://github.com/jacebrowning/gdm-demo @ 63ddfd82d308ddae72d31b61cb8942c898fa05b5 + /tmp/gitman-shared/deps/gitman_1/gdm_sources/gdm_4: https://github.com/jacebrowning/gdm-demo @ 63ddfd82d308ddae72d31b61cb8942c898fa05b5 + /tmp/gitman-shared/deps/gitman_2: https://github.com/jacebrowning/gitman-demo @ 7bd138fe7359561a8c2ff9d195dff238794ccc04 + /tmp/gitman-shared/deps/gitman_3: https://github.com/jacebrowning/gitman-demo @ 9bf18e16b956041f0267c21baad555a23237b52e + """, end='\n\n') + + def describe_lock(): - def it_should_record_all_versions_when_no_arguments(config): + def it_records_all_versions_when_no_arguments(config): expect(gitman.update(depth=1, lock=False)) == True expect(gitman.lock()) == True @@ -284,7 +313,7 @@ def it_should_record_all_versions_when_no_arguments(config): rev: 9bf18e16b956041f0267c21baad555a23237b52e """) == config.__mapper__.text - def it_should_record_specified_dependencies(config): + def it_records_specified_dependencies(config): expect(gitman.update(depth=1, lock=False)) == True expect(gitman.lock('gitman_1', 'gitman_3')) == True diff --git a/tests/test_cli.py b/tests/test_cli.py index a3cd167c..4900d01a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,5 +1,6 @@ # pylint: disable=unused-variable,redefined-outer-name,expression-not-assigned +import os from unittest.mock import patch, call import pytest @@ -16,6 +17,36 @@ def config(tmpdir): return path +@pytest.fixture +def location(tmpdir): + tmpdir.chdir() + path = str(tmpdir.join("gdm.yml")) + with open(path, 'w') as outfile: + outfile.write("location: foo") + return str(tmpdir.join("foo")) + + +def describe_show(): + + @patch('gitman.common.show') + def it_prints_location_by_default(show, location): + cli.main(['show']) + + expect(show.mock_calls) == [call(location)] + + @patch('gitman.common.show') + def it_can_print_a_depenendcy_path(show, location): + cli.main(['show', 'bar']) + + expect(show.mock_calls) == [call(os.path.join(location, "bar"))] + + def it_exits_when_no_config_found(tmpdir): + tmpdir.chdir() + + with expect.raises(SystemExit): + cli.main(['show']) + + def describe_edit(): @patch('gitman.system.launch')