Support advanced inclusion of other YAML files
Is your feature request related to a problem? Please describe.
Using too many conditionals in the copier.yml questionnaire file can make it lengthy and difficult to manage. To make the file more organized and user-friendly, we can use the include feature to split the main copier.yml file into separate ones. However, it would be even better if variables or conditionals can also be utilized when using include statements.
Describe the solution you'd like
A conditional to be used "when" a file is to be included will be nice:
!include env/dev.yml
when: "{{ env_type == 'dev' }}"
or use a variable while you use the include statement:
!include env/{{ env_type }}.yml
Describe alternatives you've considered The above doesn't seem to be supported and result in a failure.
Additional context NA
Hi, We just encountered the same issue and I would like to make it work. It's in "comunity contribution", so maybe I should only commented when a working prototype is done, but just letting you know.
I spent a little time looking to implement this features and made some discoveries:
To support conditional includes we would probably need to move away from using the YAML tag !include since the current include logic works by using a PyYAML constructor when loading the YAML content so we wouldn't have access to any of the Copier answers we would want to utilize when conditionally including a Copier configuration (since we need to load the YAML to ask those questions).
We'd probably want to load the YAML and ignore the conditional includes until after we gather answers for any questions in within this configuration but before we perform any rendering. For example this could look something like:
env_type:
type: str
choices:
"Development": dev
"Staging": staging
"Production": prod
include_extras:
type: bool
_include:
- "templates/copier.{{ env_type }}.yaml"
- file: copier.extras.yaml
when: "{{ include_extras }}"
The tricky bit ends up being combining the templates. The YAML tag !include merges a subset of the configuration YAML keys together (i.e. _exclude) and mostly overrides existing keys. Since we are deferring our includes we need to consider scenarios such as:
- What happens if there is a duplicate question key in an included configuration? Should we ask the question again or just use the first answer? If we just use the first answer should the
validatorfor the duplicate key be respected? - What question keys should be available within an included configuration? For example I would expect that
env_typeandinclude_extrasshould be available within"templates/copier.{{ env_type }}.yaml"(maybe with a prefix) but question keys created from"templates/copier.{{ env_type }}.yaml"should probably not be available incopier.extras.yaml. - If configuration files have different values for
_envops.variable_(start|end)_stringhow do these get combined? We could limit these settings to only apply within current configuration file but these also apply to the templates. Probably we should just throw an error if there are different settings for this across different configuration files.
We probably want to move away from using the name "include" for this feature since Copier uses _exclude to exclude files from rendering. As include/exclude are antonyms this could lead to confusion. Maybe using _require is a better alternative.
The Copier code base isn't currently designed for dealing with changing the template configuration at runtime. Making this change is possible it'll just take some effort to make the necessary changes and think through the corner cases with modifications to the configuration file over time.
How about an approach similar to conditionally rendered files? For example:
!include "{% if <condition> %}env/dev.yml{% endif %}"
This is a familiar technique for Copier template authors and does not require a custom extension of the reasonably known !include constructor.