domd 0.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. domd/__init__.py +44 -0
  2. domd/adapters/__init__.py +0 -0
  3. domd/adapters/api/__init__.py +0 -0
  4. domd/adapters/api/command_testing.py +198 -0
  5. domd/adapters/api/flask_api.py +754 -0
  6. domd/adapters/cli/__init__.py +0 -0
  7. domd/adapters/cli/command_presenter.py +132 -0
  8. domd/adapters/formatters/__init__.py +0 -0
  9. domd/adapters/formatters/markdown_formatter.py +108 -0
  10. domd/adapters/persistence/__init__.py +0 -0
  11. domd/adapters/persistence/in_memory_command_repository.py +123 -0
  12. domd/adapters/persistence/shell_command_executor.py +536 -0
  13. domd/api.py +145 -0
  14. domd/application/__init__.py +0 -0
  15. domd/application/factory.py +149 -0
  16. domd/cli/__init__.py +9 -0
  17. domd/cli/cli.py +638 -0
  18. domd/cli/commands/test_commands.py +138 -0
  19. domd/command_execution/__init__.py +15 -0
  20. domd/core/__init__.py +67 -0
  21. domd/core/command_detection/__init__.py +18 -0
  22. domd/core/command_detection/base_detector.py +195 -0
  23. domd/core/command_detection/docker_tester.py +187 -0
  24. domd/core/command_detection/handlers/__init__.py +6 -0
  25. domd/core/command_detection/handlers/command_handler.py +1373 -0
  26. domd/core/command_detection/handlers/config_handler.py +131 -0
  27. domd/core/command_detection/models.py +98 -0
  28. domd/core/command_detection/parsers/__init__.py +6 -0
  29. domd/core/command_detection/parsers/base_parser.py +85 -0
  30. domd/core/command_detection/parsers/parser_registry.py +155 -0
  31. domd/core/command_detection/project_detector.py +311 -0
  32. domd/core/command_detection/utils/__init__.py +11 -0
  33. domd/core/command_detection/utils/file_utils.py +107 -0
  34. domd/core/command_detection/utils/virtualenv.py +106 -0
  35. domd/core/command_execution/__init__.py +28 -0
  36. domd/core/command_execution/command_executor.py +222 -0
  37. domd/core/command_execution/command_recorder.py +96 -0
  38. domd/core/command_execution/command_runner.py +199 -0
  39. domd/core/command_execution/environment_detector.py +173 -0
  40. domd/core/command_execution/executor.py +160 -0
  41. domd/core/commands/__init__.py +6 -0
  42. domd/core/commands/command.py +62 -0
  43. domd/core/commands/executor.py +249 -0
  44. domd/core/detector.py +15 -0
  45. domd/core/domain/__init__.py +0 -0
  46. domd/core/domain/command.py +132 -0
  47. domd/core/parsers/__init__.py +34 -0
  48. domd/core/parsers/ansible_galaxy.py +234 -0
  49. domd/core/parsers/ansible_inventory.py +148 -0
  50. domd/core/parsers/ansible_playbook.py +122 -0
  51. domd/core/parsers/ansible_role.py +140 -0
  52. domd/core/parsers/ansible_vault.py +133 -0
  53. domd/core/parsers/base.py +103 -0
  54. domd/core/parsers/cargo_toml.py +130 -0
  55. domd/core/parsers/composer_json.py +58 -0
  56. domd/core/parsers/go_mod.py +135 -0
  57. domd/core/parsers/makefile.py +83 -0
  58. domd/core/parsers/package_json.py +109 -0
  59. domd/core/parsers/pyproject_toml.py +324 -0
  60. domd/core/parsers/tox_ini.py +120 -0
  61. domd/core/parsing/__init__.py +29 -0
  62. domd/core/parsing/base.py +95 -0
  63. domd/core/parsing/file_processor.py +249 -0
  64. domd/core/parsing/parser_registry.py +174 -0
  65. domd/core/parsing/pattern_matcher.py +261 -0
  66. domd/core/ports/__init__.py +0 -0
  67. domd/core/ports/command_executor.py +54 -0
  68. domd/core/ports/command_repository.py +104 -0
  69. domd/core/ports/report_formatter.py +46 -0
  70. domd/core/project_detection/__init__.py +5 -0
  71. domd/core/project_detection/command_handling.py +576 -0
  72. domd/core/project_detection/config_files.py +147 -0
  73. domd/core/project_detection/detector.py +1031 -0
  74. domd/core/project_detection/virtualenv.py +110 -0
  75. domd/core/reporters/__init__.py +7 -0
  76. domd/core/reporters/base.py +49 -0
  77. domd/core/reporters/done_md.py +154 -0
  78. domd/core/reporters/todo_md.py +219 -0
  79. domd/core/reporting/__init__.py +31 -0
  80. domd/core/reporting/formatters.py +474 -0
  81. domd/core/reporting/reporter.py +396 -0
  82. domd/core/services/__init__.py +0 -0
  83. domd/core/services/command_service.py +211 -0
  84. domd/core/services/report_service.py +83 -0
  85. domd/core/utils/__init__.py +21 -0
  86. domd/core/utils/command_utils.py +56 -0
  87. domd/core/utils/environment.py +195 -0
  88. domd/core/utils/file_utils.py +85 -0
  89. domd/core/utils/logging_utils.py +76 -0
  90. domd/core/utils/virtualenv.py +141 -0
  91. domd/parsers/__init__.py +77 -0
  92. domd/parsers/ansible.py +31 -0
  93. domd/parsers/base.py +4 -0
  94. domd/parsers/build_systems.py +32 -0
  95. domd/parsers/ci_cd.py +22 -0
  96. domd/parsers/docker/__init__.py +27 -0
  97. domd/parsers/docker/docker_compose.py +107 -0
  98. domd/parsers/docker/dockerfile.py +213 -0
  99. domd/parsers/docker.py +4 -0
  100. domd/parsers/javascript/__init__.py +28 -0
  101. domd/parsers/javascript.py +4 -0
  102. domd/parsers/markdown_parser.py +83 -0
  103. domd/parsers/package_json.py +106 -0
  104. domd/parsers/python.py +25 -0
  105. domd/parsers/test_build_systems.py +3 -0
  106. domd/parsers/test_ci_cd.py +3 -0
  107. domd/parsers/test_docker.py +3 -0
  108. domd/parsers/test_javascript.py +3 -0
  109. domd/parsers/test_python.py +3 -0
  110. domd/parsing/__init__.py +15 -0
  111. domd/parsing/base.py +5 -0
  112. domd/reporters/__init__.py +1 -0
  113. domd/reporters/console.py +4 -0
  114. domd/reporters/json_reporter.py +4 -0
  115. domd/reporters/test_console.py +3 -0
  116. domd/reporters/test_json_reporter.py +3 -0
  117. domd/reporters/test_todo_md.py +3 -0
  118. domd/reporters/todo_md.py +119 -0
  119. domd/reporting/__init__.py +22 -0
  120. domd/utils/__init__.py +1 -0
  121. domd/utils/command_runner.py +4 -0
  122. domd/utils/file_utils.py +4 -0
  123. domd/utils/path_utils.py +83 -0
  124. domd/utils/test_command_runner.py +3 -0
  125. domd/utils/test_file_utils.py +3 -0
  126. domd-0.0.0.dist-info/METADATA +5 -0
  127. domd-0.0.0.dist-info/RECORD +130 -0
  128. domd-0.0.0.dist-info/WHEEL +5 -0
  129. domd-0.0.0.dist-info/licenses/LICENSE +201 -0
  130. domd-0.0.0.dist-info/top_level.txt +1 -0
