Repository: cookiecutter/cookiecutter

Issue:
Boolean parameters parsed as String
* Cookiecutter version: 2.0
* Template project url: https://github.com/cookiecutter/cookiecutter-django
* Python version: 3.8
* Operating System: Linux

### Description:

We want to be able to ask the user for true/false questions.
The example template shows the current usage of boolean parameters, in {{cookiecutter.project_slug}}/.github/dependabot.yml:
`{%- if cookiecutter.use_docker == 'y' %}` 
This usage is rather problematic, as it is requires the user to enter exactly 'y'. If the user enters "yes" or "true" it won't be valid.

We want to add the ability to specify boolean parameters as "true" JSON booleans and naturally prompt for them.
Thus the usage of booleans in the template's cookiecutter.json would look like:
`"use_docker": false`
Instead of the current usage, which is:
 `"use_docker": "n"`

Currently this example boolean which is specified in the cookiecutter.json file is parsed as a string and thus checking for it would require a string comparison, which raises and exact same problem as the user would have to explicitly enter "true" or "false" instead of a boolean.

This would also simplify the usage of the boolean parameters in files, so the above shown dependabot.yml would change to:
`{%- if cookiecutter.use_docker %}` 

Discussion:

Patch:
diff --git a/cookiecutter/prompt.py b/cookiecutter/prompt.py
index a067d09..003ace6 100644
--- a/cookiecutter/prompt.py
+++ b/cookiecutter/prompt.py
@@ -143,8 +143,8 @@ def render_variable(env, raw, cookiecutter_dict):
         being populated with variables.
     :return: The rendered value for the default variable.
     """
-    if raw is None:
-        return None
+    if raw is None or isinstance(raw, bool):
+        return raw
     elif isinstance(raw, dict):
         return {
             render_variable(env, k, cookiecutter_dict): render_variable(
@@ -201,6 +201,14 @@ def prompt_for_config(context, no_input=False):
                     cookiecutter_dict, env, key, raw, no_input
                 )
                 cookiecutter_dict[key] = val
+            elif isinstance(raw, bool):
+                # We are dealing with a boolean variable
+                if no_input:
+                    cookiecutter_dict[key] = render_variable(
+                        env, raw, cookiecutter_dict
+                    )
+                else:
+                    cookiecutter_dict[key] = read_user_yes_no(key, raw)
             elif not isinstance(raw, dict):
                 # We are dealing with a regular variable
                 val = render_variable(env, raw, cookiecutter_dict)
diff --git a/docs/advanced/boolean_variables.rst b/docs/advanced/boolean_variables.rst
new file mode 100644
index 0000000..58c5e48
--- /dev/null
+++ b/docs/advanced/boolean_variables.rst
@@ -0,0 +1,46 @@
+.. _boolean-variables:
+
+Boolean Variables (2.2+)
+------------------------
+
+Boolean variables are used for answering True/False questions.
+
+Basic Usage
+~~~~~~~~~~~
+
+Boolean variables are regular key / value pairs, but with the value being True/False.
+
+For example, if you provide the following boolean variable in your ``cookiecutter.json``::
+
+   {
+       "run_as_docker": true
+   }
+
+you'd get the following user input when running Cookiecutter::
+
+  run_as_docker [True]:
+
+Depending on the user's input, a different condition will be selected.
+
+The above ``run_as_docker`` boolean variable creates ``cookiecutter.run_as_docker``, which
+can be used like this::
+
+  {%- if cookiecutter.run_as_docker -%}
+  # In case of True add your content here
+
+  {%- else -%}
+  # In case of False add your content here
+
+  {% endif %}
+
+Cookiecutter is using `Jinja2's if conditional expression <http://jinja.pocoo.org/docs/dev/templates/#if>`_ to determine the correct ``run_as_docker``.
+
+Input Validation
+~~~~~~~~~~~~~~~~
+If a non valid value is inserted to a boolean field, the following error will be printed:
+
+.. code-block:: bash
+
+   run_as_docker [True]: docker
+   Error: docker is not a valid boolean
+
diff --git a/docs/advanced/index.rst b/docs/advanced/index.rst
index 216731d..89150af 100644
--- a/docs/advanced/index.rst
+++ b/docs/advanced/index.rst
@@ -18,6 +18,7 @@ Various advanced topics regarding cookiecutter usage.
    copy_without_render
    replay
    choice_variables
+   boolean_variables
    dict_variables
    templates
    template_extensions


Test patch:
diff --git a/tests/test_prompt.py b/tests/test_prompt.py
index 037591d..9e85bcd 100644
--- a/tests/test_prompt.py
+++ b/tests/test_prompt.py
@@ -21,7 +21,7 @@ class TestRenderVariable:
         'raw_var, rendered_var',
         [
             (1, '1'),
-            (True, 'True'),
+            (True, True),
             ('foo', 'foo'),
             ('{{cookiecutter.project}}', 'foobar'),
             (None, None),
@@ -39,7 +39,7 @@ class TestRenderVariable:
         assert result == rendered_var
 
         # Make sure that non None non str variables are converted beforehand
-        if raw_var is not None:
+        if raw_var is not None and not isinstance(raw_var, bool):
             if not isinstance(raw_var, str):
                 raw_var = str(raw_var)
             from_string.assert_called_once_with(raw_var)
@@ -49,10 +49,10 @@ class TestRenderVariable:
     @pytest.mark.parametrize(
         'raw_var, rendered_var',
         [
-            ({1: True, 'foo': False}, {'1': 'True', 'foo': 'False'}),
+            ({1: True, 'foo': False}, {'1': True, 'foo': False}),
             (
                 {'{{cookiecutter.project}}': ['foo', 1], 'bar': False},
-                {'foobar': ['foo', '1'], 'bar': 'False'},
+                {'foobar': ['foo', '1'], 'bar': False},
             ),
             (['foo', '{{cookiecutter.project}}', None], ['foo', 'foobar', None]),
         ],
@@ -380,6 +380,42 @@ class TestPromptChoiceForConfig:
         assert expected_choice == actual_choice
 
 
+class TestReadUserYesNo(object):
+    """Class to unite boolean prompt related tests."""
+
+    @pytest.mark.parametrize(
+        'run_as_docker',
+        (
+            True,
+            False,
+        ),
+    )
+    def test_should_invoke_read_user_yes_no(self, mocker, run_as_docker):
+        """Verify correct function called for boolean variables."""
+        read_user_yes_no = mocker.patch('cookiecutter.prompt.read_user_yes_no')
+        read_user_yes_no.return_value = run_as_docker
+
+        read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
+
+        context = {'cookiecutter': {'run_as_docker': run_as_docker}}
+
+        cookiecutter_dict = prompt.prompt_for_config(context)
+
+        assert not read_user_variable.called
+        read_user_yes_no.assert_called_once_with('run_as_docker', run_as_docker)
+        assert cookiecutter_dict == {'run_as_docker': run_as_docker}
+
+    def test_boolean_parameter_no_input(self):
+        """Verify boolean parameter sent to prompt for config with no input."""
+        context = {
+            'cookiecutter': {
+                'run_as_docker': True,
+            }
+        }
+        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
+        assert cookiecutter_dict == context['cookiecutter']
+
+
 @pytest.mark.parametrize(
     'context',
     (