[chores:fix] Overrided default commitizen plugin entrypoint #110#591
[chores:fix] Overrided default commitizen plugin entrypoint #110#591nemesifier merged 1 commit intomasterfrom
Conversation
Changed the commitizen entry point from 'openwisp' to 'cz_conventional_commits' to make the OpenWISP commit message standard the default across all OpenWISP repositories. Dropped toml config file as not needed anymore. Related to #110
WalkthroughThe changes modify the commitizen plugin configuration. The .cz.toml file is stripped of its commitizen configuration block, removing settings for plugin name, version provider, tag format, and changelog behavior. Simultaneously, setup.py updates the commitizen plugin entry point from the key "openwisp" to "cz_conventional_commits", while maintaining the reference to the same OpenWispCommitizen callable. Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 1 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@setup.py`:
- Around line 23-28: The entry point currently registers as
"cz_conventional_commits" which overrides Commitizen's default globally; change
the entry point key to a unique name (e.g., "openwisp" or "openwisp_commitizen")
instead of "cz_conventional_commits" so it registers as "openwisp =
openwisp_utils.releaser.commitizen:OpenWispCommitizen" (or similar) and add a
short note in the README/CONTRIBUTING explaining the global-install caveat and
how to opt-in per-repo (or set name="openwisp" in local commitizen config).
- Around line 27-29: The setup.py entry point registration for
"cz_conventional_commits"
(openwisp_utils.releaser.commitizen:OpenWispCommitizen) can be overridden
unpredictably due to unstable entry-point ordering; instead, make the override
explicit by adding a Commitizen configuration that sets name =
"cz_conventional_commits" and points to the openwisp implementation (e.g., in
pyproject.toml under [tool.commitizen] or a .commitizen.cfg) so Commitizen will
deterministically load the openwisp_utils.releaser.commitizen:OpenWispCommitizen
implementation rather than relying on entry-point order.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.cz.tomlsetup.py
💤 Files with no reviewable changes (1)
- .cz.toml
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: nemesifier
Repo: openwisp/openwisp-utils PR: 560
File: openwisp_utils/commitizen/openwisp.py:9-25
Timestamp: 2026-02-06T20:46:32.980Z
Learning: In openwisp-utils, the commit message prefix "chores" (plural) is intentionally used instead of "chore" (singular) in the Commitizen ALLOWED_PREFIXES configuration.
📚 Learning: 2026-02-06T20:46:32.980Z
Learnt from: nemesifier
Repo: openwisp/openwisp-utils PR: 560
File: openwisp_utils/commitizen/openwisp.py:9-25
Timestamp: 2026-02-06T20:46:32.980Z
Learning: In openwisp-utils, the commit message prefix "chores" (plural) is intentionally used instead of "chore" (singular) in the Commitizen ALLOWED_PREFIXES configuration.
Applied to files:
setup.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
- GitHub Check: Python==3.12 | django~=5.0.0
- GitHub Check: Python==3.12 | django~=5.2.0
- GitHub Check: Python==3.11 | django~=4.2.0
- GitHub Check: Python==3.13 | django~=5.2.0
- GitHub Check: Python==3.13 | django~=5.1.0
- GitHub Check: Python==3.12 | django~=5.1.0
- GitHub Check: Python==3.11 | django~=5.1.0
- GitHub Check: Python==3.12 | django~=4.2.0
- GitHub Check: Python==3.11 | django~=5.2.0
- GitHub Check: Python==3.11 | django~=5.0.0
- GitHub Check: Python==3.10 | django~=5.1.0
- GitHub Check: Python==3.10 | django~=5.0.0
- GitHub Check: Python==3.10 | django~=5.2.0
- GitHub Check: Python==3.10 | django~=4.2.0
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| # We override the default 'cz_conventional_commits' plugin to enforce the OpenWISP | ||
| # commit message standard across all OpenWISP repositories without requiring | ||
| # additional configuration in each repo. This ensures consistency and reduces | ||
| # maintenance overhead. | ||
| "commitizen.plugin": [ | ||
| "openwisp = openwisp_utils.releaser.commitizen:OpenWispCommitizen", | ||
| "cz_conventional_commits = openwisp_utils.releaser.commitizen:OpenWispCommitizen", |
There was a problem hiding this comment.
Global override of the default commitizen plugin has environment-wide side effects.
By registering as cz_conventional_commits, this entry point will shadow the built-in commitizen default plugin for every project in the same Python environment where openwisp-utils is installed — not just OpenWISP repos. If a developer (or CI) shares a virtualenv or has openwisp-utils installed globally, any non-OpenWISP project using commitizen's default plugin will silently get OpenWISP commit rules.
This is likely acceptable if OpenWISP repos always use dedicated virtualenvs, but it's worth documenting this caveat (e.g., in README/contributing docs) so contributors and downstream users are aware. If scoped isolation is desired later, an alternative would be to keep the custom name (openwisp) and set name = "openwisp" in each repo's config.
🤖 Prompt for AI Agents
In `@setup.py` around lines 23 - 28, The entry point currently registers as
"cz_conventional_commits" which overrides Commitizen's default globally; change
the entry point key to a unique name (e.g., "openwisp" or "openwisp_commitizen")
instead of "cz_conventional_commits" so it registers as "openwisp =
openwisp_utils.releaser.commitizen:OpenWispCommitizen" (or similar) and add a
short note in the README/CONTRIBUTING explaining the global-install caveat and
how to opt-in per-repo (or set name="openwisp" in local commitizen config).
| "commitizen.plugin": [ | ||
| "openwisp = openwisp_utils.releaser.commitizen:OpenWispCommitizen", | ||
| "cz_conventional_commits = openwisp_utils.releaser.commitizen:OpenWispCommitizen", | ||
| ], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check if commitizen is used in the codebase and how
rg -n 'commitizen' -i --type py --type toml --type txt --type cfgRepository: openwisp/openwisp-utils
Length of output: 94
🏁 Script executed:
# Look for setup.py details and entry point configuration
fd -n 'setup.py|setup.cfg|pyproject.toml' -x cat -n {}Repository: openwisp/openwisp-utils
Length of output: 297
🌐 Web query:
commitizen plugin entry point resolution order multiple packages
💡 Result:
For cz-cli (the Node “Commitizen” CLI) the “plugin/adapter entry point” is whatever you configure in config.commitizen.path (in package.json) or in a .czrc file, and it’s resolved like this:
1) Which config wins (when multiple configs exist)
Priority is project-level first, then global: a repo’s package.json (config.commitizen) or a repo .czrc is used in preference to the user’s home ~/.czrc (“If your repository is already Commitizen friendly, the local … adapter will be used, instead of globally installed one.”). [1]
(Commitizen’s config system is described as loading from multiple sources with a defined priority order; project vs global is the key practical distinction.) [2]
If you run npx cz in a repo that is not Commitizen-configured, it falls back to using the streamich/git-cz adapter. [1]
2) How the adapter “entry point” is resolved (and what happens with multiple packages)
config.commitizen.path is resolved via Node’s require.resolve and supports:
- npm module names
- directories / files relative to
process.cwd() - absolute paths
[1]
So in a monorepo / multi-package setup, the adapter you actually load is determined by Node resolution starting from the current working directory (process.cwd()):
- If multiple packages/workspaces contain different adapters (or different versions), the one that’s resolvable from the directory you run
czin (typically the closestnode_modulesup the directory tree) is the one that will be used. This is a direct consequence ofrequire.resolve+process.cwd()-relative resolution. [1]
Practical rule: run cz from (or set cwd to) the package you want to control the adapter/config for, and ensure that package has the intended config.commitizen.path. [1]
Sources:
[1] commitizen/cz-cli README (adapter config, local-vs-global behavior, and require.resolve-based resolution)
[2] DeepWiki summary of cz-cli configuration system (multiple sources + priority order)
🌐 Web query:
Python importlib.metadata entry_points duplicate names same group resolution
💡 Result:
importlib.metadata.entry_points() does not define any special “winner” when multiple entry points share the same (group, name).
- Duplicates are preserved.
EntryPoints.select(group=..., name=...)is just a filter and can return multipleEntryPointobjects with the same name/group (e.g., editable-install metadata duplication can produce literal duplicates). [1] - Indexing picks the first match.
EntryPoints.__getitem__(name)is implemented asnext(iter(self.select(name=name))), so if more than one match exists,eps['x']returns whichever matching entry point happens to come first in the underlying iteration order. [2] - Order/precedence is not a stable contract. Since
entry_points()is an environment-wide collection, the “first” one should be treated as effectively arbitrary (i.e., not a reliable conflict-resolution mechanism). The docs also note you can’t currently query byEntryPoint.distviaentry_points(..., dist=...), so you must implement your own selection if you care which distribution won. [3]
Practical resolution pattern: always use select(group=..., name=...) and handle 0/1/N results explicitly (choose by ep.dist, by ep.value, or error on ambiguity). If the duplicates are truly identical, de-duplication with set(...) works because the duplicates may compare equal in practice (as reported in the editable-install duplication case). [1]
Sources:
[1] setuptools issue showing duplicated entry points can be returned and suggesting set() to remove equal duplicates: (github.com)
[2] EntryPoints.__getitem__ implementation returning the first select(name=...) result: (sandialabs.github.io)
[3] Python docs note: entry_points(**select_params) passes params to select() and it’s not currently possible to query based on EntryPoint.dist: (docs.python.org)
Citations:
- 1: Entry points duplicated when package is installed editable pypa/setuptools#3649
- 2: https://sandialabs.github.io/WecOptTool/_modules/importlib/metadata.html?utm_source=openai
- 3: https://docs.python.org/3.15/library/importlib.metadata.html?utm_source=openai
🏁 Script executed:
# Look for setup.py and related config files
find . -maxdepth 2 -type f \( -name "setup.py" -o -name "setup.cfg" -o -name "pyproject.toml" -o -name "requirements*.txt" \)Repository: openwisp/openwisp-utils
Length of output: 113
🏁 Script executed:
# Search for commitizen mentions in the codebase
rg -n 'commitizen' --type py --type toml --type txtRepository: openwisp/openwisp-utils
Length of output: 373
🏁 Script executed:
# Check the setup.py file to see dependencies
head -50 setup.pyRepository: openwisp/openwisp-utils
Length of output: 2028
🌐 Web query:
Python commitizen library entry points plugin resolution PyPI
💡 Result:
Commitizen resolves “cz” plugins via Python package entry points, not by PyPI package name.
- Discovery mechanism: since Commitizen v3.0.0 (2023-04-23), plugins must be exposed as
commitizen.pluginentry points (loaded viaimportlib.metadata.EntryPoint). The old “discover_this” legacy mechanism is no longer used. [3], [1] - How Commitizen selects a plugin: your config
name = "..."(e.g., in[tool.commitizen]) is the plugin name Commitizen looks up; that name must match an installed entry point under thecommitizen.plugingroup. The default iscz_conventional_commits. [2] - How a plugin package registers itself (so it can be resolved):
- setuptools example:
entry_points={"commitizen.plugin": ["cz_jira = cz_jira:JiraCz"]}[1] - Poetry example:
[tool.poetry.plugins."commitizen.plugin"] cz_emoji = "cz_emoji:CzEmoji"[3]
- setuptools example:
- How to verify what’s installed in an environment:
- If a package is installed from PyPI but doesn’t declare a
commitizen.pluginentry point, Commitizen won’t find it. (PyPI hosting alone isn’t sufficient.) [1], [3] - You can inspect entry points locally:
python -c "import importlib.metadata as m; print([ (ep.group, ep.name, ep.value) for ep in m.entry_points() if ep.group=='commitizen.plugin' ])"
- If a package is installed from PyPI but doesn’t declare a
- Current context: Commitizen’s latest PyPI release is 4.13.6 (Feb 7, 2026). [4]
Sources: Customization / plugin authoring & migration notes [1], configuration name setting [2], v3.0.0 release notes describing the entry-point plugin system [3], Commitizen PyPI page (latest release date/version) [4].
Entry point override for cz_conventional_commits may not resolve reliably due to unstable entry point ordering.
When both commitizen and openwisp-utils register the same entry point name (commitizen.plugin:cz_conventional_commits), the resolver uses importlib.metadata.EntryPoint.__getitem__(), which returns the first match. However, the iteration order of duplicate entry points is not stable and depends on installation order and environment state, meaning the override may not consistently select the openwisp version. Consider making the override explicit via commitizen configuration (e.g., name = "cz_conventional_commits" in [tool.commitizen] or .commitizen.cfg with a path that explicitly references openwisp-utils) to guarantee the intended plugin is loaded.
🤖 Prompt for AI Agents
In `@setup.py` around lines 27 - 29, The setup.py entry point registration for
"cz_conventional_commits"
(openwisp_utils.releaser.commitizen:OpenWispCommitizen) can be overridden
unpredictably due to unstable entry-point ordering; instead, make the override
explicit by adding a Commitizen configuration that sets name =
"cz_conventional_commits" and points to the openwisp implementation (e.g., in
pyproject.toml under [tool.commitizen] or a .commitizen.cfg) so Commitizen will
deterministically load the openwisp_utils.releaser.commitizen:OpenWispCommitizen
implementation rather than relying on entry-point order.
Changed the commitizen entry point from 'openwisp' to 'cz_conventional_commits' to make the OpenWISP commit message standard the default across all OpenWISP repositories. Dropped toml config file as not needed anymore.
Related to #110