sum-cli 3.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.
- sum/__init__.py +1 -0
- sum/boilerplate/.env.example +124 -0
- sum/boilerplate/.gitea/workflows/ci.yml +33 -0
- sum/boilerplate/.gitea/workflows/deploy-production.yml +98 -0
- sum/boilerplate/.gitea/workflows/deploy-staging.yml +113 -0
- sum/boilerplate/.github/workflows/ci.yml +36 -0
- sum/boilerplate/.github/workflows/deploy-production.yml +102 -0
- sum/boilerplate/.github/workflows/deploy-staging.yml +115 -0
- sum/boilerplate/.gitignore +45 -0
- sum/boilerplate/README.md +259 -0
- sum/boilerplate/manage.py +34 -0
- sum/boilerplate/project_name/__init__.py +5 -0
- sum/boilerplate/project_name/home/__init__.py +5 -0
- sum/boilerplate/project_name/home/apps.py +20 -0
- sum/boilerplate/project_name/home/management/__init__.py +0 -0
- sum/boilerplate/project_name/home/management/commands/__init__.py +0 -0
- sum/boilerplate/project_name/home/management/commands/populate_demo_content.py +644 -0
- sum/boilerplate/project_name/home/management/commands/seed.py +129 -0
- sum/boilerplate/project_name/home/management/commands/seed_showroom.py +1661 -0
- sum/boilerplate/project_name/home/migrations/__init__.py +3 -0
- sum/boilerplate/project_name/home/models.py +13 -0
- sum/boilerplate/project_name/settings/__init__.py +5 -0
- sum/boilerplate/project_name/settings/base.py +348 -0
- sum/boilerplate/project_name/settings/local.py +78 -0
- sum/boilerplate/project_name/settings/production.py +106 -0
- sum/boilerplate/project_name/urls.py +33 -0
- sum/boilerplate/project_name/wsgi.py +16 -0
- sum/boilerplate/pytest.ini +5 -0
- sum/boilerplate/requirements.txt +25 -0
- sum/boilerplate/static/client/.gitkeep +3 -0
- sum/boilerplate/templates/overrides/.gitkeep +3 -0
- sum/boilerplate/tests/__init__.py +3 -0
- sum/boilerplate/tests/test_health.py +51 -0
- sum/cli.py +42 -0
- sum/commands/__init__.py +10 -0
- sum/commands/backup.py +308 -0
- sum/commands/check.py +128 -0
- sum/commands/init.py +265 -0
- sum/commands/promote.py +758 -0
- sum/commands/run.py +96 -0
- sum/commands/themes.py +56 -0
- sum/commands/update.py +301 -0
- sum/config.py +61 -0
- sum/docs/USER_GUIDE.md +663 -0
- sum/exceptions.py +45 -0
- sum/setup/__init__.py +17 -0
- sum/setup/auth.py +184 -0
- sum/setup/database.py +58 -0
- sum/setup/deps.py +73 -0
- sum/setup/git_ops.py +463 -0
- sum/setup/infrastructure.py +576 -0
- sum/setup/orchestrator.py +354 -0
- sum/setup/remote_themes.py +371 -0
- sum/setup/scaffold.py +500 -0
- sum/setup/seed.py +110 -0
- sum/setup/site_orchestrator.py +441 -0
- sum/setup/venv.py +89 -0
- sum/system_config.py +330 -0
- sum/themes_registry.py +180 -0
- sum/utils/__init__.py +25 -0
- sum/utils/django.py +97 -0
- sum/utils/environment.py +76 -0
- sum/utils/output.py +78 -0
- sum/utils/project.py +110 -0
- sum/utils/prompts.py +36 -0
- sum/utils/validation.py +313 -0
- sum_cli-3.0.0.dist-info/METADATA +127 -0
- sum_cli-3.0.0.dist-info/RECORD +72 -0
- sum_cli-3.0.0.dist-info/WHEEL +5 -0
- sum_cli-3.0.0.dist-info/entry_points.txt +2 -0
- sum_cli-3.0.0.dist-info/licenses/LICENSE +29 -0
- sum_cli-3.0.0.dist-info/top_level.txt +1 -0
sum/commands/init.py
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# pyright: reportImplicitStringConcatenation=false, reportUnusedCallResult=false
|
|
2
|
+
|
|
3
|
+
"""Init command implementation.
|
|
4
|
+
|
|
5
|
+
Creates a working site on staging at /srv/sum/<name>/ with:
|
|
6
|
+
- Postgres database
|
|
7
|
+
- External venv
|
|
8
|
+
- Systemd service
|
|
9
|
+
- Caddy configuration
|
|
10
|
+
- Git repository (optional)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from types import ModuleType
|
|
16
|
+
|
|
17
|
+
from sum.exceptions import SetupError
|
|
18
|
+
from sum.setup.infrastructure import check_infrastructure
|
|
19
|
+
from sum.setup.site_orchestrator import SiteOrchestrator, SiteSetupConfig
|
|
20
|
+
from sum.system_config import ConfigurationError, get_system_config
|
|
21
|
+
from sum.utils.output import OutputFormatter
|
|
22
|
+
from sum.utils.project import validate_project_name
|
|
23
|
+
|
|
24
|
+
click_module: ModuleType | None
|
|
25
|
+
try:
|
|
26
|
+
import click as click_module
|
|
27
|
+
except ImportError: # pragma: no cover - click is expected in the CLI runtime
|
|
28
|
+
click_module = None
|
|
29
|
+
|
|
30
|
+
click: ModuleType | None = click_module
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def run_init(
|
|
34
|
+
site_name: str,
|
|
35
|
+
*,
|
|
36
|
+
theme: str = "theme_a",
|
|
37
|
+
profile: str = "starter",
|
|
38
|
+
content_path: str | None = None,
|
|
39
|
+
no_git: bool = False,
|
|
40
|
+
skip_systemd: bool = False,
|
|
41
|
+
skip_caddy: bool = False,
|
|
42
|
+
superuser_username: str = "admin",
|
|
43
|
+
) -> int:
|
|
44
|
+
"""Initialize a new site on staging.
|
|
45
|
+
|
|
46
|
+
Creates a fully working site at /srv/sum/<name>/ with all infrastructure
|
|
47
|
+
configured and ready to serve traffic.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
site_name: Name/slug for the site.
|
|
51
|
+
theme: Theme slug to use.
|
|
52
|
+
profile: Content profile name to seed.
|
|
53
|
+
content_path: Optional path to custom content directory.
|
|
54
|
+
no_git: Skip GitHub repository creation.
|
|
55
|
+
skip_systemd: Skip systemd service installation.
|
|
56
|
+
skip_caddy: Skip Caddy configuration.
|
|
57
|
+
superuser_username: Username for Django superuser.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Exit code (0 for success, non-zero for failure).
|
|
61
|
+
"""
|
|
62
|
+
# Validate site name
|
|
63
|
+
try:
|
|
64
|
+
naming = validate_project_name(site_name)
|
|
65
|
+
except ValueError as exc:
|
|
66
|
+
OutputFormatter.error(str(exc))
|
|
67
|
+
return 1
|
|
68
|
+
|
|
69
|
+
site_slug = naming.slug
|
|
70
|
+
|
|
71
|
+
# Check infrastructure prerequisites
|
|
72
|
+
infra = check_infrastructure()
|
|
73
|
+
if not infra.has_sudo:
|
|
74
|
+
OutputFormatter.error(
|
|
75
|
+
"This command requires root privileges.\n"
|
|
76
|
+
"Run with: sudo sum-platform init ..."
|
|
77
|
+
)
|
|
78
|
+
return 1
|
|
79
|
+
|
|
80
|
+
if infra.errors:
|
|
81
|
+
OutputFormatter.error("Infrastructure prerequisites not met:")
|
|
82
|
+
for error in infra.errors:
|
|
83
|
+
OutputFormatter.error(f" - {error}")
|
|
84
|
+
return 1
|
|
85
|
+
|
|
86
|
+
# Load system config
|
|
87
|
+
try:
|
|
88
|
+
config = get_system_config()
|
|
89
|
+
except ConfigurationError as exc:
|
|
90
|
+
OutputFormatter.error(str(exc))
|
|
91
|
+
return 1
|
|
92
|
+
|
|
93
|
+
# Check if site already exists
|
|
94
|
+
site_dir = config.get_site_dir(site_slug)
|
|
95
|
+
if site_dir.exists():
|
|
96
|
+
OutputFormatter.error(f"Site already exists at {site_dir}")
|
|
97
|
+
return 1
|
|
98
|
+
|
|
99
|
+
# Warn about GitHub if gh CLI not available and --no-git not set
|
|
100
|
+
if not no_git and not infra.has_gh_cli:
|
|
101
|
+
OutputFormatter.warning(
|
|
102
|
+
"GitHub CLI (gh) not available. Repository creation will be skipped.\n"
|
|
103
|
+
"To enable: install gh CLI and run 'gh auth login'"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Build setup config
|
|
107
|
+
setup_config = SiteSetupConfig(
|
|
108
|
+
site_slug=site_slug,
|
|
109
|
+
theme_slug=theme,
|
|
110
|
+
seed_profile=profile,
|
|
111
|
+
content_path=content_path,
|
|
112
|
+
superuser_username=superuser_username,
|
|
113
|
+
skip_git=no_git,
|
|
114
|
+
skip_systemd=skip_systemd,
|
|
115
|
+
skip_caddy=skip_caddy,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Run setup
|
|
119
|
+
OutputFormatter.header(f"Creating site: {site_slug}")
|
|
120
|
+
print()
|
|
121
|
+
|
|
122
|
+
orchestrator = SiteOrchestrator(config)
|
|
123
|
+
try:
|
|
124
|
+
result = orchestrator.setup_site(setup_config)
|
|
125
|
+
except SetupError as exc:
|
|
126
|
+
OutputFormatter.error(str(exc))
|
|
127
|
+
return 1
|
|
128
|
+
|
|
129
|
+
# Output summary
|
|
130
|
+
print()
|
|
131
|
+
OutputFormatter.success("Site created successfully!")
|
|
132
|
+
print()
|
|
133
|
+
print(f" URL: https://{result.domain}")
|
|
134
|
+
print(f" Admin: {result.admin_url}")
|
|
135
|
+
print(f" Username: {result.superuser_username}")
|
|
136
|
+
# Intentional: Display generated password to user (also saved to credentials file)
|
|
137
|
+
print(f" Password: {result.superuser_password}") # nosec B105
|
|
138
|
+
print()
|
|
139
|
+
print(f" Site dir: {result.site_dir}")
|
|
140
|
+
print(f" App dir: {result.app_dir}")
|
|
141
|
+
if result.repo_url:
|
|
142
|
+
print(f" Repository: {result.repo_url}")
|
|
143
|
+
print()
|
|
144
|
+
print(f" Credentials saved to: {result.credentials_path}")
|
|
145
|
+
print()
|
|
146
|
+
|
|
147
|
+
return 0
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _init_command(
|
|
151
|
+
site_name: str,
|
|
152
|
+
theme: str,
|
|
153
|
+
profile: str,
|
|
154
|
+
content_path: str | None,
|
|
155
|
+
no_git: bool,
|
|
156
|
+
skip_systemd: bool,
|
|
157
|
+
skip_caddy: bool,
|
|
158
|
+
superuser_username: str,
|
|
159
|
+
) -> None:
|
|
160
|
+
"""Initialize a new site on staging."""
|
|
161
|
+
result = run_init(
|
|
162
|
+
site_name,
|
|
163
|
+
theme=theme,
|
|
164
|
+
profile=profile,
|
|
165
|
+
content_path=content_path,
|
|
166
|
+
no_git=no_git,
|
|
167
|
+
skip_systemd=skip_systemd,
|
|
168
|
+
skip_caddy=skip_caddy,
|
|
169
|
+
superuser_username=superuser_username,
|
|
170
|
+
)
|
|
171
|
+
if result != 0:
|
|
172
|
+
raise SystemExit(result)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _missing_click(*_args: object, **_kwargs: object) -> None:
|
|
176
|
+
raise RuntimeError("click is required to use the init command")
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
if click is None:
|
|
180
|
+
init = _missing_click
|
|
181
|
+
else:
|
|
182
|
+
|
|
183
|
+
@click.command(name="init")
|
|
184
|
+
@click.argument("site_name")
|
|
185
|
+
@click.option(
|
|
186
|
+
"--theme",
|
|
187
|
+
default="theme_a",
|
|
188
|
+
show_default=True,
|
|
189
|
+
help="Theme slug to use for the site.",
|
|
190
|
+
)
|
|
191
|
+
@click.option(
|
|
192
|
+
"--profile",
|
|
193
|
+
default="starter",
|
|
194
|
+
show_default=True,
|
|
195
|
+
help="Content profile to seed (e.g., starter, sage-stone).",
|
|
196
|
+
)
|
|
197
|
+
@click.option(
|
|
198
|
+
"--content-path",
|
|
199
|
+
default=None,
|
|
200
|
+
help="Path to custom content directory for seeding.",
|
|
201
|
+
)
|
|
202
|
+
@click.option(
|
|
203
|
+
"--no-git",
|
|
204
|
+
is_flag=True,
|
|
205
|
+
help="Skip GitHub repository creation (git init only).",
|
|
206
|
+
)
|
|
207
|
+
@click.option(
|
|
208
|
+
"--skip-systemd",
|
|
209
|
+
is_flag=True,
|
|
210
|
+
help="Skip systemd service installation.",
|
|
211
|
+
)
|
|
212
|
+
@click.option(
|
|
213
|
+
"--skip-caddy",
|
|
214
|
+
is_flag=True,
|
|
215
|
+
help="Skip Caddy reverse proxy configuration.",
|
|
216
|
+
)
|
|
217
|
+
@click.option(
|
|
218
|
+
"--superuser",
|
|
219
|
+
"superuser_username",
|
|
220
|
+
default="admin",
|
|
221
|
+
show_default=True,
|
|
222
|
+
help="Username for Django superuser.",
|
|
223
|
+
)
|
|
224
|
+
def _click_init(
|
|
225
|
+
site_name: str,
|
|
226
|
+
theme: str,
|
|
227
|
+
profile: str,
|
|
228
|
+
content_path: str | None,
|
|
229
|
+
no_git: bool,
|
|
230
|
+
skip_systemd: bool,
|
|
231
|
+
skip_caddy: bool,
|
|
232
|
+
superuser_username: str,
|
|
233
|
+
) -> None:
|
|
234
|
+
"""Initialize a new site on staging.
|
|
235
|
+
|
|
236
|
+
Creates a working site at /srv/sum/<SITE_NAME>/ with:
|
|
237
|
+
|
|
238
|
+
\b
|
|
239
|
+
- PostgreSQL database
|
|
240
|
+
- Django project with selected theme
|
|
241
|
+
- External virtualenv
|
|
242
|
+
- Systemd service
|
|
243
|
+
- Caddy reverse proxy
|
|
244
|
+
- GitHub repository (optional)
|
|
245
|
+
|
|
246
|
+
The site will be accessible at https://<SITE_NAME>.lintel.site
|
|
247
|
+
|
|
248
|
+
\b
|
|
249
|
+
Examples:
|
|
250
|
+
sudo sum-platform init acme
|
|
251
|
+
sudo sum-platform init acme --theme theme_b
|
|
252
|
+
sudo sum-platform init acme --content-path /path/to/profiles/acme
|
|
253
|
+
"""
|
|
254
|
+
_init_command(
|
|
255
|
+
site_name,
|
|
256
|
+
theme=theme,
|
|
257
|
+
profile=profile,
|
|
258
|
+
content_path=content_path,
|
|
259
|
+
no_git=no_git,
|
|
260
|
+
skip_systemd=skip_systemd,
|
|
261
|
+
skip_caddy=skip_caddy,
|
|
262
|
+
superuser_username=superuser_username,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
init = _click_init
|