djaploy 1.2.1__tar.gz → 1.2.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.
Files changed (92) hide show
  1. {djaploy-1.2.1 → djaploy-1.2.3}/PKG-INFO +1 -1
  2. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/builtin_hooks.py +13 -0
  3. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/commands/deploy.py +3 -1
  4. djaploy-1.2.3/djaploy/commands/status.py +88 -0
  5. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/infra/djaploy_hooks.py +3 -0
  6. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy.egg-info/PKG-INFO +1 -1
  7. {djaploy-1.2.1 → djaploy-1.2.3}/pyproject.toml +1 -1
  8. djaploy-1.2.1/djaploy/commands/status.py +0 -62
  9. {djaploy-1.2.1 → djaploy-1.2.3}/LICENSE +0 -0
  10. {djaploy-1.2.1 → djaploy-1.2.3}/README.md +0 -0
  11. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/__init__.py +0 -0
  12. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/app.py +0 -0
  13. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/__init__.py +0 -0
  14. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/borg/__init__.py +0 -0
  15. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/borg/infra/__init__.py +0 -0
  16. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/borg/infra/djaploy_hooks.py +0 -0
  17. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/janitor/__init__.py +0 -0
  18. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/janitor/apps.py +0 -0
  19. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/janitor/infra/__init__.py +0 -0
  20. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/janitor/infra/commands/createjanitoruser.py +0 -0
  21. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/janitor/infra/djaploy_hooks.py +0 -0
  22. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/nginx/__init__.py +0 -0
  23. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/nginx/apps.py +0 -0
  24. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/nginx/infra/__init__.py +0 -0
  25. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/nginx/infra/djaploy_hooks.py +0 -0
  26. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/rclone/__init__.py +0 -0
  27. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/rclone/apps.py +0 -0
  28. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/rclone/infra/__init__.py +0 -0
  29. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/rclone/infra/djaploy_hooks.py +0 -0
  30. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/sync_certs/__init__.py +0 -0
  31. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/sync_certs/apps.py +0 -0
  32. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/sync_certs/infra/__init__.py +0 -0
  33. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/sync_certs/infra/djaploy_hooks.py +0 -0
  34. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/systemd/__init__.py +0 -0
  35. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/systemd/apps.py +0 -0
  36. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/systemd/infra/__init__.py +0 -0
  37. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/systemd/infra/djaploy_hooks.py +0 -0
  38. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/tailscale/__init__.py +0 -0
  39. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/tailscale/apps.py +0 -0
  40. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/tailscale/infra/__init__.py +0 -0
  41. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/tailscale/infra/djaploy_hooks.py +0 -0
  42. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/versioning/__init__.py +0 -0
  43. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/versioning/apps.py +0 -0
  44. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/versioning/infra/__init__.py +0 -0
  45. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/apps/versioning/infra/djaploy_hooks.py +0 -0
  46. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/artifact.py +0 -0
  47. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/bin/__init__.py +0 -0
  48. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/bin/django_pyinfra.py +0 -0
  49. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/bin/gunicornherder.py +0 -0
  50. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/certificates.py +0 -0
  51. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/changelog.py +0 -0
  52. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/commands/__init__.py +0 -0
  53. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/commands/_utils.py +0 -0
  54. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/commands/activate.py +0 -0
  55. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/commands/configure.py +0 -0
  56. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/commands/restore.py +0 -0
  57. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/commands/rollback.py +0 -0
  58. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/commands/sync_certs.py +0 -0
  59. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/config.py +0 -0
  60. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/deploy.py +0 -0
  61. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/discovery.py +0 -0
  62. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/hooks.py +0 -0
  63. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/infra/__init__.py +0 -0
  64. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/infra/bluegreen.py +0 -0
  65. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/infra/templates.py +0 -0
  66. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/infra/utils.py +0 -0
  67. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/management/__init__.py +0 -0
  68. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/management/commands/__init__.py +0 -0
  69. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/management/commands/djaploy.py +0 -0
  70. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/management/commands/restore_backup.py +0 -0
  71. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/management/commands/sync_certs.py +0 -0
  72. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/management/commands/update_certs.py +0 -0
  73. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/management/commands/verify.py +0 -0
  74. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/management/utils.py +0 -0
  75. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/notifications.py +0 -0
  76. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/utils.py +0 -0
  77. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/version.py +0 -0
  78. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy/versioning.py +0 -0
  79. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy.egg-info/SOURCES.txt +0 -0
  80. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy.egg-info/dependency_links.txt +0 -0
  81. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy.egg-info/entry_points.txt +0 -0
  82. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy.egg-info/requires.txt +0 -0
  83. {djaploy-1.2.1 → djaploy-1.2.3}/djaploy.egg-info/top_level.txt +0 -0
  84. {djaploy-1.2.1 → djaploy-1.2.3}/setup.cfg +0 -0
  85. {djaploy-1.2.1 → djaploy-1.2.3}/tests/test_bluegreen.py +0 -0
  86. {djaploy-1.2.1 → djaploy-1.2.3}/tests/test_borg.py +0 -0
  87. {djaploy-1.2.1 → djaploy-1.2.3}/tests/test_config.py +0 -0
  88. {djaploy-1.2.1 → djaploy-1.2.3}/tests/test_deploy_scripts.py +0 -0
  89. {djaploy-1.2.1 → djaploy-1.2.3}/tests/test_discovery.py +0 -0
  90. {djaploy-1.2.1 → djaploy-1.2.3}/tests/test_gunicornherder.py +0 -0
  91. {djaploy-1.2.1 → djaploy-1.2.3}/tests/test_hooks.py +0 -0
  92. {djaploy-1.2.1 → djaploy-1.2.3}/tests/test_versioning.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: djaploy
