diagram-to-iac 0.14.0__tar.gz → 1.0.1__tar.gz

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 (70) hide show
  1. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/PKG-INFO +1 -2
  2. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/pyproject.toml +2 -2
  3. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/r2d.py +6 -0
  4. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac.egg-info/PKG-INFO +1 -2
  5. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac.egg-info/SOURCES.txt +2 -1
  6. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac.egg-info/requires.txt +0 -1
  7. diagram_to_iac-1.0.1/tests/test_devops_in_a_box.py +304 -0
  8. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/README.md +0 -0
  9. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/setup.cfg +0 -0
  10. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/__init__.py +0 -0
  11. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/actions/__init__.py +0 -0
  12. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/actions/git_entry.py +0 -0
  13. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/actions/supervisor_entry.py +0 -0
  14. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/actions/terraform_agent_entry.py +0 -0
  15. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/__init__.py +0 -0
  16. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/demonstrator_langgraph/__init__.py +0 -0
  17. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/demonstrator_langgraph/agent.py +0 -0
  18. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/git_langgraph/__init__.py +0 -0
  19. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/git_langgraph/agent.py +0 -0
  20. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/git_langgraph/pr.py +0 -0
  21. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/hello_langgraph/__init__.py +0 -0
  22. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/hello_langgraph/agent.py +0 -0
  23. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/policy_agent/__init__.py +0 -0
  24. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/policy_agent/agent.py +0 -0
  25. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/policy_agent/integration_example.py +0 -0
  26. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/policy_agent/tools/__init__.py +0 -0
  27. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/policy_agent/tools/tfsec_tool.py +0 -0
  28. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/shell_langgraph/__init__.py +0 -0
  29. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/shell_langgraph/agent.py +0 -0
  30. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/shell_langgraph/detector.py +0 -0
  31. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/supervisor_langgraph/__init__.py +0 -0
  32. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/supervisor_langgraph/agent.py +0 -0
  33. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/supervisor_langgraph/demonstrator.py +0 -0
  34. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/supervisor_langgraph/guards.py +0 -0
  35. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/supervisor_langgraph/pat_loop.py +0 -0
  36. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/supervisor_langgraph/router.py +0 -0
  37. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/terraform_langgraph/__init__.py +0 -0
  38. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/terraform_langgraph/agent.py +0 -0
  39. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/agents/terraform_langgraph/parser.py +0 -0
  40. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/cli.py +0 -0
  41. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/core/__init__.py +0 -0
  42. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/core/agent_base.py +0 -0
  43. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/core/enhanced_memory.py +0 -0
  44. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/core/errors.py +0 -0
  45. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/core/issue_tracker.py +0 -0
  46. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/core/memory.py +0 -0
  47. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/services/__init__.py +0 -0
  48. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/services/observability.py +0 -0
  49. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/services/step_summary.py +0 -0
  50. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/__init__.py +0 -0
  51. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/api_utils.py +0 -0
  52. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/git/__init__.py +0 -0
  53. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/git/git.py +0 -0
  54. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/hello/__init__.py +0 -0
  55. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/hello/cal_utils.py +0 -0
  56. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/hello/text_utils.py +0 -0
  57. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/llm_utils/__init__.py +0 -0
  58. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/llm_utils/anthropic_driver.py +0 -0
  59. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/llm_utils/base_driver.py +0 -0
  60. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/llm_utils/gemini_driver.py +0 -0
  61. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/llm_utils/openai_driver.py +0 -0
  62. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/llm_utils/router.py +0 -0
  63. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/sec_utils.py +0 -0
  64. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/shell/__init__.py +0 -0
  65. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/shell/shell.py +0 -0
  66. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/text_utils.py +0 -0
  67. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac/tools/tf/terraform.py +0 -0
  68. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac.egg-info/dependency_links.txt +0 -0
  69. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac.egg-info/entry_points.txt +0 -0
  70. {diagram_to_iac-0.14.0 → diagram_to_iac-1.0.1}/src/diagram_to_iac.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diagram-to-iac
3
- Version: 0.14.0
3
+ Version: 1.0.1
4
4
  Summary: Convert architecture diagrams into IaC modules
5
5
  Author-email: vindpro <admin@vindpro.com>
6
6
  Description-Content-Type: text/markdown
@@ -17,7 +17,6 @@ Requires-Dist: pydantic==2.11.7
17
17
  Requires-Dist: PyYAML==6.0.2
18
18
  Requires-Dist: Requests==2.32.4
19
19
  Requires-Dist: GitPython<4.0,>=3.1
20
- Requires-Dist: pytest-mock<4.0.0,>=3.10.0
21
20
 
22
21
  # diagram-to-iac
23
22
 
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "diagram-to-iac"
7
- version = "0.14.0"
7
+ version = "1.0.1"
8
8
  description = "Convert architecture diagrams into IaC modules"
