copier-org / copier

Library and command-line utility for rendering projects templates.
https://readthedocs.org/projects/copier/
MIT License
2.02k stars 181 forks source link

Conditional argument ignored when updating #1727

Open lhupfeldt opened 2 months ago

lhupfeldt commented 2 months ago

Describe the problem

Commandline data argument is ignored when commandline value is changed during update. Argument is not remembered in answers file.

Template

copier_ignored_arg_bug.zip

To Reproduce

Create a copier.yaml with an argument which is conditional based on another argument.

_min_copier_version: 9.0.0

_subdirectory: "template"

_exclude:
  - "*~"

_message_before_copy: |
  Hi

project_name:
  type: str
  default: X

# Hidden options used for testing

show_internal_test_options:
  type: bool
  help: "Show options for internal use for testing template."
  default: false
  when: false

with_internal1:
  type: bool
  help: "Internal opt 1"
  default: false
  when: "{{ show_internal_test_options }}"

Git commit template. Expand template with "hidden" data arg specified on commandline.

 ]$ mkdir ttt && cd ttt && copier copy ../copier_ignored_arg_bug . --defaults --data with_internal1=true 

Value of with_internal1 is correctly expanded as True in template file, but is not store in answers file. Commit subproject. Make a change in template, e.g. the message. Commit. Update subproject with new value of with_internal1

 ttt]$ copier update -A --data with_internal1=false

Value of with_internal1 is unchanged and remains expanded as True in template file! The template file is unchanged, only answers file is update (with new git commit).

Logs

No response

Expected behavior

The template file should be updated with the value specified on commandline. Copier should save the value in the answers file.

Screenshots/screencasts/logs

No response

Operating system

Linux

Operating system distribution and version

Fedora

Copier version

9.3.1

Python version

3.11.8

Installation method

pip+pypi

Additional context

No response

yajo commented 2 months ago

Seems a theoretical valid case, but what's the real use case for such feature? I mean: why would you need an answer whose when evaluates to false to be actually stored? If it's changing the output, it's probably a template issue

lhupfeldt commented 2 months ago

In the simple example I could just specify the show_internal_test_options. But why should I have to? The show_internal_test_options is just for interactive UI usage to make sure the internal test options are not asked in interactive usage, the real option affecting the template expansion is with_internal1. In the actual template where I have the issue I have maybe 15 secret options affecting template expansion. If I set show_internal_test_options I will have to answer those or use --defaults, which then also affects all other options. I don't understand what you mean by "it's probably a template issue". The --data with_internal1=false is silently ignored during update, unlike other options which are changable.

pawamoy commented 2 months ago

Sounds like hacking the answer system to customize the CLI interactivity. I sometimes wonder if Copier shouldn't provide some kind of wrapper around it to build more flexible CLIs/TUIs without having to twist its internals. Some kind of Textual form, for example.

sisp commented 2 months ago

I wonder whether we should disallow overriding answers to hidden questions (when: false with both literal false and Jinja expression evaluating as false) via --data/data= for better consistency across interactive and programmatic use of Copier. :thinking: In interactive mode, a hidden question cannot be answered by a user, so the default value will always be used. This default value can be either hardcoded or a computed value. So why should it be possible to override the answer in programmatic mode?

yajo commented 1 month ago

That makes sense @sisp. However, that won't fix the fact that skipped answers (when=false) won't be stored.

@lhupfeldt have you tried hacking the .copier-answers.yml.jinja file? Something like this:

# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
{{ dict(_copier_answers, with_internal1=with_internal1) | to_nice_yaml -}}

This way you hardcode a key that's gonna be sometimes skipped in the questionary.

FWIW, keep in mind that, during updates, if you pass -A, you'll only be prompted for new questions. Old ones, already answered, won't ask you again.