Skip to content

Commit

Permalink
Add CLI option to keep project files on failure.
Browse files Browse the repository at this point in the history
  • Loading branch information
MaciejPatro committed Jun 1, 2022
1 parent fdffddb commit 23182a5
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 1 deletion.
7 changes: 7 additions & 0 deletions cookiecutter/cli.py
Expand Up @@ -144,6 +144,11 @@ def list_installed_templates(default_config, passed_config_file):
@click.option(
'-l', '--list-installed', is_flag=True, help='List currently installed templates.'
)
@click.option(
'--keep-project-on-failure',
is_flag=True,
help='Do not delete project folder on failure',
)
def main(
template,
extra_context,
Expand All @@ -161,6 +166,7 @@ def main(
accept_hooks,
replay_file,
list_installed,
keep_project_on_failure,
):
"""Create a project from a Cookiecutter project template (TEMPLATE).
Expand Down Expand Up @@ -205,6 +211,7 @@ def main(
directory=directory,
skip_if_file_exists=skip_if_file_exists,
accept_hooks=_accept_hooks,
keep_project_on_failure=keep_project_on_failure,
)
except (
ContextDecodingException,
Expand Down
5 changes: 4 additions & 1 deletion cookiecutter/generate.py
Expand Up @@ -268,6 +268,7 @@ def generate_files(
overwrite_if_exists=False,
skip_if_file_exists=False,
accept_hooks=True,
keep_project_on_failure=False,
):
"""Render the templates and saves them to files.
Expand All @@ -277,6 +278,8 @@ def generate_files(
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
template_dir = find_template(repo_dir)
logger.debug('Generating project from %s...', template_dir)
Expand Down Expand Up @@ -307,7 +310,7 @@ def generate_files(

# if we created the output directory, then it's ok to remove it
# if rendering fails
delete_project_on_failure = output_directory_created
delete_project_on_failure = output_directory_created and not keep_project_on_failure

if accept_hooks:
_run_hook_from_repo_dir(
Expand Down
4 changes: 4 additions & 0 deletions cookiecutter/main.py
Expand Up @@ -34,6 +34,7 @@ def cookiecutter(
directory=None,
skip_if_file_exists=False,
accept_hooks=True,
keep_project_on_failure=False,
):
"""
Run Cookiecutter just as if using it from the command line.
Expand All @@ -53,6 +54,8 @@ def cookiecutter(
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
if replay and ((no_input is not False) or (extra_context is not None)):
err_msg = (
Expand Down Expand Up @@ -118,6 +121,7 @@ def cookiecutter(
skip_if_file_exists=skip_if_file_exists,
output_dir=output_dir,
accept_hooks=accept_hooks,
keep_project_on_failure=keep_project_on_failure,
)

# Cleanup (if required)
Expand Down
9 changes: 9 additions & 0 deletions tests/test_cli.py
Expand Up @@ -109,6 +109,7 @@ def test_cli_replay(mocker, cli_runner):
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)


Expand All @@ -135,6 +136,7 @@ def test_cli_replay_file(mocker, cli_runner):
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)


Expand Down Expand Up @@ -170,6 +172,7 @@ def test_cli_exit_on_noinput_and_replay(mocker, cli_runner):
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)


Expand Down Expand Up @@ -205,6 +208,7 @@ def test_run_cookiecutter_on_overwrite_if_exists_and_replay(
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)


Expand Down Expand Up @@ -261,6 +265,7 @@ def test_cli_output_dir(mocker, cli_runner, output_dir_flag, output_dir):
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)


Expand Down Expand Up @@ -305,6 +310,7 @@ def test_user_config(mocker, cli_runner, user_config_path):
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)


Expand Down Expand Up @@ -335,6 +341,7 @@ def test_default_user_config_overwrite(mocker, cli_runner, user_config_path):
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)


Expand All @@ -360,6 +367,7 @@ def test_default_user_config(mocker, cli_runner):
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)


Expand Down Expand Up @@ -629,6 +637,7 @@ def test_cli_accept_hooks(
directory=None,
skip_if_file_exists=False,
accept_hooks=expected,
keep_project_on_failure=False,
)


Expand Down
12 changes: 12 additions & 0 deletions tests/test_generate_files.py
Expand Up @@ -390,6 +390,18 @@ def test_raise_undefined_variable_dir_name(output_dir, undefined_context):
assert not Path(output_dir).joinpath('testproject').exists()


def test_keep_project_dir_on_failure(output_dir, undefined_context):
"""Verify correct error raised when directory name cannot be rendered."""
with pytest.raises(exceptions.UndefinedVariableInTemplate):
generate.generate_files(
repo_dir='tests/undefined-variable/dir-name/',
output_dir=output_dir,
context=undefined_context,
keep_project_on_failure=True,
)
assert Path(output_dir).joinpath('testproject').exists()


def test_raise_undefined_variable_dir_name_existing_project(
output_dir, undefined_context
):
Expand Down
2 changes: 2 additions & 0 deletions tests/test_specify_output_dir.py
Expand Up @@ -57,6 +57,7 @@ def test_api_invocation(mocker, template, output_dir, context):
skip_if_file_exists=False,
output_dir=output_dir,
accept_hooks=True,
keep_project_on_failure=False,
)


Expand All @@ -73,4 +74,5 @@ def test_default_output_dir(mocker, template, context):
skip_if_file_exists=False,
output_dir='.',
accept_hooks=True,
keep_project_on_failure=False,
)

0 comments on commit 23182a5

Please sign in to comment.