9
9
  readme = "README.md"
10
10
  authors = [{ name="vindpro", email="admin@vindpro.com" }]
11
- dependencies = ["anthropic==0.54.0", "google_api_python_client==2.172.0", "langchain_anthropic==0.3.15", "langchain-core>=0.3.62,<1.0.0", "langchain_google_genai==2.1.5", "langchain_openai==0.3.24", "langgraph==0.4.8", "openai==1.88.0", "protobuf>=5.27.0", "pydantic==2.11.7", "PyYAML==6.0.2", "Requests==2.32.4", "GitPython>=3.1,<4.0", "pytest-mock>=3.10.0,<4.0.0"] # ← always overwritten by update_deps.py
11
+ dependencies = ["anthropic==0.54.0", "google_api_python_client==2.172.0", "langchain_anthropic==0.3.15", "langchain-core>=0.3.62,<1.0.0", "langchain_google_genai==2.1.5", "langchain_openai==0.3.24", "langgraph==0.4.8", "openai==1.88.0", "protobuf>=5.27.0", "pydantic==2.11.7", "PyYAML==6.0.2", "Requests==2.32.4", "GitPython>=3.1,<4.0"] # ← always overwritten by update_deps.py
12
12
 
13
13
 
14
14
 
@@ -198,6 +198,12 @@ Mission: "One container, many minds—zero manual toil."
198
198
  type=str,
199
199
  help='Path to custom configuration file'
200
200
  )
201
+ parser.add_argument(
202
+ '--version',
203
+ action='version',
204
+ version='%(prog)s 1.0.0 - DevOps-in-a-Box R2D CLI',
205
+ help='Show version information and exit'
206
+ )
201
207
 
202
208
  return parser
203
209
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diagram-to-iac
3
- Version: 0.14.0
3
+ Version: 1.0.1
4
4
  Summary: Convert architecture diagrams into IaC modules
5
5
  Author-email: vindpro <admin@vindpro.com>
6
6
  Description-Content-Type: text/markdown
@@ -17,7 +17,6 @@ Requires-Dist: pydantic==2.11.7
17
17
  Requires-Dist: PyYAML==6.0.2
18
18
  Requires-Dist: Requests==2.32.4
19
19
  Requires-Dist: GitPython<4.0,>=3.1
20
- Requires-Dist: pytest-mock<4.0.0,>=3.10.0
21
20
 
22
21
  # diagram-to-iac
23
22
 
@@ -64,4 +64,5 @@ src/diagram_to_iac/tools/llm_utils/openai_driver.py
64
64
  src/diagram_to_iac/tools/llm_utils/router.py
65
65
  src/diagram_to_iac/tools/shell/__init__.py
66
66
  src/diagram_to_iac/tools/shell/shell.py
67
- src/diagram_to_iac/tools/tf/terraform.py
67
+ src/diagram_to_iac/tools/tf/terraform.py
68
+ tests/test_devops_in_a_box.py
@@ -11,4 +11,3 @@ pydantic==2.11.7
11
11
  PyYAML==6.0.2
12
12
  Requests==2.32.4
13
13
  GitPython<4.0,>=3.1
