# py-cookiecutter-templates

Project directory structure templates for the Python Cookiecutter package.

# What's Cookiecutter?

The Python package [Cookiecutter](https://github.com/cookiecutter/cookiecutter) assists in creating directory structure for whatever purpose you need such as for example a new Python project, an Ansible role or a `docker-compose` project - anything really that benefits from a unifirm reproducible directory structure. If you've ever wanted to put project structure best practices into version control then Cookiecutter's here to help.

Cookiecutter is governed by so-called Cookiecutter templates, most of its magic inside Cookiecutter templates happens via the [Jinja2 template engine](https://palletsprojects.com/p/jinja/). You'll feel right at home if you're familiar with Ansible.

# Repo layout

Each subdirectory in this repo is a Cookiecutter template, you'll recognize them from their telltale `cookiecutter.json` files. Directories usually also have a readme file explaining more about each individual template.

# Get started

Get Cookiecutter like so:
```
pip install cookiecutter
```

Unfamiliar with Python and `pip`? Check out [Developing](#developing) further down to get started with a virtual environment.

When all is set execute a template like so, `docker-compose` as an example:
```
cookiecutter https://quico.space/Quico/py-cookiecutter-templates.git --directory 'docker-compose'
```

Cookiecutter prompts you for whatever info the template needs then generates files and directories.

This is Cookiecutter prompting for info:
```
project_slug [dir-name]: grafana
service [grafana]:
component_list [grafana]: grafana,nginx
Select build:
1 - no
2 - yes
Choose from 1, 2 [1]:  
```

The end result is a directory structure that has everything you need to hit the ground running.
```
.
└── grafana
    ├── build-context
    │   ├── grafana
    │   │   ├── docker-data
    │   │   │   └── .gitkeep
    │   │   ├── Dockerfile
    │   │   └── extras
    │   │       └── .gitkeep
    │   └── nginx
    │       ├── docker-data
    │       │   └── .gitkeep
    │       ├── Dockerfile
    │       └── extras
    │           └── .gitkeep
    ├── common-settings.yml
    ├── docker-compose.override.yml
    ├── docker-compose.yml
    ├── env
    │   └── fqdn_context.env.example
    └── README.md
```

# Developing

To change Cookiecutter templates get yourself an environment then make, test and commit your changes. First things first, the environment.

## Environment

Get yourself a Python virtual environment. In this example we're assuming you're running a Linux operating system and you'll be using [pyenv](https://github.com/pyenv/pyenv) to manage virtual environments.

### pyenv

- Install pyenv with what they are calling their automatic installer. Feel free to also read up on pyenv on their [GitHub project page](https://github.com/pyenv/pyenv).
    ```
    curl https://pyenv.run | bash
    ```

- Following the installer's instruction add at least the following commands to your `~/.bashrc` file
    ```
    export PYENV_ROOT="$HOME/.pyenv"
    command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
    eval "$(pyenv init -)"
    ```

- You will also likely want to add this line which will make sure pyenv auto-activates venvs when you navigate into certain directories. More on that down at [venv](#venv).
    ```
    eval "$(pyenv virtualenv-init -)"
    ```

- Also make sure `~/.bashrc` gets loaded for example by including this in a `~/.bash_profile` file
    ```
    [[ -f ~/.bashrc ]] && . ~/.bashrc
    ```

- Reload `~/.bashrc`
    ```
    source ~/.bashrc
    ```

### Python

- Update pyenv's package list
    ```
    pyenv update
    ```
- Pick a Python version you like, for example copy-paste `3.11.4`:
    ```
    pyenv install --list | less

    ...
    3.10.12
    3.11.0
    3.11-dev
    3.11.1
    3.11.2
    3.11.3
    3.11.4
    3.12.0b2
    3.12-dev
    3.13-dev
    ...
    ```
- Install Python, wait for compilation to finish on your machine
    ```
    pyenv install 3.11.4
    ```

### Repo

- Clone this repo
    ```
    git clone https://quico.space/Quico/py-cookiecutter-templates.git ~/py-cookiecutter-templates
    ```

### venv

- Create a virtual environment where `3.11.4` is the Python version you want to use in this venv and `cookiecutter-3.11.4` is the name of your venv. Adding or dropping the Python version from your venv name comes down to personal preference.
    ```
    pyenv virtualenv 3.11.4 cookiecutter-3.11.4
    ```

- In your repo path `~/py-cookiecutter-templates` create a `.python-version` file to tell pyenv to always activate your desired venv when inside this dir.
    ```
    cd ~/py-cookiecutter-templates
    pyenv local cookiecutter-3.11.4
    ```
    pyenv will immediately prefix your shell's `${PS1}` prompt with the venv name.
    ```
    (cookiecutter-3.11.4) [✔ 23:19 user@machine py-cookiecutter-templates]$ 
    ```
    It will deactivate the venv and drop its prefix as soon as you navigate out of this dir.
    ```
    (cookiecutter-3.11.4) [✔ 23:19 user@machine py-cookiecutter-templates]$ cd
    [✔ 23:19 user@machine ~]$ 
    ```
    For now though stay in `~/py-cookiecutter-templates`, you're going to want to pip-install [cookiecutter](https://pypi.org/project/cookiecutter).

- Upgrade `pip`
    ```
    pip install --upgrade pip
    ```

- Install [cookiecutter](https://pypi.org/project/cookiecutter)
    ```
    pip install cookiecutter
    ```

All done, your environment is set up.

## Change

Make some code changes, for example to the Docker Compose Cookiecutter template. When you're happy run your local Cookiecutter template to see how your changes are rendering.

- Create `/tmp/cookiecutter-docker-compose`
    ```
    mkdir '/tmp/cookiecutter-docker-compose'
    ```

- Render a Docker Compose directory into your output directory, answer Cookiecutter's prompts:
    ```
    # cookiecutter ~/py-cookiecutter-templates \
        --directory docker-compose \
        --output-dir /tmp/cookiecutter-docker-compose

    project_slug [dir-name]: mydir
    service [mydir]: myservice
    component_list [myservice]: mycomponent_one,mycomponent_two
    Select build:
    1 - no
    2 - yes
    Choose from 1, 2 [1]: 2
    ```

- Observe that in `/tmp/cookiecutter-docker-compose` you now have your rendered Docker Compose dir:
    ```
    # tree -a .

    .
    └── mydir
        ├── build-context
        │   ├── mycomponent_one
        │   │   ├── docker-data
        │   │   │   └── .gitkeep
        │   │   ├── Dockerfile
        │   │   └── extras
        │   │       └── .gitkeep
        │   └── mycomponent_two
        │       ├── docker-data
        │       │   └── .gitkeep
        │       ├── Dockerfile
        │       └── extras
        │           └── .gitkeep
        ├── common-settings.yml
        ├── docker-compose.override.yml
        ├── docker-compose.yml
        ├── env
        │   └── fqdn_context.env.example
        └── README.md
    ```

- For rapid testing you will most likely want to not type prompt answers repeatedly. Give them as command line arguments instead, also specify `--no-input` to suppress prompts:
    ```
    cookiecutter ~/py-cookiecutter-templates \
        --no-input \
        --directory docker-compose \
        --output-dir /tmp/cookiecutter-docker-compose \
        project_slug=mydir \
        service=myservice \
        component_list=mycomponent_one,mycomponent_two \
        build=yes
    ```

## Commit prep

When you're about ready to commit changes into this repo check the following bullet points.

- Did you update the [Cookiecutter template README.md file](docker-compose/README.md), here for example for Docker Compose?
    - Change in behavior?
    - An updated example directory layout?
    - Updated example file content?
- Did you commit a new completely rendered example directory structure into [docker-compose/examples](docker-compose/examples) dir?
- Did you change something that affects existing example directories? If so rerender them.