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.
Files changed (72) hide show
  1. sum/__init__.py +1 -0
  2. sum/boilerplate/.env.example +124 -0
  3. sum/boilerplate/.gitea/workflows/ci.yml +33 -0
  4. sum/boilerplate/.gitea/workflows/deploy-production.yml +98 -0
  5. sum/boilerplate/.gitea/workflows/deploy-staging.yml +113 -0
  6. sum/boilerplate/.github/workflows/ci.yml +36 -0
  7. sum/boilerplate/.github/workflows/deploy-production.yml +102 -0
  8. sum/boilerplate/.github/workflows/deploy-staging.yml +115 -0
  9. sum/boilerplate/.gitignore +45 -0
  10. sum/boilerplate/README.md +259 -0
  11. sum/boilerplate/manage.py +34 -0
  12. sum/boilerplate/project_name/__init__.py +5 -0
  13. sum/boilerplate/project_name/home/__init__.py +5 -0
  14. sum/boilerplate/project_name/home/apps.py +20 -0
  15. sum/boilerplate/project_name/home/management/__init__.py +0 -0
  16. sum/boilerplate/project_name/home/management/commands/__init__.py +0 -0
  17. sum/boilerplate/project_name/home/management/commands/populate_demo_content.py +644 -0
  18. sum/boilerplate/project_name/home/management/commands/seed.py +129 -0
  19. sum/boilerplate/project_name/home/management/commands/seed_showroom.py +1661 -0
  20. sum/boilerplate/project_name/home/migrations/__init__.py +3 -0
  21. sum/boilerplate/project_name/home/models.py +13 -0
  22. sum/boilerplate/project_name/settings/__init__.py +5 -0
  23. sum/boilerplate/project_name/settings/base.py +348 -0
  24. sum/boilerplate/project_name/settings/local.py +78 -0
  25. sum/boilerplate/project_name/settings/production.py +106 -0
  26. sum/boilerplate/project_name/urls.py +33 -0
  27. sum/boilerplate/project_name/wsgi.py +16 -0
  28. sum/boilerplate/pytest.ini +5 -0
  29. sum/boilerplate/requirements.txt +25 -0
  30. sum/boilerplate/static/client/.gitkeep +3 -0
  31. sum/boilerplate/templates/overrides/.gitkeep +3 -0
  32. sum/boilerplate/tests/__init__.py +3 -0
  33. sum/boilerplate/tests/test_health.py +51 -0
  34. sum/cli.py +42 -0
  35. sum/commands/__init__.py +10 -0
  36. sum/commands/backup.py +308 -0
  37. sum/commands/check.py +128 -0
  38. sum/commands/init.py +265 -0
  39. sum/commands/promote.py +758 -0
  40. sum/commands/run.py +96 -0
  41. sum/commands/themes.py +56 -0
  42. sum/commands/update.py +301 -0
  43. sum/config.py +61 -0
  44. sum/docs/USER_GUIDE.md +663 -0
  45. sum/exceptions.py +45 -0
  46. sum/setup/__init__.py +17 -0
  47. sum/setup/auth.py +184 -0
  48. sum/setup/database.py +58 -0
  49. sum/setup/deps.py +73 -0
  50. sum/setup/git_ops.py +463 -0
  51. sum/setup/infrastructure.py +576 -0
  52. sum/setup/orchestrator.py +354 -0
  53. sum/setup/remote_themes.py +371 -0
  54. sum/setup/scaffold.py +500 -0
  55. sum/setup/seed.py +110 -0
  56. sum/setup/site_orchestrator.py +441 -0
  57. sum/setup/venv.py +89 -0
  58. sum/system_config.py +330 -0
  59. sum/themes_registry.py +180 -0
  60. sum/utils/__init__.py +25 -0
  61. sum/utils/django.py +97 -0
  62. sum/utils/environment.py +76 -0
  63. sum/utils/output.py +78 -0
  64. sum/utils/project.py +110 -0
  65. sum/utils/prompts.py +36 -0
  66. sum/utils/validation.py +313 -0
  67. sum_cli-3.0.0.dist-info/METADATA +127 -0
  68. sum_cli-3.0.0.dist-info/RECORD +72 -0
  69. sum_cli-3.0.0.dist-info/WHEEL +5 -0
  70. sum_cli-3.0.0.dist-info/entry_points.txt +2 -0
  71. sum_cli-3.0.0.dist-info/licenses/LICENSE +29 -0
  72. 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