3
- Version: 1.2.1
3
+ Version: 1.2.3
4
4
  Summary: Modular Django deployment system based on pyinfra
5
5
  Author-email: Johanna Mae Dimayuga <johanna@techco.fi>
6
6
  License: MIT License
@@ -103,6 +103,19 @@ def _deploy_calculate_release_info(context):
103
103
  if release_info:
104
104
  context["pyinfra_data"]["version"] = release_info["new_version"]
105
105
  context["pyinfra_data"]["commit"] = release_info["commit"]
106
+ elif "commit" not in context["pyinfra_data"]:
107
+ # Always pass commit hash even without versioning configured
108
+ try:
109
+ import subprocess
110
+ from django.conf import settings
111
+ commit = subprocess.check_output(
112
+ ["git", "rev-parse", "--short", "HEAD"],
113
+ cwd=str(settings.GIT_DIR),
114
+ text=True,
115
+ ).strip()
116
+ context["pyinfra_data"]["commit"] = commit
117
+ except Exception:
118
+ pass
106
119
 
107
120
 
108
121
  # ── deploy:postcommand ───────────────────────────────────────────────
@@ -34,7 +34,9 @@ for phase in ("deploy:upload", "deploy:configure", "deploy:pre", "deploy:start")
34
34
  _activate_val = getattr(host.data, "activate", None)
35
35
  if _activate_val in (True, "true", "True"):
36
36
  for phase in ("activate:pre", "activate", "activate:post"):
37
- for hook in registry.get_remote_hooks(phase):
37
+ _hooks = registry.get_remote_hooks(phase)
38
+ print(f"[activate] phase={phase} hooks={[h.function.__name__ for h in _hooks]}")
39
+ for hook in _hooks:
38
40
  _deploy_decorator(hook.function.__name__)(hook.function)(
39
41
  host.data
40
42
  )
@@ -0,0 +1,88 @@
1
+ """
2
+ Pyinfra command: show blue-green deployment status.
3
+
4
+ Reads and displays the blue-green state from each host.
5
+
6
+ Usage (via djaploy management command):
7
+ manage.py djaploy status --env production
8
+ """
9
+
10
+ from pyinfra import host
11
+ from pyinfra.api import deploy as _deploy_decorator
12
+ from pyinfra.operations import python as python_op
13
+
14
+ from djaploy.hooks import discover_hooks, get_registry
15
+ from djaploy.infra.utils import is_bluegreen, get_app_path, get_slot_socket_path
16
+ from djaploy.infra.djaploy_hooks import _read_slot_info_from_remote
17
+
18
+ discover_hooks()
19
+ registry = get_registry()
20
+
21
+ if is_bluegreen(host.data):
22
+ app_name = getattr(host.data, 'app_name', 'unknown')
23
+ app_path = get_app_path(host.data)
24
+ state_file = f"{app_path}/state.json"
25
+
26
+ def _show_status(app_n, state_f):
27
+ blue_info = _read_slot_info_from_remote(host, "blue", state_f)
28
+ green_info = _read_slot_info_from_remote(host, "green", state_f)
29
+
30
+ # Read active slot
31
+ import json
32
+ result = host.run_shell_command(command=f"cat {state_f}")
33
+ active = "none"
34
+ if result[0] and len(result) > 1:
35
+ try:
36
+ lines = [l.line if hasattr(l, 'line') else str(l) for l in result[1]]
37
+ state_data = json.loads("\n".join(lines))
38
+ active = state_data.get("active_slot") or "none"
39
+ except (json.JSONDecodeError, KeyError):
40
+ pass
41
+
42
+ print(f"\nBlue-Green Status for {app_n}")
43
+ print("=" * 40)
44
+ print(f"Active slot: {active}\n")
45
+
46
+ for slot, info in [("blue", blue_info), ("green", green_info)]:
47
+ tag = "ACTIVE" if active == slot else "inactive"
48
+ print(f"{slot.upper()} ({tag}):")
49
+ if info:
50
+ print(f" Release: {info.get('release', 'unknown')}")
51
+ print(f" Commit: {info.get('commit', 'unknown')}")
52
+ print(f" Deployed at: {info.get('deployed_at', 'unknown')}")
53
+ print(f" Python: {info.get('python_interpreter', 'unknown')}")
54
+ print(f" Venv: {info.get('venv_path', 'unknown')}")
55
+ print(f" Socket: {get_slot_socket_path(app_n, slot)}")
56
+ else:
57
+ print(" (empty)")
58
+ print()
59
+
60
+ # Show service status
61
+ for slot in ("blue", "green"):
62
+ svc = f"{app_n}-{slot}.service"
63
+ res = host.run_shell_command(command=f"systemctl is-active {svc} 2>/dev/null || echo inactive")
64
+ status_str = "unknown"
65
+ if res[0] and len(res) > 1:
66
+ try:
67
+ status_str = (list(res[1])[0].line if hasattr(list(res[1])[0], 'line') else str(list(res[1])[0])).strip()
68
+ except (IndexError, AttributeError):
69
+ pass
70
+ print(f"Service {svc}: {status_str}")
71
+ print()
72
+
73
+ python_op.call(
74
+ name="Show blue-green status",
75
+ function=_show_status,
76
+ app_n=app_name,
77
+ state_f=state_file,
78
+ )
79
+ else:
80
+ def _show_non_bluegreen():
81
+ strategy = getattr(host.data, "deployment_strategy", "zero_downtime")
82
+ print(f"\nDeployment strategy: {strategy}")
83
+ print("Not a blue-green deployment. Use deploy/rollback commands.\n")
84
+
85
+ python_op.call(
86
+ name="Show deployment status",
87
+ function=_show_non_bluegreen,
88
+ )
@@ -854,6 +854,9 @@ def activate_bluegreen(host_data):
854
854
  )
