rocketdoo 2.0.2b6__tar.gz → 2.2.0__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.
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/LICENSE +1 -1
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/MANIFEST.in +2 -0
- {rocketdoo-2.0.2b6/rocketdoo.egg-info → rocketdoo-2.2.0}/PKG-INFO +3 -3
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/README.md +1 -1
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/pyproject.toml +2 -1
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/cli.py +21 -0
- rocketdoo-2.2.0/rocketdoo/core/deploy/__init__.py +19 -0
- rocketdoo-2.2.0/rocketdoo/core/deploy/base.py +319 -0
- rocketdoo-2.2.0/rocketdoo/core/deploy/config_manager.py +611 -0
- rocketdoo-2.2.0/rocketdoo/core/deploy/module_packager.py +353 -0
- rocketdoo-2.2.0/rocketdoo/core/deploy/odoo_sh.py +591 -0
- rocketdoo-2.2.0/rocketdoo/core/deploy/vps.py +622 -0
- rocketdoo-2.2.0/rocketdoo/core/module_scanner.py +267 -0
- rocketdoo-2.2.0/rocketdoo/deploy_cli.py +507 -0
- rocketdoo-2.2.0/rocketdoo/templates/deploy/.deployignore +75 -0
- rocketdoo-2.2.0/rocketdoo/templates/deploy/deploy.yaml +0 -0
- rocketdoo-2.2.0/rocketdoo/templates/deploy/deploy.yaml.jinja +172 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0/rocketdoo.egg-info}/PKG-INFO +3 -3
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo.egg-info/SOURCES.txt +12 -1
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/__init__.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/config.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/core/__init__.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/core/config_loader.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/core/edition_setup.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/core/generator.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/core/gitman_config.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/core/port_validation.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/core/ssh_manager.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/core/utils.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/delete_identifiers.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/docker_cli.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/init_project.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/main.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/project_info.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/rocketdoo.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/scaffold.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/.devcontainer/devcontainer.json +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/.devcontainer/docker-compose.yaml +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/.vscode/launch.json +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/.vscode/launch.json.jinja +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/.vscode/settings.json +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/Dockerfile.jinja +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/addons/.gitkeep +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/config/odoo.conf +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/config/odoo.conf.jinja +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/docker-compose.yaml.jinja +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/install_dependencies.sh +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/templates/odoo_pg_pass +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo/welcome.py +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo.egg-info/dependency_links.txt +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo.egg-info/entry_points.txt +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo.egg-info/requires.txt +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/rocketdoo.egg-info/top_level.txt +0 -0
- {rocketdoo-2.0.2b6 → rocketdoo-2.2.0}/setup.cfg +0 -0
|
@@ -57,7 +57,7 @@ If the Library as you received it specifies that a proxy can decide whether futu
|
|
|
57
57
|
<div RKD as ROCKETDOO V2=""></div>
|
|
58
58
|
|
|
59
59
|
Licencia: LGPL-3.0+
|
|
60
|
-
Versión: "2.0
|
|
60
|
+
Versión: "2.2.0"
|
|
61
61
|
Autor: Horacio Montaño, Elias Braceras
|
|
62
62
|
Fecha: 16/10/2024
|
|
63
63
|
Descripción: Framework to development Odoo
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
include README.md
|
|
2
2
|
include LICENSE
|
|
3
|
+
include rocketdoo/templates/deploy/.deployignore
|
|
4
|
+
include rocketdoo/templates/deploy/deploy.yaml.jinja
|
|
3
5
|
recursive-include rocketdoo/templates *
|
|
4
6
|
recursive-include rocketdoo/templates .*
|
|
5
7
|
recursive-include rocketdoo/templates *.jinja
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rocketdoo
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Framework for creating Odoo development environments with Docker and custom templates.
|
|
5
5
|
Author-email: Horacio Montaño <horaciomontano@hdmsoft.com.ar>
|
|
6
6
|
License: GNU LESSER GENERAL PUBLIC LICENSE
|
|
@@ -62,7 +62,7 @@ License: GNU LESSER GENERAL PUBLIC LICENSE
|
|
|
62
62
|
<div RKD as ROCKETDOO V2=""></div>
|
|
63
63
|
|
|
64
64
|
Licencia: LGPL-3.0+
|
|
65
|
-
Versión: "2.0
|
|
65
|
+
Versión: "2.2.0"
|
|
66
66
|
Autor: Horacio Montaño, Elias Braceras
|
|
67
67
|
Fecha: 16/10/2024
|
|
68
68
|
Descripción: Framework to development Odoo
|
|
@@ -95,7 +95,7 @@ Odoo Development Framework
|
|
|
95
95
|
- "Horacio Montaño" and "Elias Braceras"
|
|
96
96
|
|
|
97
97
|
## Version:
|
|
98
|
-
- "2.0
|
|
98
|
+
- "2.2.0"
|
|
99
99
|
|
|
100
100
|
----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
101
101
|
|
|
@@ -15,7 +15,7 @@ Odoo Development Framework
|
|
|
15
15
|
- "Horacio Montaño" and "Elias Braceras"
|
|
16
16
|
|
|
17
17
|
## Version:
|
|
18
|
-
- "2.0
|
|
18
|
+
- "2.2.0"
|
|
19
19
|
|
|
20
20
|
----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
21
21
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "rocketdoo"
|
|
3
|
-
version = "2.0
|
|
3
|
+
version = "2.2.0"
|
|
4
4
|
description = "Framework for creating Odoo development environments with Docker and custom templates."
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Horacio Montaño", email = "horaciomontano@hdmsoft.com.ar" }
|
|
@@ -38,6 +38,7 @@ rocketdoo = [
|
|
|
38
38
|
"templates/**/**/*",
|
|
39
39
|
"templates/**/.vscode/*",
|
|
40
40
|
"templates/**/*.jinja",
|
|
41
|
+
"templates/deploy/*",
|
|
41
42
|
"templates/**/.*",
|
|
42
43
|
"templates/**/**/.*",
|
|
43
44
|
]
|
|
@@ -11,6 +11,14 @@ from .init_project import init_project
|
|
|
11
11
|
from .project_info import get_project_info, project_exists
|
|
12
12
|
from rocketdoo import __version__
|
|
13
13
|
from rocketdoo.docker_cli import docker, up, down, status, stop, pause, logs, build, restart
|
|
14
|
+
from rocketdoo.deploy_cli import (
|
|
15
|
+
deploy,
|
|
16
|
+
deploy_init,
|
|
17
|
+
list_modules,
|
|
18
|
+
deploy_config,
|
|
19
|
+
deploy_run,
|
|
20
|
+
validate_modules
|
|
21
|
+
)
|
|
14
22
|
|
|
15
23
|
# Detect the command name used to invoke the CLI
|
|
16
24
|
PROG_NAME = "rkd" if "rkd" in sys.argv[0] else "rocketdoo"
|
|
@@ -417,5 +425,18 @@ main.add_command(logs)
|
|
|
417
425
|
main.add_command(build)
|
|
418
426
|
main.add_command(delete_command)
|
|
419
427
|
|
|
428
|
+
# ============================================================
|
|
429
|
+
# 🚀 Register Deploy commands as Rocketdoo subcommands
|
|
430
|
+
# ============================================================
|
|
431
|
+
# Complete subgroup
|
|
432
|
+
main.add_command(deploy, name="deploy")
|
|
433
|
+
|
|
434
|
+
# Direct aliases for common deploy commands
|
|
435
|
+
main.add_command(deploy_init, name="deploy-init")
|
|
436
|
+
main.add_command(list_modules, name="deploy-list")
|
|
437
|
+
main.add_command(deploy_run, name="deploy-run")
|
|
438
|
+
main.add_command(deploy_config, name="deploy-config")
|
|
439
|
+
main.add_command(validate_modules, name="deploy-validate")
|
|
440
|
+
|
|
420
441
|
if __name__ == "__main__":
|
|
421
442
|
main()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RocketDoo Deploy Module
|
|
3
|
+
Deployment functionality for Odoo modules to VPS and Odoo.sh
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .base import BaseDeployer, DeploymentResult
|
|
7
|
+
from .config_manager import DeployConfigManager
|
|
8
|
+
from .module_packager import ModulePackager
|
|
9
|
+
from .vps import VPSDeployer
|
|
10
|
+
from .odoo_sh import OdooSHDeployer
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'BaseDeployer',
|
|
14
|
+
'DeploymentResult',
|
|
15
|
+
'DeployConfigManager',
|
|
16
|
+
'ModulePackager',
|
|
17
|
+
'VPSDeployer',
|
|
18
|
+
'OdooSHDeployer'
|
|
19
|
+
]
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
RocketDoo Deploy - Base Deployer
|
|
4
|
+
Abstract base class for all deployers
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import List, Dict, Optional
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
13
|
+
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DeploymentResult:
|
|
18
|
+
"""Result of a deployment operation"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, success: bool, message: str, details: Optional[Dict] = None):
|
|
21
|
+
self.success = success
|
|
22
|
+
self.message = message
|
|
23
|
+
self.details = details or {}
|
|
24
|
+
self.timestamp = datetime.now()
|
|
25
|
+
|
|
26
|
+
def __bool__(self):
|
|
27
|
+
return self.success
|
|
28
|
+
|
|
29
|
+
def __str__(self):
|
|
30
|
+
status = "✅ SUCCESS" if self.success else "❌ FAILED"
|
|
31
|
+
return f"{status}: {self.message}"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class BaseDeployer(ABC):
|
|
35
|
+
"""
|
|
36
|
+
Abstract base class for deployers
|
|
37
|
+
|
|
38
|
+
Each deployment type (VPS, Odoo.sh, etc) inherits from this class
|
|
39
|
+
and implements the abstract methods.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self, target_name: str, config: Dict, project_path: Path):
|
|
43
|
+
"""
|
|
44
|
+
Initialize the deployer
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
target_name: Name of the target (e.g., 'vps_production')
|
|
48
|
+
config: Target configuration from deploy.yaml
|
|
49
|
+
project_path: Root path of the project
|
|
50
|
+
"""
|
|
51
|
+
self.target_name = target_name
|
|
52
|
+
self.config = config
|
|
53
|
+
self.project_path = Path(project_path)
|
|
54
|
+
self.addons_path = self.project_path / config.get('modules', {}).get('base_path', 'addons')
|
|
55
|
+
self.console = console
|
|
56
|
+
|
|
57
|
+
# Deployment logs
|
|
58
|
+
self.logs = []
|
|
59
|
+
|
|
60
|
+
def log(self, message: str, level: str = "info"):
|
|
61
|
+
"""Log a message"""
|
|
62
|
+
timestamp = datetime.now().strftime("%H:%M:%S")
|
|
63
|
+
self.logs.append({
|
|
64
|
+
'timestamp': timestamp,
|
|
65
|
+
'level': level,
|
|
66
|
+
'message': message
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
# Also print to console
|
|
70
|
+
styles = {
|
|
71
|
+
'info': 'cyan',
|
|
72
|
+
'success': 'green',
|
|
73
|
+
'warning': 'yellow',
|
|
74
|
+
'error': 'red'
|
|
75
|
+
}
|
|
76
|
+
self.console.print(f"[{timestamp}] {message}", style=styles.get(level, 'white'))
|
|
77
|
+
|
|
78
|
+
@abstractmethod
|
|
79
|
+
def validate_config(self) -> List[str]:
|
|
80
|
+
"""
|
|
81
|
+
Validate deployer configuration
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
List of configuration errors (empty if OK)
|
|
85
|
+
"""
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
@abstractmethod
|
|
89
|
+
def pre_deploy_check(self) -> bool:
|
|
90
|
+
"""
|
|
91
|
+
Pre-deployment checks (connectivity, permissions, etc)
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
True if all checks pass
|
|
95
|
+
"""
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
@abstractmethod
|
|
99
|
+
def deploy_modules(self, modules: List[Dict]) -> DeploymentResult:
|
|
100
|
+
"""
|
|
101
|
+
Deploy the modules
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
modules: List of modules to deploy (from ModuleScanner)
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
DeploymentResult with the operation result
|
|
108
|
+
"""
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
@abstractmethod
|
|
112
|
+
def post_deploy_actions(self) -> DeploymentResult:
|
|
113
|
+
"""
|
|
114
|
+
Post-deployment actions (restart, update, etc)
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
DeploymentResult with the operation result
|
|
118
|
+
"""
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
def rollback(self) -> DeploymentResult:
|
|
122
|
+
"""
|
|
123
|
+
Rollback in case of error
|
|
124
|
+
Default does nothing, subclasses can implement
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
DeploymentResult with rollback result
|
|
128
|
+
"""
|
|
129
|
+
self.log("Rollback not implemented for this deployer", "warning")
|
|
130
|
+
return DeploymentResult(
|
|
131
|
+
success=True,
|
|
132
|
+
message="No rollback needed"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
def create_backup(self, modules: List[Dict]) -> bool:
|
|
136
|
+
"""
|
|
137
|
+
Create backup of modules before deployment
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
modules: List of modules to backup
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
True if backup was successful
|
|
144
|
+
"""
|
|
145
|
+
backup_config = self.config.get('backup', {})
|
|
146
|
+
if not backup_config.get('enabled', True):
|
|
147
|
+
return True
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
backup_path = self.project_path / backup_config.get('path', '.rkd/deploy_backups')
|
|
151
|
+
backup_path.mkdir(parents=True, exist_ok=True)
|
|
152
|
+
|
|
153
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
154
|
+
backup_dir = backup_path / f"{self.target_name}_{timestamp}"
|
|
155
|
+
backup_dir.mkdir()
|
|
156
|
+
|
|
157
|
+
# Copy modules to backup
|
|
158
|
+
import shutil
|
|
159
|
+
for module in modules:
|
|
160
|
+
src = Path(module['full_path'])
|
|
161
|
+
dst = backup_dir / module['name']
|
|
162
|
+
shutil.copytree(src, dst)
|
|
163
|
+
|
|
164
|
+
self.log(f"Backup created at: {backup_dir}", "success")
|
|
165
|
+
|
|
166
|
+
# Clean up old backups
|
|
167
|
+
self._cleanup_old_backups(backup_path, backup_config.get('keep_last', 3))
|
|
168
|
+
|
|
169
|
+
return True
|
|
170
|
+
|
|
171
|
+
except Exception as e:
|
|
172
|
+
self.log(f"Error creating backup: {e}", "error")
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
def _cleanup_old_backups(self, backup_path: Path, keep_last: int):
|
|
176
|
+
"""Delete old backups keeping only the last N"""
|
|
177
|
+
try:
|
|
178
|
+
backups = sorted(
|
|
179
|
+
[d for d in backup_path.iterdir() if d.is_dir() and d.name.startswith(self.target_name)],
|
|
180
|
+
key=lambda x: x.stat().st_mtime,
|
|
181
|
+
reverse=True
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Delete old backups
|
|
185
|
+
for backup in backups[keep_last:]:
|
|
186
|
+
import shutil
|
|
187
|
+
shutil.rmtree(backup)
|
|
188
|
+
self.log(f"Old backup deleted: {backup.name}", "info")
|
|
189
|
+
|
|
190
|
+
except Exception as e:
|
|
191
|
+
self.log(f"Error cleaning up backups: {e}", "warning")
|
|
192
|
+
|
|
193
|
+
def validate_modules(self, modules: List[Dict]) -> List[str]:
|
|
194
|
+
"""
|
|
195
|
+
Validate modules before deployment
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
modules: List of modules to validate
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
List of errors found
|
|
202
|
+
"""
|
|
203
|
+
errors = []
|
|
204
|
+
validations = self.config.get('validations', {})
|
|
205
|
+
|
|
206
|
+
if not validations:
|
|
207
|
+
return errors
|
|
208
|
+
|
|
209
|
+
for module in modules:
|
|
210
|
+
module_name = module['name']
|
|
211
|
+
module_path = Path(module['full_path'])
|
|
212
|
+
|
|
213
|
+
# Validate manifest
|
|
214
|
+
if validations.get('check_manifest', True):
|
|
215
|
+
manifest_path = module_path / "__manifest__.py"
|
|
216
|
+
if not manifest_path.exists():
|
|
217
|
+
errors.append(f"{module_name}: __manifest__.py not found")
|
|
218
|
+
|
|
219
|
+
# Validate Python syntax
|
|
220
|
+
if validations.get('check_python_syntax', True):
|
|
221
|
+
py_files = list(module_path.rglob("*.py"))
|
|
222
|
+
for py_file in py_files:
|
|
223
|
+
try:
|
|
224
|
+
with open(py_file, 'r', encoding='utf-8') as f:
|
|
225
|
+
compile(f.read(), str(py_file), 'exec')
|
|
226
|
+
except SyntaxError as e:
|
|
227
|
+
errors.append(f"{module_name}: Syntax error in {py_file.name}: {e}")
|
|
228
|
+
|
|
229
|
+
# Validate XML
|
|
230
|
+
if validations.get('check_xml_syntax', True):
|
|
231
|
+
xml_files = list(module_path.rglob("*.xml"))
|
|
232
|
+
for xml_file in xml_files:
|
|
233
|
+
try:
|
|
234
|
+
import xml.etree.ElementTree as ET
|
|
235
|
+
ET.parse(xml_file)
|
|
236
|
+
except ET.ParseError as e:
|
|
237
|
+
errors.append(f"{module_name}: Invalid XML in {xml_file.name}: {e}")
|
|
238
|
+
|
|
239
|
+
return errors
|
|
240
|
+
|
|
241
|
+
def execute(self, modules: List[Dict]) -> DeploymentResult:
|
|
242
|
+
"""
|
|
243
|
+
Execute the complete deployment
|
|
244
|
+
|
|
245
|
+
This is the main method that orchestrates the entire process
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
modules: List of modules to deploy
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
DeploymentResult with final result
|
|
252
|
+
"""
|
|
253
|
+
self.console.print(f"\n🚀 Starting deployment to: {self.target_name}", style="bold blue")
|
|
254
|
+
self.console.print(f"📦 Modules to deploy: {len(modules)}\n")
|
|
255
|
+
|
|
256
|
+
# 1. Validate configuration
|
|
257
|
+
self.log("Validating configuration...", "info")
|
|
258
|
+
config_errors = self.validate_config()
|
|
259
|
+
if config_errors:
|
|
260
|
+
for error in config_errors:
|
|
261
|
+
self.log(f" ❌ {error}", "error")
|
|
262
|
+
return DeploymentResult(
|
|
263
|
+
success=False,
|
|
264
|
+
message="Invalid configuration",
|
|
265
|
+
details={'errors': config_errors}
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# 2. Validate modules
|
|
269
|
+
self.log("Validating modules...", "info")
|
|
270
|
+
validation_errors = self.validate_modules(modules)
|
|
271
|
+
if validation_errors:
|
|
272
|
+
for error in validation_errors:
|
|
273
|
+
self.log(f" ❌ {error}", "error")
|
|
274
|
+
return DeploymentResult(
|
|
275
|
+
success=False,
|
|
276
|
+
message="Module validation failed",
|
|
277
|
+
details={'errors': validation_errors}
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# 3. Create backup
|
|
281
|
+
self.log("Creating backup...", "info")
|
|
282
|
+
if not self.create_backup(modules):
|
|
283
|
+
return DeploymentResult(
|
|
284
|
+
success=False,
|
|
285
|
+
message="Backup failed"
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
# 4. Pre-deploy check
|
|
289
|
+
self.log("Checking connectivity...", "info")
|
|
290
|
+
if not self.pre_deploy_check():
|
|
291
|
+
return DeploymentResult(
|
|
292
|
+
success=False,
|
|
293
|
+
message="Pre-deploy check failed"
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# 5. Deploy
|
|
297
|
+
self.log("Deploying modules...", "info")
|
|
298
|
+
deploy_result = self.deploy_modules(modules)
|
|
299
|
+
if not deploy_result.success:
|
|
300
|
+
self.log("Deployment failed, initiating rollback...", "error")
|
|
301
|
+
self.rollback()
|
|
302
|
+
return deploy_result
|
|
303
|
+
|
|
304
|
+
# 6. Post-deploy
|
|
305
|
+
self.log("Executing post-deploy actions...", "info")
|
|
306
|
+
post_result = self.post_deploy_actions()
|
|
307
|
+
if not post_result.success:
|
|
308
|
+
self.log("Post-deploy failed", "warning")
|
|
309
|
+
# Don't rollback here, modules are already deployed
|
|
310
|
+
|
|
311
|
+
self.console.print(f"\n✅ Deployment completed successfully!", style="bold green")
|
|
312
|
+
return DeploymentResult(
|
|
313
|
+
success=True,
|
|
314
|
+
message=f"Deployment to {self.target_name} completed",
|
|
315
|
+
details={
|
|
316
|
+
'modules_deployed': len(modules),
|
|
317
|
+
'logs': self.logs
|
|
318
|
+
}
|
|
319
|
+
)
|