diff --git a/CHANGELOG.md b/CHANGELOG.md index 87029c9..720269a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ OR Changelog ========= + +## 2.14.0 - 4 April 2023 +- [Implemented #57](https://github.com/cruft/cruft/issues/57): Accept cookiecutter arguments on the command line for update + ## 2.13.0 - 4 April 2023 - [Implemented #172](https://github.com/cruft/cruft/issues/172): Add support for local extensions diff --git a/cruft/_cli.py b/cruft/_cli.py index 3e7cdbe..52d9872 100644 --- a/cruft/_cli.py +++ b/cruft/_cli.py @@ -240,6 +240,12 @@ def update( " repository (but no other changes)" ), ), + extra_context: str = typer.Option( + "{}", + "--extra-context", + help="A JSON string describing any extra context to pass to cookiecutter.", + show_default=False, + ), ) -> None: if not _commands.update( project_dir=project_dir, @@ -250,6 +256,7 @@ def update( checkout=checkout, strict=strict, allow_untracked_files=allow_untracked_files, + extra_context=json.loads(extra_context), ): raise typer.Exit(1) diff --git a/cruft/_commands/update.py b/cruft/_commands/update.py index 76c383c..9bc3eaa 100644 --- a/cruft/_commands/update.py +++ b/cruft/_commands/update.py @@ -1,7 +1,7 @@ import json from pathlib import Path from subprocess import DEVNULL, PIPE, CalledProcessError, run # nosec -from typing import Optional, Set +from typing import Any, Dict, Optional, Set import click import typer @@ -22,6 +22,7 @@ def update( checkout: Optional[str] = None, strict: bool = True, allow_untracked_files: bool = False, + extra_context: Optional[Dict[str, Any]] = None, ) -> bool: """Update specified project's cruft to the latest and greatest release.""" cruft_file = utils.cruft.get_cruft_file(project_dir) @@ -59,7 +60,7 @@ def update( # Bail early if the repo is already up to date and no inputs are asked if not ( - cookiecutter_input or refresh_private_variables + extra_context or cookiecutter_input or refresh_private_variables ) and utils.cruft.is_project_updated(repo, cruft_state["commit"], last_commit, strict): typer.secho( "Nothing to do, project's cruft is already up to date!", fg=typer.colors.GREEN @@ -67,7 +68,7 @@ def update( return True # Generate clean outputs via the cookiecutter - # from the current cruft state commit of the cookiectter and the updated + # from the current cruft state commit of the cookiecutter and the updated # cookiecutter. # For the current cruft state, we do not try to update the cookiecutter_input # because we want to keep the current context input intact. @@ -85,6 +86,12 @@ def update( if refresh_private_variables: _clean_cookiecutter_private_variables(cruft_state) + # Add new input data from command line to cookiecutter context + if extra_context: + extra = cruft_state["context"]["cookiecutter"] + for k, v in extra_context.items(): + extra[k] = v + new_context = utils.generate.cookiecutter_template( output_dir=new_template_dir, repo=repo, diff --git a/tests/test_cli.py b/tests/test_cli.py index 18647c3..7c39825 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -418,6 +418,34 @@ def test_update_refresh_private_variables_from_template( assert result.exit_code == 0 +@pytest.mark.parametrize( + "template_version", + [ + "input", + "input-updated", + ], +) +def test_update_extra_context( + cruft_runner, + cookiecutter_dir_input, + capfd, + template_version, +): + result = cruft_runner( + ["update", "--project-dir", cookiecutter_dir_input.as_posix()] + + ["-c", template_version, '--extra-context={"input":"extra-context"}'], + input="v\ny\n", + ) + git_diff_captured = capfd.readouterr() + if template_version == "input-updated": + assert "-Initial" in git_diff_captured.out + assert "+Updated" in git_diff_captured.out + assert "-Input from cookiecutter: some-input" in git_diff_captured.out + assert "+Input from cookiecutter: extra-context" in git_diff_captured.out + assert "cruft has been updated" in result.stdout + assert result.exit_code == 0 + + @pytest.mark.parametrize("args,expected_exit_code", [([], 0), (["--exit-code"], 1), (["-e"], 1)]) def test_diff_has_diff(args, expected_exit_code, cruft_runner, cookiecutter_dir): (cookiecutter_dir / "README.md").write_text("changed content\n")