855
855
  return
856
856
 
857
+ # Store on host.data so activate:post hooks can read it
858
+ host.data._bluegreen_activated_slot = target_slot
859
+
857
860
  # Update nginx upstream config to point to target slot
858
861
  from io import StringIO
859
862
  from djaploy.infra.templates import NGINX_UPSTREAM_BLUEGREEN, build_template_context
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: djaploy
3
- Version: 1.2.1
3
+ Version: 1.2.3
4
4
  Summary: Modular Django deployment system based on pyinfra
5
5
  Author-email: Johanna Mae Dimayuga <johanna@techco.fi>
6
6
  License: MIT License
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "djaploy"
3
- version = "1.2.1"
3
+ version = "1.2.3"
4
4
  description = "Modular Django deployment system based on pyinfra"
5
5
  authors = [
6
6
  {name = "Johanna Mae Dimayuga", email = "johanna@techco.fi"}
@@ -1,62 +0,0 @@
1
- """
2
- Pyinfra command: show blue-green deployment status.
3
-
4
- Reads and displays the blue-green state from each host.
5
-
6
- Usage (via djaploy management command):
7
- manage.py djaploy status --env production
8
- """
9
-
10
- from pyinfra import host
11
- from pyinfra.api import deploy as _deploy_decorator
12
- from pyinfra.operations import server
13
-
14
- from djaploy.hooks import discover_hooks, get_registry
15
- from djaploy.infra.utils import is_bluegreen, get_app_path, get_slot_socket_path
16
- from djaploy.infra.bluegreen import print_status_cmd
17
-
18
- discover_hooks()
19
- registry = get_registry()
20
-
21
- if is_bluegreen(host.data):
22
- app_name = getattr(host.data, 'app_name', 'unknown')
23
- app_path = get_app_path(host.data)
24
- state_file = f"{app_path}/state.json"
25
-
26
- @_deploy_decorator("show_bluegreen_status")
27
- def show_bluegreen_status(host_data):
28
- server.shell(
29
- name="Show blue-green status",
30
- commands=[
31
- print_status_cmd(state_file, app_name),
32
- f'echo "Sockets:"',
33
- f'echo " Blue: {get_slot_socket_path(app_name, "blue")}"',
34
- f'echo " Green: {get_slot_socket_path(app_name, "green")}"',
35
- f'echo ""',
36
- # Show systemd service status
37
- f'echo "Services:"',
38
- f'systemctl is-active {app_name}-blue.service 2>/dev/null && '
39
- f'echo " {app_name}-blue: active" || '
40
- f'echo " {app_name}-blue: inactive"',
41
- f'systemctl is-active {app_name}-green.service 2>/dev/null && '
42
- f'echo " {app_name}-green: active" || '
43
- f'echo " {app_name}-green: inactive"',
44
- f'echo ""',
45
- ],
46
- _sudo=True,
47
- )
48
-
49
- show_bluegreen_status(host.data)
50
- else:
51
- @_deploy_decorator("show_status")
52
- def show_status(host_data):
53
- server.shell(
54
- name="Show deployment status",
55
- commands=[
56
- f'echo "Deployment strategy: {getattr(host.data, "deployment_strategy", "zero_downtime")}"',
57
- f'echo "Not a blue-green deployment. Use deploy/rollback commands."',
58
- ],
59
- _sudo=True,
60
- )
61
-
62
- show_status(host.data)
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