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
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Seed the test project using YAML content profiles.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
python manage.py seed starter # Clean production-ready content
|
|
6
|
+
python manage.py seed starter --clear # Clear existing content first
|
|
7
|
+
python manage.py seed sage-stone # Full demo content
|
|
8
|
+
python manage.py seed starter --dry-run
|
|
9
|
+
|
|
10
|
+
The content directory is auto-detected by walking up the directory tree,
|
|
11
|
+
so the command works from subdirectories. The command also attempts to add
|
|
12
|
+
the repository root to ``sys.path`` so the ``seeders`` package is importable.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
from django.core.management.base import BaseCommand, CommandError, CommandParser
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _ensure_repo_root_on_path() -> None:
|
|
24
|
+
"""Add the repo root (containing seeders/content) to sys.path if needed."""
|
|
25
|
+
for parent in Path(__file__).resolve().parents:
|
|
26
|
+
if (parent / "seeders").is_dir() and (parent / "content").is_dir():
|
|
27
|
+
sys.path.insert(0, str(parent))
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
_ensure_repo_root_on_path()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
from seeders import SeedOrchestrator, SeedPlan
|
|
36
|
+
from seeders.exceptions import SeederError
|
|
37
|
+
except ImportError as _import_err:
|
|
38
|
+
# Provide a helpful error message when seeders cannot be imported
|
|
39
|
+
_IMPORT_ERROR_MSG = (
|
|
40
|
+
"Cannot import 'seeders' package. This typically happens when running "
|
|
41
|
+
"the seed command from a subdirectory.\n\n"
|
|
42
|
+
"Solutions:\n"
|
|
43
|
+
" 1. Run from the repository root:\n"
|
|
44
|
+
" python core/sum_core/test_project/manage.py seed <profile>\n\n"
|
|
45
|
+
" 2. Use the Makefile target:\n"
|
|
46
|
+
" make seed\n\n"
|
|
47
|
+
" 3. Set PYTHONPATH to include the repo root:\n"
|
|
48
|
+
" PYTHONPATH=. python manage.py seed <profile>\n"
|
|
49
|
+
)
|
|
50
|
+
raise ImportError(_IMPORT_ERROR_MSG) from _import_err
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Command(BaseCommand):
|
|
54
|
+
help = "Seed the test project from YAML content profiles."
|
|
55
|
+
|
|
56
|
+
def add_arguments(self, parser: CommandParser) -> None:
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"profile",
|
|
59
|
+
nargs="?",
|
|
60
|
+
help="Content profile to seed (e.g., starter, sage-stone).",
|
|
61
|
+
)
|
|
62
|
+
parser.add_argument(
|
|
63
|
+
"--clear",
|
|
64
|
+
action="store_true",
|
|
65
|
+
help="Clear existing seeded content before re-seeding.",
|
|
66
|
+
)
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"--content-path",
|
|
69
|
+
default=None,
|
|
70
|
+
help="Override the content directory (defaults to ./content).",
|
|
71
|
+
)
|
|
72
|
+
parser.add_argument(
|
|
73
|
+
"--dry-run",
|
|
74
|
+
action="store_true",
|
|
75
|
+
help="Validate content and print the plan without writing.",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def handle(self, *args, **options) -> None:
|
|
79
|
+
content_path = options.get("content_path")
|
|
80
|
+
content_dir = Path(content_path).expanduser() if content_path else None
|
|
81
|
+
orchestrator = SeedOrchestrator(content_dir=content_dir)
|
|
82
|
+
|
|
83
|
+
profile = options.get("profile") or self._default_profile(orchestrator)
|
|
84
|
+
if not profile:
|
|
85
|
+
profiles = orchestrator.list_profiles()
|
|
86
|
+
if profiles:
|
|
87
|
+
raise CommandError(
|
|
88
|
+
"Missing profile. Available profiles: " + ", ".join(profiles)
|
|
89
|
+
)
|
|
90
|
+
raise CommandError("Missing profile and no content profiles were found.")
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
if options.get("dry_run"):
|
|
94
|
+
plan = orchestrator.plan(profile)
|
|
95
|
+
self._print_plan(plan)
|
|
96
|
+
return
|
|
97
|
+
orchestrator.seed(profile, clear=options.get("clear", False))
|
|
98
|
+
except SeederError as exc:
|
|
99
|
+
raise CommandError(str(exc)) from exc
|
|
100
|
+
|
|
101
|
+
self.stdout.write(self.style.SUCCESS(f"Seeded profile '{profile}'."))
|
|
102
|
+
|
|
103
|
+
def _default_profile(self, orchestrator: SeedOrchestrator) -> str | None:
|
|
104
|
+
"""Return a sensible default profile, if one can be inferred.
|
|
105
|
+
|
|
106
|
+
The test project ships with sample profiles. ``starter`` is the clean
|
|
107
|
+
production-ready default; ``sage-stone`` is a full demo profile.
|
|
108
|
+
"""
|
|
109
|
+
profiles = orchestrator.list_profiles()
|
|
110
|
+
if "starter" in profiles:
|
|
111
|
+
return "starter"
|
|
112
|
+
if "sage-stone" in profiles:
|
|
113
|
+
return "sage-stone"
|
|
114
|
+
if len(profiles) == 1:
|
|
115
|
+
return profiles[0]
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
def _print_plan(self, plan: SeedPlan) -> None:
|
|
119
|
+
self.stdout.write(self.style.MIGRATE_HEADING("Seed plan"))
|
|
120
|
+
self.stdout.write(self.style.NOTICE(f" Profile: {plan.profile}"))
|
|
121
|
+
self.stdout.write(self.style.NOTICE(f" Content dir: {plan.content_dir}"))
|
|
122
|
+
if plan.pages:
|
|
123
|
+
self.stdout.write(self.style.SUCCESS(" Pages:"))
|
|
124
|
+
for page in plan.pages:
|
|
125
|
+
self.stdout.write(f" - {page}")
|
|
126
|
+
if plan.seeders:
|
|
127
|
+
self.stdout.write(self.style.SUCCESS(" Seeders:"))
|
|
128
|
+
for seeder in plan.seeders:
|
|
129
|
+
self.stdout.write(f" - {seeder}")
|