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
@@ -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}")