feat(customize): add required field for input questions#1984
feat(customize): add required field for input questions#1984bearomorphism wants to merge 1 commit intocommitizen-tools:masterfrom
Conversation
Users can now mark a cz_customize input question as required by setting required = true in their config. The loader converts this into a questionary validate= callable that rejects empty/whitespace-only answers with the message 'This answer is required.' The required key is stripped before the question dict reaches questionary, so questionary never sees the unknown key. Closes commitizen-tools#1231 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1984 +/- ##
==========================================
- Coverage 98.23% 98.17% -0.07%
==========================================
Files 61 61
Lines 2779 2791 +12
==========================================
+ Hits 2730 2740 +10
- Misses 49 51 +2 ☔ View full report in Codecov by Sentry. |
|
closing since we're not sure about this feature... |
There was a problem hiding this comment.
Pull request overview
Adds a required flag to cz_customize input questions so config-only users can require non-empty answers, implemented by injecting a questionary validate callable while avoiding mutation of the underlying parsed config.
Changes:
- Extend
InputQuestiontyping to include optionalrequiredandvalidate. - Update
CustomizeCommitsCz.questions()to shallow-copy question dicts and inject a required-field validator fortype="input". - Document the new
requiredflag and add unit tests for the injected validator behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
commitizen/cz/customize/customize.py |
Shallow-copies question dicts and injects a non-blank validator when required=true on input questions. |
commitizen/question.py |
Updates InputQuestion TypedDict to allow required and validate. |
docs/customization/config_file.md |
Documents the new required question field and updates examples. |
tests/test_cz_customize.py |
Adds tests covering required-validator injection, behavior, and non-mutation across calls. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| result: list[CzQuestion] = [] | ||
| for raw in raw_questions: | ||
| q: dict[str, Any] = dict(raw) | ||
| if q.get("type") == "input" and q.pop("required", False): |
| q: dict[str, Any] = dict(raw) | ||
| if q.get("type") == "input" and q.pop("required", False): | ||
| q["validate"] = _required_validator |
|
|
||
| assert validate("") is not True | ||
| assert validate(" ") is not True | ||
| assert isinstance(validate(""), str) # error message |
|
Closing this PR per maintainer-triage policy: feature-request issues should sit with the maintainers for design / scope review before any implementation lands. The issue's The implementation itself is preserved on the branch ( This PR is being closed so that #1231 reverts to "awaiting maintainer triage / decision" rather than "PR pending review", which is the correct state for a feature request. Closed via the round-2 triage cleanup in #1965. |
Description
Closes #1231.
Adds a
requiredfield tocz_customizeinput questions so users can enforce non-empty answers without writing a custom Python validator.Why
Users who configure commit rules entirely through
pyproject.toml/.cz.json/.cz.yamlhave no way to mark a free-text question as mandatory. They must either accept empty answers silently or write a Python class just to add a one-line validator. This PR provides a zero-code path for the common case.What changed
commitizen/question.pyvalidateandrequiredoptional fields toInputQuestionTypedDictcommitizen/cz/customize/customize.pyquestions()now shallow-copies each question dict; iftype == "input"andrequired=True, popsrequiredand injects avalidatecallable that rejects blank inputdocs/customization/config_file.mdrequiredrow to the questions field table; addedrequired = trueto the TOML exampletests/test_cz_customize.pyHow it works
When
questions()processes each question from the config:type = "input"andrequired = true, therequiredkey is popped and replaced withvalidate = _required_validator._required_validatorreturnsTruefor non-blank strings and"This answer is required."for empty/whitespace-only input — the exact signature questionary expects.list,confirm) pass through unchanged;requiredis meaningless there since both always return a value.Backward compatibility
Fully backward-compatible. The
requiredkey defaults toFalse(absent), so existing configs are unaffected. No CLI flags, exit codes, or public APIs changed.Checklist
Was generative AI tooling used to co-author this PR?
Code Changes
uv run poe alllocally to ensure this change passes linter check and testsExpected Behavior
required = trueon an input questionKeyError/ unknown key passed to questionaryvalidatecallable injected; empty input is rejected with"This answer is required."requiredabsent /falselistorconfirmquestion with norequiredkeyquestions()twice on the same configSteps to Test This Pull Request
Additional Context
Related issue: #1231