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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve update command #159

Merged
merged 7 commits into from Dec 28, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions cruft/_cli.py
Expand Up @@ -193,6 +193,13 @@ def update(
help="Prompt for cookiecutter parameters for the latest template version",
show_default=False,
),
refresh_private_variables: bool = typer.Option(
False,
"--refresh-private-variables",
"-r",
help="Refresh cookiecutter private variables for the latest template version",
show_default=False,
),
skip_apply_ask: bool = typer.Option(
False,
"--skip-apply-ask",
Expand Down Expand Up @@ -237,6 +244,7 @@ def update(
if not _commands.update(
project_dir=project_dir,
cookiecutter_input=cookiecutter_input,
refresh_private_variables=refresh_private_variables,
skip_apply_ask=skip_apply_ask,
skip_update=skip_update,
checkout=checkout,
Expand Down
21 changes: 18 additions & 3 deletions cruft/_commands/update.py
Expand Up @@ -16,6 +16,7 @@
def update(
project_dir: Path = Path("."),
cookiecutter_input: bool = False,
refresh_private_variables: bool = False,
skip_apply_ask: bool = True,
skip_update: bool = False,
checkout: Optional[str] = None,
Expand Down Expand Up @@ -50,8 +51,10 @@ def update(
) as repo:
last_commit = repo.head.object.hexsha

# Bail early if the repo is already up to date.
if utils.cruft.is_project_updated(repo, cruft_state["commit"], last_commit, strict):
# Bail early if the repo is already up to date and no inputs are asked
if not (
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
)
Expand All @@ -60,16 +63,22 @@ def update(
# Generate clean outputs via the cookiecutter
# from the current cruft state commit of the cookiectter 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.
_ = utils.generate.cookiecutter_template(
output_dir=current_template_dir,
repo=repo,
cruft_state=cruft_state,
project_dir=project_dir,
cookiecutter_input=cookiecutter_input,
checkout=cruft_state["commit"],
deleted_paths=deleted_paths,
update_deleted_paths=True,
)
# Remove private variables from cruft_state to refresh their values
# from the cookiecutter template config
if refresh_private_variables:
_clean_cookiecutter_private_variables(cruft_state)

new_context = utils.generate.cookiecutter_template(
output_dir=new_template_dir,
repo=repo,
Expand Down Expand Up @@ -104,6 +113,12 @@ def update(
return True


def _clean_cookiecutter_private_variables(cruft_state: dict):
for key in list(cruft_state["context"]["cookiecutter"].keys()):
if key != "_template" and key.startswith("_"):
del cruft_state["context"]["cookiecutter"][key]


#################################################
# Calculating project diff and applying updates #
#################################################
Expand Down
60 changes: 60 additions & 0 deletions tests/test_cli.py
Expand Up @@ -50,6 +50,18 @@ def cookiecutter_dir_hooked_git(tmpdir):
)


@pytest.fixture
def cookiecutter_dir_input(tmpdir):
yield Path(
cruft.create(
"https://github.com/gmsantos/cookiecutter-test",
Path(tmpdir),
directory="dir",
checkout="input",
)
)


def test_create(cruft_runner, tmpdir):
result = cruft_runner(
[
Expand Down Expand Up @@ -358,6 +370,54 @@ def test_update_interactive_view_no_changes_when_deleted(cruft_runner, cookiecut
assert "cruft has been updated" in result.stdout


def test_update_same_commit_but_ask_for_input(cruft_runner, cookiecutter_dir_input):
result = cruft_runner(
["update", "--project-dir", cookiecutter_dir_input.as_posix(), "-c", "input", "-y", "-i"],
input="\n\n", # no input changes
)
assert "cruft has been updated" in result.stdout
assert result.exit_code == 0


def test_update_with_input_changes(cruft_runner, cookiecutter_dir_input, capfd):
result = cruft_runner(
["update", "--project-dir", cookiecutter_dir_input.as_posix(), "-c", "input", "-i"],
input="test\nnew-input\nv\ny\n",
)
git_diff_captured = capfd.readouterr()
assert "-Input from cookiecutter: some-input" in git_diff_captured.out
assert "+Input from cookiecutter: new-input" in git_diff_captured.out
assert "cruft has been updated" in result.stdout
assert result.exit_code == 0


def test_update_new_inputs_added_to_template(cruft_runner, cookiecutter_dir_input, capfd):
result = cruft_runner(
["update", "--project-dir", cookiecutter_dir_input.as_posix(), "-c", "input-updated", "-i"],
input="test\nsome-input\nnew-input-from-template\nv\ny\n",
)
git_diff_captured = capfd.readouterr()
assert "-Initial" in git_diff_captured.out
assert "+Updated" in git_diff_captured.out
assert "+New input added from template: new-input-from-template" in git_diff_captured.out
assert "cruft has been updated" in result.stdout
assert result.exit_code == 0


def test_update_refresh_private_variables_from_template(
cruft_runner, cookiecutter_dir_input, capfd
):
result = cruft_runner(
["update", "--project-dir", cookiecutter_dir_input.as_posix(), "-c", "input-updated", "-r"],
input="v\ny\n",
)
git_diff_captured = capfd.readouterr()
assert "-Private variable: 1.0" in git_diff_captured.out
assert "+Private variable: 2.0" 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")
Expand Down