plone / plone/cookieplone

Add cookieplone update command to refresh projects against newer template versions

Open
#176 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

04 type: enhancement
Dominant language
Python
Stars
12
Forks
4
Avg merge
4m
Merged PRs (30d)
1

Description

Summary

Add a cookieplone update command that refreshes an already-generated project against the latest version of the template it was created from, preserving the user's local changes and surfacing conflicts for manual review.

Today, once a user runs cookieplone and scaffolds a project, the generated tree is frozen in time. Any improvement that later lands in the upstream template — bugfixes, new CI steps, dependency bumps, new boilerplate files, tightened security defaults — is invisible to existing projects unless the user manually diffs upstream and copies edits over. That is both tedious and error-prone, and in practice means real projects drift further and further away from the templates that spawned them.

A first-class update command would let template authors ship improvements knowing downstream consumers can actually adopt them, and let downstream users benefit from ecosystem-wide fixes with a single command.

User experience

From within a previously generated codebase:

cookieplone update

Cookieplone should:

  1. Discover which template the project was generated from (via the __template__ key persisted in .cookieplone.json, see #168).
  2. Re-resolve the upstream repository at the current default branch or tag.
  3. Replay the original answers from the answers file against the latest template.
  4. Compute a three-way diff between:
    • the old rendered template (the snapshot the project was born from),
    • the new rendered template (what the current upstream would produce with the same answers),
    • the current project on disk (including the user's local edits).
  5. Apply the new-vs-old diff to the working tree, leaving conflict markers where a hunk overlaps user changes — the same mental model as git merge.
  6. Report a summary: files added, files removed, files updated cleanly, files with conflicts.

Additional flags to consider:

  • --answers <path> — override the answers file location (default: the .cookieplone_answers_*.json in the project root).
  • --tag <ref> — update against a specific tag/branch/commit of the template repository instead of the default.
  • --dry-run — print the diff without writing anything.
  • --skip <glob> — never touch matching paths (useful for generated lockfiles, .env, etc.).
  • --interactive — prompt per-file before applying changes.

Prior art

This is the same problem that cruft solves on top of plain Cookiecutter. The cruft model (store a reference to the template + the exact commit/version + the answers, and use a three-way merge on update) works well in practice and is worth studying as a reference implementation.

Cookieplone has two advantages over a generic cruft integration:

  • It already persists a structured answers file with __template__ (after #168), so we do not need a separate .cruft.json sidecar.
  • It already knows how to resolve Cookieplone repositories, sub-templates, and the v2 schema, so the update command can reuse the same machinery instead of shelling out to cruft.

Proposed scope

In scope (first cut)
  • A new cookieplone update subcommand.
  • Discovery of the source template from the answers file written by the original run.
  • Re-rendering with the original answers against the latest template.
  • Three-way merge of the old render, the new render, and the working tree.
  • Conflict marker output (git-style) for hunks the merge cannot apply cleanly.
  • Summary report at the end of the run.
  • Support for the --tag, --dry-run, and --skip flags described above.
Out of scope (track separately)
  • Re-prompting the user for new schema fields that did not exist in the original run. (Start by assuming every new field uses the schema's default; add an interactive prompt pass later.)
  • Automated answer migration (for example, renaming a question between template versions).
  • Updating sub-templates separately from the parent project.
  • Cross-template updates (switching from one template to another).
  • A cookieplone status command that reports how far a project has drifted from its template without applying any changes. (Nice as a follow-up.)

Open questions

  1. Answers file naming. Today the answers file lives as .cookieplone_answers_<folder_name>.json. Should cookieplone update assume exactly one such file at the project root, or should it accept a path explicitly?
  2. Template pinning. Should the answers file also record the exact template commit/tag at generation time, so update knows the "old" side of the three-way merge without having to guess? This would be a small addition to write_answers() and makes the three-way merge reliable.
  3. Binary and generated files. How should the merge handle binary files, lock files, and files flagged in _copy_without_render?
  4. Integration with extends (#175). Once the repository extension mechanism lands, update has to handle the case where a project was generated from a downstream repo that inherits from an upstream — updates should walk both layers.

Acceptance criteria

  • cookieplone update works end-to-end against a project generated with the current version of Cookieplone.
  • A three-way merge produces conflict markers for hunks that overlap user edits.
  • --dry-run shows the planned changes without writing anything.
  • --tag lets the caller update to a specific template ref.
  • --skip honours user-provided globs.
  • The command reports a structured summary (added / removed / updated / conflicted files).
  • Integration tests cover: clean update, update with user edits, update with conflicts, update after a new schema field was added upstream, and update with --tag pinning.
  • Documentation:
    • New how-to guide: "Update a project against a newer template version".
    • Reference entry for the new subcommand in docs/src/reference/cli.md.
    • Concept page explaining the three-way merge model and conflict handling.
  • News fragment under news/ (type: feature).

Notes

  • Milestone: 3.0.0 — this is a substantial feature. File it now so the design conversation can start early and #168 / #175 can inform the final shape.
  • Depends on (or interacts with) #175 once the repository extension mechanism lands.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the existing Cookieplone command entry points and write_answers(), along with the design context in #168 and #175. Use the current project-generation flow as the baseline for implementing update, then add integration coverage for clean changes, local edits, conflicts, new schema fields, and --tag pinning. Done means the acceptance criteria pass, including --dry-run, --skip, the structured summary, documentation, and the news fragment.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.