Running cookieplone several times

Having had to run cookieplone several times in a row today, I remembered vaguely that there is a way to have cookiecutter replay the answers you gave previously, and it's mentioned at

which points to Replay Project Generation — cookiecutter 2.6.0 documentation but I am wondering what the correct invocation should be.

Neither

uvx cookieplone --replay-file ~/.cookiecutter_replay/project_settings.json project

nor

uvx cookieplone project --replay-file ~/.cookiecutter_replay/project_settings.json

work, giving the error:

Unable to render variable 'hostname'
        Error message: 'collections.OrderedDict object' has no attribute 'project_slug'
        Context: {
  "cookiecutter": {
    "__backend_addon_format": "1",
    "__backend_addon_git_initialize": "0",
    "__cookieplone_subtemplates": [
      [
        "add-ons/backend",
        "Setup Backend",
        "1"
      ],
      [
        "add-ons/frontend",
        "Setup Frontend",
        "1"
      ],
      [
        "docs/starter",
        "Generate documentation scaffold",
        "{{cookiecutter.initialize_documentation}}"
      ],
      [
        "sub/cache",
        "Setup Cache",
        "{{cookiecutter.devops_cache}}"
      ],
      [
        "sub/project_settings",
        "Setup Project Settings",
        "1"
      ]
    ],
    "__devops_compose_name": "{{ cookiecutter.project_slug | replace('.','-') | replace('_','-') }}",
    "__devops_db_password": "{{ random_ascii_string(12) }}",
    "__devops_db_version": "14.15",
    "__devops_host": "{{ cookiecutter.hostname | extract_host }}",
    "__devops_stack_name": "{{ cookiecutter.hostname | replace('.','-') | replace('_','-') }}",
    "__devops_swarm_public_network": "nw-public",
    "__devops_swarm_stack_network": "nw-internal",
    "__devops_traefik_docker_network": "{{ cookiecutter.__devops_stack_name }}_{{ cookiecutter.__devops_swarm_stack_network }}",
    "__devops_traefik_local_include_ui": "yes",
    "__devops_traefik_stack_include_ui": "no",
    "__devops_traefik_version": "v2.11",
    "__devops_varnish_version": "7.6",
    "__devops_zeo_version": "6.0.0",
    "__feature_headless": "1",
    "__gha_version_cache": "v4",
    "__gha_version_checkout": "v4",
    "__gha_version_docker_build_push": "v6",
    "__gha_version_docker_buildx": "v3",
    "__gha_version_docker_login": "v3",
    "__gha_version_docker_metadata": "v5",
    "__gha_version_docker_qemu": "v3",
    "__gha_version_docker_stack": "v1.2.0",
    "__gha_version_paths_filter": "v3",
    "__gha_version_setup_node": "v4",
    "__gha_version_setup_uv": "v5",
    "__profile_version": "{% now 'utc', '%Y%m%d001' %}",
    "__project_git_initialize": "1",
    "__python_package_name_upper": "{{ cookiecutter.python_package_name | pascal_case }}",
    "__version_package": "1.0.0a0",
    "devops_ansible": [
      "1",
      "0"
    ],
    "devops_cache": [
      "1",
      "0"
    ],
    "devops_gha_deploy": [
      "1",
      "0"
    ],
    "devops_storage": [
      "relstorage",
      "zeo",
      "filestorage"
    ],
    "hostname": "{{ cookiecutter.project_slug }}.example.com",
    "initialize_documentation": [
      "1",
      "0"
    ]
  }
}

Try uvx cookieplone --help

you get:

 Usage: cookieplone [OPTIONS] [TEMPLATE] [EXTRA_CONTEXT]...         
                                                                    
 Generate a new Plone codebase.                                     
                                                                    
╭─ Arguments ──────────────────────────────────────────────────────╮
│   template           [TEMPLATE]          Template to be used.    │
│   extra_context      [EXTRA_CONTEXT]...  Extra context.          │
╰──────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────╮
│ --output-dir              -o      PATH  Where to generate the    │
│                                         code.                    │
│ --tag                             TEXT  Tag. [default: main]     │
│ --info                                  Display information      │
│                                         about cookieplone        │
│                                         installation.            │
│ --version                               Display the version of   │
│                                         cookieplone.             │
│ --no-input                              Do not prompt for        │
│                                         parameters and only use  │
│                                         cookiecutter.json file   │
│                                         content. Defaults to     │
│                                         deleting any cached      │
│                                         resources and            │
│                                         redownloading them.      │
│                                         Cannot be combined with  │
│                                         the --replay flag.       │
│ --replay                  -r                                     │
│ --replay-file                     PATH                           │
│ --skip-if-file-exists     -s            Skip the files in the    │
│                                         corresponding            │
│                                         directories if they      │
│                                         already exist            │
│ --overwrite-if-exists     -f                                     │
│ --config-file                     PATH  User configuration file  │
│ --default-config                        Do not load a config     │
│                                         file. Use the defaults   │
│                                         instead                  │
│ --keep-project-on-failu…                Do not delete project    │
│                                         folder on failure        │
│ --debug-file                      PATH  File to be used as a     │
│                                         stream for DEBUG logging │
│ --all                     -a            Display all templates,   │
│                                         including hidden ones    │
│ --verbose                 -v                                     │
│ --help                                  Show this message and    │
│                                         exit.                    │
╰──────────────────────────────────────────────────────────────────╯

The --replay-file option is meant to point to another explicit replay file (e.g. when you saved one to protect the config against overwrite).

I expect you have to add --replay before to activate the replay in general.

Without explicit file it reuses the last run (that will be overwritten during every regular one).

Also you cannot interactively tweak the replay. You have to edit a copy of the replay file manually to change stuff before the replay. You can use a dummy run to figure out the format you need in that file.

Beware: do not edit the replay config in place without versioning and commit, it gets overwritten during the next interactive run. It is not inside your repo but in your user space!

Usually this works fine.

Tipp: Post Creation Hooks

You can use a post-creation-hook shell or python script to copy the replay file with a timestamp into a logs directory inside of your repo. Then you can include that into versioning or not.

If you ask for a comment, the purpose can be documented there as well, but it is hard to embed the comment in the json. better add some *.metadata_file next to the replay file, where * is the name of the replay config.

Pure cookiecutter related example hooks/post-gen-project.sh:

cp "~/.cookiecutter_replay/cookiecutter-projectname-configs.json" "replays/{{cookiecutter.job_config_name|lower}}-v{{cookiecutter.version}}-%datestamp%_%timestamp%-replay.json"

NOTE: Maybe you need to test a bit around. This was taken from a projects hooks\post-gen-project.bat file I made for a Windows Python project and tweaked a bit without testing for cookieplone, but you will get the point.

1 Like