domd/__init__.py ADDED
@@ -0,0 +1,44 @@
1
+ """
2
+ TodoMD Package
3
+
4
+ Automatically detects and tests project commands from various configuration files,
5
+ generates TODO.md for failed commands with detailed error reports.
6
+
7
+ Supports: Makefile, package.json, pyproject.toml, Docker, CI/CD workflows, and more.
8
+ """
9
+
10
+ __version__ = "2.2.64"
11
+ __author__ = "Tom Sapletta"
12
+ __email__ = "info@softreck.dev"
13
+ __license__ = "Apache-2.0"
14
+
15
+ from typing import Callable, TypeVar
16
+
17
+ from .core.project_detection.detector import ProjectCommandDetector
18
+
19
+ # Define a type variable for the main function
20
+ F = TypeVar("F", bound=Callable[..., int])
21
+
22
+ # Import main function from cli module
23
+ try:
24
+ from .cli import main
25
+ except ImportError:
26
+ # Fallback main function if cli import fails
27
+ def main() -> int:
28
+ """Fallback main function.
29
+
30
+ Returns:
31
+ int: Exit code (1 for error)
32
+ """
33
+ print("Error: Could not import CLI module.")
34
+ print(
35
+ "Please check your installation and ensure all dependencies are installed."
36
+ )
37
+ return 1
38
+
39
+
40
+ __all__ = [
41
+ "ProjectCommandDetector",
42
+ "main",
43
+ "__version__",
44
+ ]
File without changes
File without changes
@@ -0,0 +1,198 @@
1
+ """
2
+ REST API endpoints for command testing functionality.
3
+ """
4
+
5
+ from pathlib import Path
6
+ from typing import Dict, List, Optional
7
+
8
+ from flask import jsonify, request
9
+ from werkzeug.exceptions import BadRequest, NotFound
10
+
11
+
12
+ def register_command_testing_routes(api, command_handler):
13
+ """Register command testing API routes.
14
+
15
+ Args:
16
+ api: The Flask API instance
17
+ command_handler: The CommandHandler instance
18
+ """
19
+
20
+ @api.app.route("/api/commands/validate", methods=["POST"])
21
+ @api.require_auth()
22
+ def validate_commands():
23
+ """
24
+ Validate a list of commands and optionally test them in Docker.
25
+
26
+ Request body:
27
+ {
28
+ "commands": ["command1", "command2", ...],
29
+ "test_in_docker": true/false,
30
+ "update_doignore": true/false
31
+ }
32
+
33
+ Returns:
34
+ JSON response with validation results
35
+ """
36
+ data = request.get_json()
37
+
38
+ if not data or "commands" not in data:
39
+ raise BadRequest("Missing 'commands' in request body")
40
+
41
+ commands = data.get("commands", [])
42
+ test_in_docker = data.get("test_in_docker", False)
43
+ update_doignore = data.get("update_doignore", False)
44
+
45
+ if not isinstance(commands, list) or not all(
46
+ isinstance(cmd, str) for cmd in commands
47
+ ):
48
+ raise BadRequest("'commands' must be a list of strings")
49
+
50
+ # Validate commands
51
+ results = command_handler.validate_commands(
52
+ commands, test_in_docker=test_in_docker
53
+ )
54
+
55
+ # Update .doignore if requested and testing in Docker
56
+ updated_ignore_count = 0
57
+ if test_in_docker and update_doignore:
58
+ failed_commands = [
59
+ cmd
60
+ for cmd, (is_valid, _) in results.items()
61
+ if not is_valid and cmd in command_handler.invalid_commands
62
+ ]
63
+ updated_ignore_count = command_handler.update_doignore(failed_commands)
64
+
65
+ # Prepare response
66
+ response = {
67
+ "validated_commands": len(results),
68
+ "valid_commands": len(
69
+ [1 for _, (is_valid, _) in results.items() if is_valid]
70
+ ),
71
+ "invalid_commands": len(command_handler.invalid_commands),
72
+ "untested_commands": len(command_handler.untested_commands),
73
+ "updated_ignore_count": updated_ignore_count,
74
+ "results": [
75
+ {
76
+ "command": cmd,
77
+ "is_valid": is_valid,
78
+ "reason": reason,
79
+ "tested_in_docker": test_in_docker
80
+ and is_valid
81
+ and cmd not in command_handler.untested_commands,
82
+ }
83
+ for cmd, (is_valid, reason) in results.items()
84
+ ],
85
+ }
86
+
87
+ return api._create_response(response)
88
+
89
+ @api.app.route("/api/commands/test-docker", methods=["POST"])
90
+ @api.require_auth()
91
+ def test_commands_in_docker():
92
+ """
93
+ Test commands in Docker containers.
94
+
95
+ Request body:
96
+ {
97
+ "commands": ["command1", "command2", ...],
98
+ "update_doignore": true/false
99
+ }
100
+
101
+ Returns:
102
+ JSON response with test results
103
+ """
104
+ if (
105
+ not command_handler.enable_docker_testing
106
+ or not command_handler.docker_tester
107
+ ):
108
+ return api._create_response(
109
+ {"error": "Docker testing is not available"}, status=503
110
+ )
111
+
112
+ data = request.get_json()
113
+
114
+ if not data or "commands" not in data:
115
+ raise BadRequest("Missing 'commands' in request body")
116
+
117
+ commands = data.get("commands", [])
118
+ update_doignore = data.get("update_doignore", False)
119
+
120
+ if not isinstance(commands, list) or not all(
121
+ isinstance(cmd, str) for cmd in commands
122
+ ):
123
+ raise BadRequest("'commands' must be a list of strings")
124
+
125
+ # Test commands in Docker
126
+ results = command_handler.docker_tester.test_commands_in_docker(commands)
127
+
128
+ # Update .doignore if requested
129
+ updated_ignore_count = 0
130
+ if update_doignore:
131
+ failed_commands = [
132
+ cmd for cmd, (success, _) in results.items() if not success
133
+ ]
134
+ updated_ignore_count = command_handler.update_doignore(failed_commands)
135
+
136
+ # Prepare response
137
+ response = {
138
+ "tested_commands": len(results),
139
+ "successful_commands": len(
140
+ [1 for _, (success, _) in results.items() if success]
141
+ ),
142
+ "failed_commands": len(
143
+ [1 for _, (success, _) in results.items() if not success]
144
+ ),
145
+ "updated_ignore_count": updated_ignore_count,
146
+ "results": [
147
+ {"command": cmd, "success": success, "output": output}
148
+ for cmd, (success, output) in results.items()
149
+ ],
150
+ }
151
+
152
+ return api._create_response(response)
153
+
154
+ @api.app.route("/api/commands/ignore", methods=["POST"])
155
+ @api.require_auth(roles=["admin"])
156
+ def add_to_doignore():
157
+ """
158
+ Add commands to .doignore file.
159
+
160
+ Request body:
161
+ {
162
+ "commands": ["command1", "command2", ...],
163
+ "comment": "Optional comment"
164
+ }
165
+
166
+ Returns:
167
+ JSON response with operation result
168
+ """
169
+ data = request.get_json()
170
+
171
+ if not data or "commands" not in data:
172
+ raise BadRequest("Missing 'commands' in request body")
173
+
174
+ commands = data.get("commands", [])
175
+ comment = data.get("comment", "")
176
+
177
+ if not isinstance(commands, list) or not all(
178
+ isinstance(cmd, str) for cmd in commands
179
+ ):
180
+ raise BadRequest("'commands' must be a list of strings")
181
+
182
+ # Add commands to .doignore
183
+ added_count = command_handler.update_doignore(commands)
184
+
185
+ # Add comment if provided
186
+ if comment and added_count > 0:
187
+ try:
188
+ with open(command_handler.doignore_path, "a") as f:
189
+ f.write(f"\n# {comment}\n")
190
+ except Exception as e:
191
+ logger.warning(f"Failed to add comment to .doignore: {e}")
192
+
193
+ return api._create_response(
194
+ {
195
+ "added_commands": added_count,
196
+ "total_ignored_commands": len(command_handler.invalid_commands),
197
+ }
198
+ )