refactor(cli): Framework-agnostic CLI options with enhanced UX and comprehensive audit#4480
Merged
cidrblock merged 5 commits intoansible:mainfrom Jul 24, 2025
Merged
Conversation
…mprehensive audit This comprehensive refactoring introduces a framework-agnostic CLI option management system that improves maintainability, user experience, and prepares for potential future migrations while ensuring 100% backward compatibility. ## Key Changes ### Framework-Agnostic Architecture - Introduced CliOption dataclass for framework-independent option definitions - Created CliOptions registry as single source of truth for all CLI options - Implemented options() and common_options() decorators for modular option application - Designed system to support future migration to argparse or other CLI frameworks ### Enhanced User Experience - Custom CLI option sorting: scenario_name, exclude, all, then alphabetical (short, long, experimental) - Implemented FirstLineHelp system to automatically extract short help from docstrings - Removed \f characters from all docstrings, improving readability - Cleaned up function signatures to single-line format ### Code Quality & Architecture - Moved all Click-related utilities from base.py to dedicated click_cfg.py module - Improved separation of concerns between command logic and CLI framework code - Added comprehensive type annotations and documentation - Fixed all linting errors (ruff, mypy, pydoclint) ### Comprehensive CLI Compatibility Audit Performed exhaustive audit of all 17 commands comparing main vs feature branch: - check: 6 options (scenario_name, exclude, all, parallel, report, shared_inventory) - cleanup: 6 options (scenario_name, exclude, all, report, shared_inventory, shared_state) - converge: 7 options (scenario_name, exclude, all, ansible_args, report, shared_inventory, shared_state) - create: 7 options (scenario_name, exclude, all, ansible_args, report, shared_inventory, shared_state) - dependency: 6 options (scenario_name, exclude, all, report, shared_inventory, shared_state) - destroy: 7 options (scenario_name, exclude, all, ansible_args, report, shared_inventory, shared_state) - drivers: 1 option (format_simple) - idempotence: 7 options (scenario_name, exclude, all, ansible_args, report, shared_inventory, shared_state) - list: 2 options (scenario_name, format_simple) - login: 2 options (scenario_name, host) - matrix: 1 option (scenario_name) - prepare: 8 options (scenario_name, exclude, all, ansible_args, force, report, shared_inventory, shared_state) - reset: 6 options (scenario_name, exclude, all, report, shared_inventory, shared_state) - side_effect: 7 options (scenario_name, exclude, all, ansible_args, report, shared_inventory, shared_state) - syntax: 6 options (scenario_name, exclude, all, report, shared_inventory, shared_state) - test: 8 options (scenario_name, exclude, all, ansible_args, destroy, parallel, report, shared_inventory) - verify: 7 options (scenario_name, exclude, all, ansible_args, report, shared_inventory, shared_state) ### Future-Proofing - Preserved existing CLI option variations for backward compatibility - Documented similar options requiring future research before consolidation - Included argparse migration example in PR documentation ## Files Changed - Created: src/molecule/click_cfg.py (framework-agnostic CLI system) - Created: tests/unit/test_click_cfg.py (comprehensive test coverage) - Created: PR_DESCRIPTION.md (detailed documentation) - Modified: All 17 command files to use new decorator system - Modified: src/molecule/command/base.py (removed Click dependencies) - Modified: src/molecule/shell.py, init files (updated imports) ## Testing & Quality Assurance - All existing tests pass (tox -e py) - Pre-commit hooks pass (ruff, mypy, pydoclint) - Comprehensive CLI audit ensures zero user-facing regressions - New test coverage for option sorting and decorator functionality This refactoring maintains complete backward compatibility while establishing a foundation for improved maintainability and potential framework migration.
4debc1d to
196fa0d
Compare
196fa0d to
474dfa3
Compare
Contributor
There was a problem hiding this comment.
Pull Request Overview
This PR refactors Molecule's CLI option handling to a framework-agnostic architecture while maintaining 100% backward compatibility. The change introduces a centralized option management system with improved user experience through better help text and option ordering.
- Introduces
CliOptiondataclass andCliOptionsregistry for framework-independent option definitions - Replaces manual Click decorators with
common_options()andoptions()decorators that use centralized definitions - Enhances user experience with automatic help text generation and logical option ordering in help output
Reviewed Changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/molecule/click_cfg.py | New framework-agnostic CLI option system with decorators and sorting |
| tests/unit/test_click_cfg.py | Comprehensive test coverage for the new CLI option architecture |
| src/molecule/constants.py | Added constants for default values used across CLI options |
| src/molecule/shell.py | Updated imports and removed \f docstring separator |
| src/molecule/command/*.py | Updated 17 command files to use new decorators and access options via ctx.params |
Comments suppressed due to low confidence (1)
tests/unit/test_click_cfg.py:840
- The test uses 'default' as a driver choice but this may not be a valid driver. Consider using a driver that's guaranteed to exist or mocking the drivers() function to ensure test reliability.
"--driver-name",
alisonlhart
approved these changes
Jul 24, 2025
Contributor
alisonlhart
left a comment
There was a problem hiding this comment.
This is awesome @cidrblock !
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refactor: Move Click configuration to framework-agnostic architecture
Overview
This PR refactors Molecule's CLI option handling system to use a framework-agnostic architecture while maintaining 100% backward compatibility. The changes prepare the codebase for potential future migration away from Click while providing immediate benefits in maintainability and user experience.
Key Changes
1. Framework-Agnostic CLI Option System
New Components:
CliOptiondataclass: Framework-independent option definitionsCliOptionsclass: Central registry of all CLI options with propertiesoptions()decorator: Applies lists ofCliOptioninstances to commandscommon_options()decorator: Automatically includes common options + specific additionsBenefits:
src/molecule/click_cfg.py)2. Enhanced User Experience
Custom Option Sorting:
CLI options now appear in a user-friendly order in help output:
--scenario-name,--exclude,--all)-f/--format,-h/--help)--driver-name,--platform-name)--report,--shared-inventory)FirstLineHelp System:
FirstLineHelpMixin: Automatically extracts first line of docstrings for short help\fseparators in docstrings3. Code Quality Improvements
Function Signatures:
Docstring Cleanup:
\fcharacters across the codebaseCLI Compatibility Audit
Zero User-Facing Changes Verified ✅
A comprehensive audit was performed comparing CLI options between
mainbranch and this feature branch:Audit Process
--option / --no-optionpairs to capture base option namesComplete Audit Results
✅ Final Result: No differences found! All commands match main branch.
Detailed Command-by-Command Verification
all,exclude,parallel,report,scenario-name,shared-inventory,shared-stateall,exclude,report,scenario-name,shared-inventory,shared-stateall,exclude,report,scenario-name,shared-inventory,shared-stateall,driver-name,exclude,report,scenario-name,shared-inventory,shared-stateall,exclude,report,scenario-name,shared-inventory,shared-stateall,driver-name,exclude,parallel,report,scenario-name,shared-inventory,shared-stateformatall,exclude,report,scenario-name,shared-inventory,shared-stateformat,scenario-namehost,scenario-namescenario-nameall,driver-name,exclude,force,format,report,scenario-name,shared-inventory,shared-statescenario-nameall,exclude,report,scenario-name,shared-inventory,shared-stateall,exclude,report,scenario-name,shared-inventory,shared-stateall,destroy,driver-name,exclude,parallel,platform-name,report,scenario-name,shared-inventory,shared-stateall,exclude,report,scenario-name,shared-inventory,shared-stateAudit Methodology Details
Option Parsing Logic:
--all / --no-all→ captured asall--report / --no-report→ captured asreport-s, --scenario-name→ captured asscenario-nameVerification Commands:
Total Verification:
Technical Implementation
CliOption Dataclass
Decorator Usage
FirstLineHelpMixin
Benefits:
\fcharacters neededFramework Migration Example: Argparse
The framework-agnostic architecture enables easy migration to other CLI frameworks. Here's how the same
CliOptiondefinitions could work withargparse:Current Click Implementation
Potential Argparse Implementation
Framework Adapter Example
Migration Benefits
Zero Business Logic Changes:
Maintained Functionality:
Gradual Migration Possible:
This architecture proves that the CLI framework is now a swappable implementation detail rather than a core dependency.
Files Changed
Core Infrastructure
src/molecule/click_cfg.py: New framework-agnostic option systemtests/unit/test_click_cfg.py: Comprehensive test coverageCommand Files (17 files)
All command files updated to use new decorators:
src/molecule/command/{check,cleanup,converge,create,dependency,destroy,drivers,idempotence,list,login,matrix,prepare,reset,side_effect,syntax,test,verify}.pySupporting Files
src/molecule/shell.py: Updated imports and docstringsrc/molecule/command/init/scenario.py: Updated docstringMigration Guide
For future CLI framework changes, the migration path is now clear:
options()andcommon_options()implementationsTesting
Breaking Changes
None. This is a pure refactoring with 100% backward compatibility maintained.
Future Cleanup Opportunities
CLI Option Consolidation
During this refactoring, several similar CLI options were preserved to maintain 100% backward compatibility:
Similar Options Identified:
scenario_namevsscenario_name_with_defaultvsscenario_name_singlevsscenario_name_single_with_defaultformat_fullvsformat_simpledriver_namevsdriver_name_with_choicesplatform_namevsplatform_name_with_defaultCurrent State:
The reasons for these variations are not immediately clear from the codebase. They were intentionally preserved in this PR to ensure zero breaking changes and avoid introducing regressions.
Required Before Consolidation:
Future Improvement Opportunity:
Once the above research is complete, a follow-up PR could potentially consolidate these into more generic, parameterized options - but only after thorough understanding and testing of the current behavior.
This refactoring establishes the foundation that makes such analysis and consolidation much safer to implement in the future.
Breaking Changes
None. This is a pure refactoring with 100% backward compatibility maintained.
This refactoring establishes a solid foundation for Molecule's CLI system while maintaining complete compatibility with existing workflows and scripts. The framework-agnostic architecture makes future consolidation and improvements much easier to implement safely.