djaploy 0.9.1__tar.gz → 0.9.3__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.
- {djaploy-0.9.1 → djaploy-0.9.3}/PKG-INFO +1 -1
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/config.py +11 -6
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/core.py +53 -28
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy.egg-info/PKG-INFO +1 -1
- {djaploy-0.9.1 → djaploy-0.9.3}/pyproject.toml +1 -1
- {djaploy-0.9.1 → djaploy-0.9.3}/LICENSE +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/README.md +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/__init__.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/artifact.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/bin/__init__.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/bin/django_pyinfra.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/certificates.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/changelog.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/deploy.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/management/__init__.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/management/commands/__init__.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/management/commands/configureserver.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/management/commands/deploy.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/management/commands/rollback.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/management/commands/sync_certs.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/management/commands/update_certs.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/management/commands/verify.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/management/utils.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/__init__.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/base.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/cert_renewal.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/litestream.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/loader.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/nginx.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/rclone.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/sync_certs.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/systemd.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/tailscale.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/modules/versioning.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/notifications.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/utils.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/version.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy/versioning.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy.egg-info/SOURCES.txt +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy.egg-info/dependency_links.txt +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy.egg-info/entry_points.txt +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy.egg-info/requires.txt +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/djaploy.egg-info/top_level.txt +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/setup.cfg +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/tests/test_config.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/tests/test_core_module.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/tests/test_deploy_scripts.py +0 -0
- {djaploy-0.9.1 → djaploy-0.9.3}/tests/test_systemd_module.py +0 -0
|
@@ -71,7 +71,7 @@ class DjaployConfig:
|
|
|
71
71
|
artifact_dir: str = "deployment"
|
|
72
72
|
deployment_strategy: str = "in_place" # "in_place" or "zero_downtime"
|
|
73
73
|
keep_releases: int = 5 # Number of releases to keep (zero_downtime only)
|
|
74
|
-
# Paths (relative to
|
|
74
|
+
# Paths (relative to git/artifact root) to symlink from shared/ into each release.
|
|
75
75
|
# When None (default), auto-detected from Django settings (STATIC_ROOT,
|
|
76
76
|
# MEDIA_ROOT, PRIVATE_MEDIA_ROOT). Set explicitly to override or to [] to disable.
|
|
77
77
|
# Note: venv is shared implicitly via the stable current/ symlink path.
|
|
@@ -118,8 +118,8 @@ class DjaployConfig:
|
|
|
118
118
|
"""Auto-detect shared resources from Django settings.
|
|
119
119
|
|
|
120
120
|
Resolves STATIC_ROOT, MEDIA_ROOT and PRIVATE_MEDIA_ROOT relative to
|
|
121
|
-
|
|
122
|
-
(paths outside
|
|
121
|
+
git_dir (the artifact/release root). Only includes paths that are
|
|
122
|
+
inside the project directory (paths outside don't need symlinking).
|
|
123
123
|
"""
|
|
124
124
|
resources = []
|
|
125
125
|
try:
|
|
@@ -127,17 +127,22 @@ class DjaployConfig:
|
|
|
127
127
|
if not django_settings.configured:
|
|
128
128
|
return resources
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
# Resolve relative to git_dir (artifact root) so paths match
|
|
131
|
+
# the release directory structure, not BASE_DIR which may be
|
|
132
|
+
# a subdirectory of the artifact.
|
|
133
|
+
artifact_root = self.git_dir or self.project_dir
|
|
134
|
+
if artifact_root is None:
|
|
135
|
+
return resources
|
|
131
136
|
|
|
132
137
|
for setting_name in ('STATIC_ROOT', 'MEDIA_ROOT', 'PRIVATE_MEDIA_ROOT'):
|
|
133
138
|
value = getattr(django_settings, setting_name, None)
|
|
134
139
|
if value:
|
|
135
140
|
abs_path = Path(value)
|
|
136
141
|
try:
|
|
137
|
-
rel = str(abs_path.relative_to(
|
|
142
|
+
rel = str(abs_path.relative_to(artifact_root))
|
|
138
143
|
resources.append(rel)
|
|
139
144
|
except ValueError:
|
|
140
|
-
pass # Outside
|
|
145
|
+
pass # Outside artifact root, no symlink needed
|
|
141
146
|
except Exception:
|
|
142
147
|
pass
|
|
143
148
|
return resources
|
|
@@ -136,15 +136,19 @@ class CoreModule(BaseModule):
|
|
|
136
136
|
_sudo=True,
|
|
137
137
|
)
|
|
138
138
|
|
|
139
|
-
# Create shared resource directories
|
|
139
|
+
# Create shared resource directories (mkdir -p for nested paths)
|
|
140
140
|
shared_resources = getattr(project_config, 'shared_resources', [])
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
141
|
+
if shared_resources:
|
|
142
|
+
mkdir_commands = [
|
|
143
|
+
f"mkdir -p {app_path}/shared/{resource}"
|
|
144
|
+
for resource in shared_resources
|
|
145
|
+
if not resource.startswith('.')
|
|
146
|
+
]
|
|
147
|
+
if mkdir_commands:
|
|
148
|
+
mkdir_commands.append(f"chown -R {app_user}:{app_user} {app_path}/shared")
|
|
149
|
+
server.shell(
|
|
150
|
+
name="Create shared resource directories",
|
|
151
|
+
commands=mkdir_commands,
|
|
148
152
|
_sudo=True,
|
|
149
153
|
)
|
|
150
154
|
|
|
@@ -259,13 +263,35 @@ class CoreModule(BaseModule):
|
|
|
259
263
|
def post_deploy(self, host_data: Dict[str, Any], project_config: Dict[str, Any], artifact_path: Path):
|
|
260
264
|
"""Run migrations and collectstatic after all modules have deployed their files"""
|
|
261
265
|
app_user = getattr(host_data, 'app_user', None) or project_config.app_user
|
|
266
|
+
|
|
262
267
|
if self._is_zero_downtime(project_config):
|
|
263
|
-
|
|
268
|
+
# Run migrations and collectstatic via the stable build/ symlink
|
|
269
|
+
# so Poetry resolves the same virtualenv used during install.
|
|
270
|
+
# Old workers keep serving from current/ without interruption.
|
|
271
|
+
base_path = self._get_app_path(host_data, project_config)
|
|
272
|
+
build_path = f"{base_path}/build"
|
|
273
|
+
release_path = getattr(host.data, '_zero_downtime_release_path', None)
|
|
274
|
+
app_path = build_path if release_path else f"{base_path}/current"
|
|
275
|
+
|
|
276
|
+
self._run_migrations(app_user, app_path, project_config)
|
|
277
|
+
self._collect_static(app_user, app_path, project_config)
|
|
278
|
+
|
|
279
|
+
# Atomic symlink swap AFTER everything is ready.
|
|
280
|
+
# Old workers continue serving until USR2 triggers the handoff.
|
|
281
|
+
if release_path:
|
|
282
|
+
server.shell(
|
|
283
|
+
name="Swap current symlink to new release",
|
|
284
|
+
commands=[
|
|
285
|
+
f"ln -sfn {release_path} {base_path}/current.tmp && mv -Tf {base_path}/current.tmp {base_path}/current",
|
|
286
|
+
],
|
|
287
|
+
_sudo=True,
|
|
288
|
+
_sudo_user=app_user,
|
|
289
|
+
_use_sudo_login=True,
|
|
290
|
+
)
|
|
264
291
|
else:
|
|
265
292
|
app_path = self._get_app_path(host_data, project_config)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
self._collect_static(app_user, app_path, project_config)
|
|
293
|
+
self._run_migrations(app_user, app_path, project_config)
|
|
294
|
+
self._collect_static(app_user, app_path, project_config)
|
|
269
295
|
|
|
270
296
|
def rollback(self, host_data: Dict[str, Any], project_config: Dict[str, Any], release: str = None):
|
|
271
297
|
"""Roll back to a previous release by swapping the current symlink"""
|
|
@@ -433,27 +459,24 @@ class CoreModule(BaseModule):
|
|
|
433
459
|
if getattr(host_data, 'pregenerate_certificates', False):
|
|
434
460
|
self._generate_ssl_certificates(host_data, app_user)
|
|
435
461
|
|
|
436
|
-
#
|
|
437
|
-
#
|
|
438
|
-
#
|
|
439
|
-
#
|
|
462
|
+
# Install deps via a stable build/ symlink so Poetry reuses the same
|
|
463
|
+
# virtualenv across releases (Poetry keys venvs by directory path).
|
|
464
|
+
# The symlink swap to current/ is deferred to post_deploy so old
|
|
465
|
+
# workers keep serving from the previous release without interruption.
|
|
466
|
+
build_link = f"{app_path}/build"
|
|
440
467
|
server.shell(
|
|
441
|
-
name=
|
|
468
|
+
name="Create stable build symlink for Poetry",
|
|
442
469
|
commands=[
|
|
443
|
-
f"ln -sfn {release_path} {
|
|
470
|
+
f"ln -sfn {release_path} {build_link}",
|
|
444
471
|
],
|
|
445
472
|
_sudo=True,
|
|
446
473
|
_sudo_user=app_user,
|
|
447
474
|
_use_sudo_login=True,
|
|
448
475
|
)
|
|
476
|
+
self._install_dependencies(app_user, build_link, project_config)
|
|
449
477
|
|
|
450
|
-
#
|
|
451
|
-
|
|
452
|
-
# reuses the same venv across deploys (shared venv behavior).
|
|
453
|
-
# Migrations and collectstatic are deferred to post_deploy so that
|
|
454
|
-
# other modules (e.g. local_settings) can place config files first.
|
|
455
|
-
current_path = f"{app_path}/current"
|
|
456
|
-
self._install_dependencies(app_user, current_path, project_config)
|
|
478
|
+
# Store release path so other modules and post_deploy can access it
|
|
479
|
+
host.data._zero_downtime_release_path = release_path
|
|
457
480
|
|
|
458
481
|
# Clean up old releases
|
|
459
482
|
keep_releases = getattr(project_config, 'keep_releases', 5)
|
|
@@ -531,11 +554,13 @@ class CoreModule(BaseModule):
|
|
|
531
554
|
|
|
532
555
|
python_version = project_config.python_version
|
|
533
556
|
|
|
557
|
+
poetry_bin = f"/home/{app_user}/.local/bin/poetry"
|
|
558
|
+
|
|
534
559
|
commands = [
|
|
535
|
-
#
|
|
536
|
-
f"
|
|
560
|
+
# Configure Poetry to not use in-project virtualenvs on the server
|
|
561
|
+
f"{poetry_bin} config virtualenvs.in-project false",
|
|
537
562
|
# Ensure the virtualenv uses the configured Python version
|
|
538
|
-
f"
|
|
563
|
+
f"{poetry_bin} env use python{python_version}",
|
|
539
564
|
]
|
|
540
565
|
|
|
541
566
|
# Optionally regenerate the lock file before installation
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|