Architecture#
Overview#
plone.meta is a code generation tool.
It reads per-repository configuration from .meta.toml, renders Jinja2 templates, validates the output, and manages git operations.
Components#
Template engine#
The core of plone.meta is a set of Jinja2 templates stored in
src/plone/meta/default/.
Each template corresponds to a configuration file in the target repository.
Templates use %(variable)s style placeholders (Python string formatting syntax within the Jinja2 context) for inserting configuration values.
The template engine has trim_blocks and lstrip_blocks enabled for clean output, and keep_trailing_newline preserves proper file endings.
Modular tox templates#
The tox.ini.j2 template uses a modular architecture with Jinja2 {% include %} directives.
Rather than a single monolithic template, the tox configuration is composed from focused sub-templates:
tox-init.j2– tox initialization and configuration headertox-base.j2– base test environment definitiontox-test-runner-specifics.j2– test runner specific settingstox-test-coverage.j2– coverage environment configurationtox-qa.j2– linting and formatting environmentstox-plone-depending-qa.j2– Plone-specific QA environments
This modular structure makes the templates easier to maintain and extend.
PackageConfiguration class#
The config_package.py module contains the PackageConfiguration class, which orchestrates the entire process:
Read
.meta.tomlfrom the target repositoryDetect whether the repository is GitHub or GitLab hosted (based on the git remote URL)
Render each template with the configuration values
Validate generated files (TOML via
tomlkit, YAML viapyyaml, INI viaconfigparser, editorconfig via theeditorconfiglibrary)Write files with meta hint comments
Create a towncrier news entry
Commit and optionally push
File validation#
Every generated file is validated before being written:
TOML files are parsed with
tomlkitand additionally validated withvalidate-pyprojectforpyproject.tomlYAML files are parsed with
pyyamlINI files are parsed with
configparsereditorconfig files are parsed with the
editorconfiglibrary
If validation fails, you are prompted to proceed or abort.
Git workflow#
config-package manages git operations:
Creates a new branch (or checks out an existing one)
Commits all changes with a descriptive message
Optionally pushes to the remote
Branch names follow the pattern config-with-<type>-template-<commit-hash>, where the commit hash refers to the plone.meta repository, making it clear which version of the templates was used.
GitHub Actions workflow architecture#
Rather than generating complete CI workflows inline, plone.meta generates a thin meta.yml that uses GitHub’s workflow_call to reference reusable workflows stored in the plone/meta repository itself.
This means:
Workflow logic is maintained in one place
Repositories only need a small dispatch file
Updates to CI logic do not require re-running
config-package(as long as therefpoints to a branch like2.x)
Test matrix#
A key architectural feature of plone.meta 2.x is the test matrix. Rather than testing against a single Python version, plone.meta generates test environments for all combinations of Plone versions and Python versions. The default matrix covers Plone 6.0, 6.1, and 6.2 across Python 3.10 through 3.14.
The test matrix is reflected in multiple generated outputs:
tox.ini: Environments named
py<version>-plone<version>(e.g.,py314-plone62,py312-plone61)GitHub Actions: A dedicated
test-matrix.ymlworkflow runs the upper and lower python version for each Plone version in CIGitLab CI: Matrix jobs are generated in
.gitlab-ci.yml
Each combination uses its own constraints file, allowing different Plone versions to pin different dependency versions.
Data flow#
.meta.toml ──> PackageConfiguration ──> Jinja2 templates ──> Rendered files
│ │
│ v
└── git branch ──> commit ──> (push) Validation