14
- pytest-mock<4.0.0,>=3.10.0
@@ -0,0 +1,304 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script to validate DevOps-in-a-Box R2D functionality
4
+ """
5
+
6
+ import sys
7
+ import os
8
+ import subprocess
9
+ import json
10
+ from pathlib import Path
11
+
12
+ def test_r2d_cli():
13
+ """Test the R2D CLI functionality"""
14
+ print("🧪 Testing DevOps-in-a-Box R2D CLI...")
15
+
16
+ # Test 1: Import and basic functionality
17
+ try:
18
+ sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
19
+ from diagram_to_iac.r2d import main
20
+ print("✅ R2D CLI module imports successfully")
21
+ except ImportError as e:
22
+ print(f"❌ Failed to import R2D CLI: {e}")
23
+ return False
24
+
25
+ # Test 2: Help command
26
+ try:
27
+ result = subprocess.run([
28
+ sys.executable, "-m", "diagram_to_iac.r2d", "--help"
29
+ ], capture_output=True, text=True, cwd=Path(__file__).parent.parent)
30
+
31
+ if result.returncode == 0:
32
+ print("✅ R2D CLI help command works")
33
+ else:
34
+ print(f"❌ R2D CLI help failed: {result.stderr}")
35
+ return False
36
+ except Exception as e:
37
+ print(f"❌ Failed to run R2D CLI help: {e}")
38
+ return False
39
+
40
+ # Test 3: Version command
41
+ try:
42
+ result = subprocess.run([
43
+ sys.executable, "-m", "diagram_to_iac.r2d", "--version"
44
+ ], capture_output=True, text=True, cwd=Path(__file__).parent.parent)
45
+
46
+ if result.returncode == 0:
47
+ print(f"✅ R2D CLI version: {result.stdout.strip()}")
48
+ else:
49
+ print(f"❌ R2D CLI version failed: {result.stderr}")
50
+ return False
51
+ except Exception as e:
52
+ print(f"❌ Failed to run R2D CLI version: {e}")
53
+ return False
54
+
55
+ return True
56
+
57
+ def test_container_build():
58
+ """Test container build locally"""
59
+ print("\n🐳 Testing DevOps-in-a-Box Container Build...")
60
+
61
+ dockerfile_path = Path(__file__).parent.parent / ".github/actions/r2d/Dockerfile"
62
+
63
+ if not dockerfile_path.exists():
64
+ print(f"❌ Dockerfile not found at {dockerfile_path}")
65
+ return False
66
+
67
+ print("✅ Dockerfile exists")
68
+
69
+ # Check if Docker is available
70
+ try:
71
+ result = subprocess.run(["docker", "--version"], capture_output=True, text=True)
72
+ if result.returncode == 0:
73
+ print(f"✅ Docker available: {result.stdout.strip()}")
74
+ else:
75
+ print("⚠️ Docker not available - skipping container build test")
76
+ return True
77
+ except FileNotFoundError:
78
+ print("⚠️ Docker not installed - skipping container build test")
79
+ return True
80
+
81
+ # Test container build (dry run)
82
+ try:
83
+ print("🔨 Testing container build (this may take a few minutes)...")
84
+ result = subprocess.run([
85
+ "docker", "build",
86
+ "-t", "diagram-to-iac-r2d:test",
87
+ "-f", str(dockerfile_path),
88
+ ".",
89
+ "--build-arg", "PACKAGE_VERSION=test"
90
+ ], capture_output=True, text=True, cwd=dockerfile_path.parent)
91
+
92
+ if result.returncode == 0:
93
+ print("✅ Container builds successfully")
94
+
95
+ # Test container run
96
+ test_result = subprocess.run([
97
+ "docker", "run", "--rm",
98
+ "diagram-to-iac-r2d:test",
99
+ "--help"
100
+ ], capture_output=True, text=True)
101
+
102
+ if test_result.returncode == 0:
103
+ print("✅ Container runs successfully")
104
+ else:
105
+ print(f"⚠️ Container run test failed: {test_result.stderr}")
106
+
107
+ # Clean up
108
+ subprocess.run(["docker", "rmi", "diagram-to-iac-r2d:test"], capture_output=True)
109
+
110
+ else:
111
+ print(f"❌ Container build failed: {result.stderr}")
112
+ return False
113
+
114
+ except Exception as e:
115
+ print(f"❌ Container build test failed: {e}")
116
+ return False
117
+
118
+ return True
119
+
120
+ def test_github_action_definition():
121
+ """Test GitHub Action definition"""
122
+ print("\n🎬 Testing GitHub Action Definition...")
123
+
124
+ action_path = Path(__file__).parent.parent / ".github/actions/r2d/action.yml"
125
+
126
+ if not action_path.exists():
127
+ print(f"❌ action.yml not found at {action_path}")
128
+ return False
129
+
130
+ try:
131
+ # PyYAML is a runtime dependency, so it should already be available
132
+ import yaml
133
+
134
+ with open(action_path, 'r') as f:
135
+ action_config = yaml.safe_load(f)
136
+
137
+ # Validate required fields
138
+ required_fields = ['name', 'description', 'inputs', 'outputs', 'runs']
139
+ for field in required_fields:
140
+ if field not in action_config:
141
+ print(f"❌ Missing required field in action.yml: {field}")
142
+ return False
143
+
144
+ print("✅ action.yml has all required fields")
145
+
146
+ # Check branding
147
+ if 'branding' in action_config:
148
+ print("✅ action.yml includes branding")
149
+
150
+ # Check inputs
151
+ required_inputs = ['repo']
152
+ for input_name in required_inputs:
153
+ if input_name not in action_config['inputs']:
154
+ print(f"❌ Missing required input: {input_name}")
155
+ return False
156
+
157
+ print("✅ action.yml has all required inputs")
158
+
159
+ # Check if using Dockerfile or published image
160
+ runs_config = action_config['runs']
161
+ if runs_config.get('using') == 'docker':
162
+ image = runs_config.get('image', '')
163
+ if image == 'Dockerfile':
164
+ print("ℹ️ Action uses local Dockerfile (development mode)")
165
+ elif image.startswith('docker://'):
166
+ print(f"✅ Action uses published image: {image}")
167
+ else:
168
+ print(f"⚠️ Unexpected image configuration: {image}")
169
+
170
+ except Exception as e:
171
+ print(f"❌ Failed to validate action.yml: {e}")
172
+ return False
173
+
174
+ return True
175
+
176
+ def test_workflow_definition():
177
+ """Test GitHub workflow definition"""
178
+ print("\n⚙️ Testing GitHub Workflow Definition...")
179
+
180
+ workflow_path = Path(__file__).parent.parent / ".github/workflows/diagram-to-iac-build.yml"
181
+
182
+ if not workflow_path.exists():
183
+ print(f"❌ workflow file not found at {workflow_path}")
184
+ return False
185
+
186
+ try:
187
+ import yaml
188
+
189
+ with open(workflow_path, 'r') as f:
190
+ content = f.read()
191
+
192
+ # Parse YAML content, handling the comment properly
193
+ try:
194
+ # First try parsing as-is (in case there's no comment)
195
+ workflow_config = yaml.safe_load(content)
196
+ except yaml.YAMLError:
197
+ # If that fails, try removing the first line if it's a comment
198
+ lines = content.split('\n')
199
+ if lines and lines[0].strip().startswith('#'):
200
+ yaml_content = '\n'.join(lines[1:])
201
+ workflow_config = yaml.safe_load(yaml_content)
202
+ else:
203
+ raise
204
+
205
+ # Validate required fields
206
+ # Note: GitHub Actions uses 'on' as a trigger key, but PyYAML may parse it as boolean True
207
+ required_fields = ['name', 'jobs']
208
+ trigger_field = 'on' # Look for 'on' key
209
+
210
+ for field in required_fields:
211
+ if field not in workflow_config:
212
+ print(f"❌ Missing required field in workflow: {field}")
213
+ return False
214
+
215
+ # Check for trigger field ('on' or boolean True)
216
+ has_trigger = False
217
+ if 'on' in workflow_config:
218
+ has_trigger = True
219
+ print("✅ Workflow has 'on' trigger field")
220
+ elif True in workflow_config:
221
+ has_trigger = True
222
+ print("✅ Workflow has trigger field (parsed as boolean)")
223
+ # PyYAML converts 'on:' to boolean True, this is normal
224
+
225
+ if not has_trigger:
226
+ print("❌ Missing trigger field ('on') in workflow")
227
+ return False
228
+
229
+ print("✅ Workflow has all required fields")
230
+
231
+ # Check jobs
232
+ jobs = workflow_config['jobs']
233
+ expected_jobs = ['publish-python-package', 'build-r2d-container']
234
+ for job_name in expected_jobs:
235
+ if job_name not in jobs:
236
+ print(f"❌ Missing expected job: {job_name}")
237
+ return False
238
+
239
+ print("✅ Workflow has all expected jobs")
240
+
241
+ # Check permissions
242
+ r2d_job = jobs['build-r2d-container']
243
+ if 'permissions' in r2d_job:
244
+ permissions = r2d_job['permissions']
245
+ if permissions.get('contents') == 'write':
246
+ print("✅ R2D container job has write permissions")
247
+ else:
248
+ print("⚠️ R2D container job may not have sufficient permissions")
249
+
250
+ except yaml.YAMLError as e:
251
+ print(f"❌ YAML parsing error in workflow: {e}")
252
+ return False
253
+ except Exception as e:
254
+ print(f"❌ Failed to validate workflow: {e}")
255
+ return False
256
+
257
+ return True
258
+
259
+ def main():
260
+ """Run all tests"""
261
+ print("🚀 DevOps-in-a-Box System Validation")
262
+ print("=" * 50)
263
+
264
+ tests = [
265
+ ("R2D CLI", test_r2d_cli),
266
+ ("Container Build", test_container_build),
267
+ ("GitHub Action", test_github_action_definition),
268
+ ("GitHub Workflow", test_workflow_definition),
269
+ ]
270
+
271
+ results = []
272
+
273
+ for test_name, test_func in tests:
274
+ try:
275
+ result = test_func()
276
+ results.append((test_name, result))
277
+ except Exception as e:
278
+ print(f"❌ {test_name} test crashed: {e}")
279
+ results.append((test_name, False))
280
+
281
+ print("\n" + "=" * 50)
282
+ print("📊 Test Results Summary")
283
+ print("=" * 50)
284
+
285
+ passed = 0
286
+ total = len(results)
287
+
288
+ for test_name, result in results:
289
+ status = "✅ PASS" if result else "❌ FAIL"
290
+ print(f"{test_name:<20} {status}")
291
+ if result:
292
+ passed += 1
293
+
294
+ print(f"\nOverall: {passed}/{total} tests passed")
295
+
296
+ if passed == total:
297
+ print("\n🎉 All tests passed! DevOps-in-a-Box is ready for deployment.")
298
+ return 0
299
+ else:
300
+ print(f"\n⚠️ {total - passed} test(s) failed. Please review the issues above.")
301
+ return 1
302
+
303
+ if __name__ == "__main__":
304
+ sys.exit(main())