djaploy 0.1.0__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 (37) hide show
  1. djaploy-0.1.0/LICENSE +21 -0
  2. djaploy-0.1.0/PKG-INFO +310 -0
  3. djaploy-0.1.0/README.md +247 -0
  4. djaploy-0.1.0/djaploy/__init__.py +14 -0
  5. djaploy-0.1.0/djaploy/artifact.py +124 -0
  6. djaploy-0.1.0/djaploy/bin/__init__.py +1 -0
  7. djaploy-0.1.0/djaploy/bin/django_pyinfra.py +49 -0
  8. djaploy-0.1.0/djaploy/certificates.py +423 -0
  9. djaploy-0.1.0/djaploy/config.py +224 -0
  10. djaploy-0.1.0/djaploy/deploy.py +357 -0
  11. djaploy-0.1.0/djaploy/management/__init__.py +3 -0
  12. djaploy-0.1.0/djaploy/management/commands/__init__.py +3 -0
  13. djaploy-0.1.0/djaploy/management/commands/configureserver.py +56 -0
  14. djaploy-0.1.0/djaploy/management/commands/deploy.py +100 -0
  15. djaploy-0.1.0/djaploy/management/commands/sync_certs.py +75 -0
  16. djaploy-0.1.0/djaploy/management/commands/update_certs.py +151 -0
  17. djaploy-0.1.0/djaploy/management/commands/verify.py +363 -0
  18. djaploy-0.1.0/djaploy/management/utils.py +131 -0
  19. djaploy-0.1.0/djaploy/modules/__init__.py +13 -0
  20. djaploy-0.1.0/djaploy/modules/base.py +152 -0
  21. djaploy-0.1.0/djaploy/modules/core.py +418 -0
  22. djaploy-0.1.0/djaploy/modules/litestream.py +166 -0
  23. djaploy-0.1.0/djaploy/modules/loader.py +129 -0
  24. djaploy-0.1.0/djaploy/modules/nginx.py +109 -0
  25. djaploy-0.1.0/djaploy/modules/rclone.py +387 -0
  26. djaploy-0.1.0/djaploy/modules/sync_certs.py +107 -0
  27. djaploy-0.1.0/djaploy/modules/systemd.py +66 -0
  28. djaploy-0.1.0/djaploy/utils.py +84 -0
  29. djaploy-0.1.0/djaploy/version.py +1 -0
  30. djaploy-0.1.0/djaploy.egg-info/PKG-INFO +310 -0
  31. djaploy-0.1.0/djaploy.egg-info/SOURCES.txt +35 -0
  32. djaploy-0.1.0/djaploy.egg-info/dependency_links.txt +1 -0
  33. djaploy-0.1.0/djaploy.egg-info/entry_points.txt +2 -0
  34. djaploy-0.1.0/djaploy.egg-info/requires.txt +9 -0
  35. djaploy-0.1.0/djaploy.egg-info/top_level.txt +1 -0
  36. djaploy-0.1.0/pyproject.toml +61 -0
  37. djaploy-0.1.0/setup.cfg +4 -0
djaploy-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 djaploy contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
djaploy-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,310 @@
1
+ Metadata-Version: 2.4
2
+ Name: djaploy
3
+ Version: 0.1.0
4
+ Summary: Modular Django deployment system based on pyinfra
5
+ Author-email: Johanna Mae Dimayuga <johanna@techco.fi>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 djaploy contributors
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Project-URL: Homepage, https://github.com/techco-fi/djaploy
28
+ Project-URL: Repository, https://github.com/techco-fi/djaploy
29
+ Project-URL: Issues, https://github.com/techco-fi/djaploy/issues
30
+ Project-URL: Documentation, https://github.com/techco-fi/djaploy#readme
31
+ Keywords: django,deployment,pyinfra,automation,infrastructure
32
+ Classifier: Development Status :: 3 - Alpha
33
+ Classifier: Environment :: Console
34
+ Classifier: Framework :: Django
35
+ Classifier: Framework :: Django :: 3.2
36
+ Classifier: Framework :: Django :: 4.0
37
+ Classifier: Framework :: Django :: 4.1
38
+ Classifier: Framework :: Django :: 4.2
39
+ Classifier: Framework :: Django :: 5.0
40
+ Classifier: Intended Audience :: Developers
41
+ Classifier: License :: OSI Approved :: MIT License
42
+ Classifier: Operating System :: OS Independent
43
+ Classifier: Programming Language :: Python :: 3
44
+ Classifier: Programming Language :: Python :: 3.8
45
+ Classifier: Programming Language :: Python :: 3.9
46
+ Classifier: Programming Language :: Python :: 3.10
47
+ Classifier: Programming Language :: Python :: 3.11
48
+ Classifier: Programming Language :: Python :: 3.12
49
+ Classifier: Topic :: Software Development :: Build Tools
50
+ Classifier: Topic :: System :: Installation/Setup
51
+ Classifier: Topic :: System :: Systems Administration
52
+ Requires-Python: >=3.9
53
+ Description-Content-Type: text/markdown
54
+ License-File: LICENSE
55
+ Requires-Dist: pyinfra>=3.4
56
+ Requires-Dist: django>=3.2
57
+ Requires-Dist: build<2.0.0,>=1.3.0
58
+ Provides-Extra: certificates
59
+ Requires-Dist: certbot>=2.0; extra == "certificates"
60
+ Provides-Extra: bunny
61
+ Requires-Dist: certbot-dns-bunny>=0.1.0; extra == "bunny"
62
+ Dynamic: license-file
63
+
64
+ # djaploy
65
+
66
+ A modular Django deployment system based on pyinfra, designed to standardize and simplify infrastructure management across Django projects.
67
+
68
+ ## Features
69
+
70
+ - **Modular Architecture**: Extensible plugin system for deployment components
71
+ - **Django Integration**: Seamless integration via Django management commands
72
+ - **Python Compilation Support**: Compile Python from source for specific versions
73
+ - **Multiple Deployment Modes**: Support for `--local`, `--latest`, and `--release` deployments
74
+ - **Infrastructure as Code**: Define infrastructure using Python with pyinfra
75
+ - **Git-based Artifacts**: Automated artifact creation from git repository
76
+
77
+ ## Installation
78
+
79
+ ### From PyPI (once published)
80
+
81
+ ```bash
82
+ pip install djaploy
83
+ ```
84
+
85
+ Or with Poetry:
86
+ ```bash
87
+ poetry add djaploy
88
+ ```
89
+
90
+ ### Development Installation
91
+
92
+ For testing djaploy locally without publishing to PyPI:
93
+
94
+ ```bash
95
+ # Clone the repository
96
+ git clone https://github.com/techco-fi/djaploy.git
97
+ cd djaploy
98
+
99
+ # Install in editable mode
100
+ pip install -e .
101
+
102
+ # Or with Poetry
103
+ poetry install
104
+ ```
105
+
106
+ Then in your Django project:
107
+ ```bash
108
+ # Using pip
109
+ pip install -e /path/to/djaploy
110
+
111
+ # Or add as a local dependency in pyproject.toml
112
+ [tool.poetry.dependencies]
113
+ djaploy = {path = "../djaploy", develop = true}
114
+ ```
115
+
116
+ ## Quick Start
117
+
118
+ ### 1. Project Structure
119
+
120
+ ```
121
+ your-django-project/
122
+ ├── manage.py
123
+ ├── your_app/
124
+ │ └── settings.py
125
+ └── djaploy/ # Deployment configuration
126
+ ├── config.py # Main configuration
127
+ ├── inventory/ # Host definitions
128
+ │ ├── production.py
129
+ │ └── staging.py
130
+ └── deploy_files/ # Environment-specific files
131
+ ├── production/
132
+ │ └── etc/systemd/system/app.service
133
+ └── staging/
134
+ ```
135
+
136
+ ### 2. Django Settings
137
+
138
+ Add to your Django `settings.py`:
139
+
140
+ ```python
141
+ # Required: Set project paths
142
+ BASE_DIR = '/path/to/django'
143
+ PROJECT_DIR = BASE_DIR # folder containing manage.py
144
+ DJAPLOY_CONFIG_DIR = BASE_DIR + '/djaploy'
145
+ GIT_DIR = BASE_DIR.parent # Git repository root
146
+ ```
147
+
148
+ ### 3. Create Configuration
149
+
150
+ Create `djaploy/config.py`:
151
+
152
+ ```python
153
+ from djaploy.config import DjaployConfig
154
+ from pathlib import Path
155
+
156
+ config = DjaployConfig(
157
+ # Required fields
158
+ project_name="myapp",
159
+ djaploy_dir=Path(__file__).parent, # REQUIRED: This djaploy directory
160
+ manage_py_path=Path("manage.py"), # REQUIRED: Path to manage.py (relative to project root)
161
+
162
+ # Python settings
163
+ python_version="3.11",
164
+ python_compile=False, # Set True to compile from source
165
+
166
+ # Server settings
167
+ app_user="app",
168
+ ssh_user="deploy",
169
+
170
+ # Modules to use
171
+ modules=[
172
+ "djaploy.modules.core", # Core setup (required)
173
+ "djaploy.modules.nginx", # Web server
174
+ "djaploy.modules.systemd", # Service management
175
+ ],
176
+
177
+ # Services to manage
178
+ services=["myapp", "myapp-worker"],
179
+ )
180
+ ```
181
+
182
+ ### 4. Define Inventory
183
+
184
+ Create `djaploy/inventory/production.py`:
185
+
186
+ ```python
187
+ from djaploy.config import HostConfig
188
+
189
+ hosts = [
190
+ HostConfig(
191
+ name="web-1",
192
+ ssh_host="192.168.1.100",
193
+ ssh_user="deploy",
194
+ app_user="app",
195
+ env="production",
196
+ services=["myapp", "myapp-worker"],
197
+ ),
198
+ ]
199
+ ```
200
+
201
+ ### 5. Deploy Files
202
+
203
+ Place service files in `djaploy/deploy_files/production/`:
204
+
205
+ ```ini
206
+ # etc/systemd/system/myapp.service
207
+ [Unit]
208
+ Description=My Django App
209
+ After=network.target
210
+
211
+ [Service]
212
+ Type=simple
213
+ User=app
214
+ WorkingDirectory=/home/app/apps/myapp
215
+ ExecStart=/home/app/.local/bin/poetry run gunicorn config.wsgi
216
+ Restart=on-failure
217
+
218
+ [Install]
219
+ WantedBy=multi-user.target
220
+ ```
221
+
222
+ ## Usage
223
+
224
+ ### Configure Server
225
+
226
+ ```bash
227
+ python manage.py configureserver --env production
228
+ ```
229
+
230
+ This will:
231
+ - Create application user
232
+ - Install/compile Python
233
+ - Install Poetry
234
+ - Set up directory structure
235
+
236
+ ### Deploy Application
237
+
238
+ ```bash
239
+ # Deploy local changes (for development)
240
+ python manage.py deploy --env production --local
241
+
242
+ # Deploy latest git commit
243
+ python manage.py deploy --env production --latest
244
+
245
+ # Deploy specific release
246
+ python manage.py deploy --env production --release v1.0.0
247
+ ```
248
+
249
+ Deployment process:
250
+ 1. Creates tar.gz artifact from git
251
+ 2. Uploads to servers
252
+ 3. Extracts application code
253
+ 4. Installs dependencies
254
+ 5. Runs migrations
255
+ 6. Collects static files
256
+ 7. Restarts services
257
+
258
+ ## Module System
259
+
260
+ Djaploy uses a modular architecture where each component (nginx, systemd, backups, etc.) is a separate module that can be enabled or disabled per project.
261
+
262
+ ### Available Modules
263
+
264
+ - `nginx`: NGINX web server configuration
265
+ - `systemd`: Systemd service management
266
+ - `litestream`: Litestream database backups
267
+ - `rclone`: Rclone-based backup system
268
+ - `tailscale`: Tailscale networking
269
+ - `ssl`: SSL certificate management
270
+ - `python_build`: Python compilation from source
271
+
272
+ ### Creating Custom Modules
273
+
274
+ Projects can create their own modules by extending the base module class:
275
+
276
+ ```python
277
+ from djaploy.modules.base import BaseModule
278
+
279
+ class MyCustomModule(BaseModule):
280
+ def configure_server(self, host):
281
+ # Server configuration logic
282
+ pass
283
+
284
+ def deploy(self, host, artifact_path):
285
+ # Deployment logic
286
+ pass
287
+ ```
288
+
289
+ ## Project Customization
290
+
291
+ ### prepare.py
292
+
293
+ Projects can include a `prepare.py` file for local build steps before deployment:
294
+
295
+ ```python
296
+ # prepare.py
297
+ from djaploy.prepare import run_command
298
+
299
+ def prepare():
300
+ run_command("npm run build")
301
+ run_command("python manage.py collectstatic --noinput")
302
+ ```
303
+
304
+ ### Custom Deploy Files
305
+
306
+ Projects can include environment-specific configuration files in a `deploy_files/` directory that will be copied to the server during deployment.
307
+
308
+ ## License
309
+
310
+ MIT
@@ -0,0 +1,247 @@
1
+ # djaploy
2
+
3
+ A modular Django deployment system based on pyinfra, designed to standardize and simplify infrastructure management across Django projects.
4
+
5
+ ## Features
6
+
7
+ - **Modular Architecture**: Extensible plugin system for deployment components
8
+ - **Django Integration**: Seamless integration via Django management commands
9
+ - **Python Compilation Support**: Compile Python from source for specific versions
10
+ - **Multiple Deployment Modes**: Support for `--local`, `--latest`, and `--release` deployments
11
+ - **Infrastructure as Code**: Define infrastructure using Python with pyinfra
12
+ - **Git-based Artifacts**: Automated artifact creation from git repository
13
+
14
+ ## Installation
15
+
16
+ ### From PyPI (once published)
17
+
18
+ ```bash
19
+ pip install djaploy
20
+ ```
21
+
22
+ Or with Poetry:
23
+ ```bash
24
+ poetry add djaploy
25
+ ```
26
+
27
+ ### Development Installation
28
+
29
+ For testing djaploy locally without publishing to PyPI:
30
+
31
+ ```bash
32
+ # Clone the repository
33
+ git clone https://github.com/techco-fi/djaploy.git
34
+ cd djaploy
35
+
36
+ # Install in editable mode
37
+ pip install -e .
38
+
39
+ # Or with Poetry
40
+ poetry install
41
+ ```
42
+
43
+ Then in your Django project:
44
+ ```bash
45
+ # Using pip
46
+ pip install -e /path/to/djaploy
47
+
48
+ # Or add as a local dependency in pyproject.toml
49
+ [tool.poetry.dependencies]
50
+ djaploy = {path = "../djaploy", develop = true}
51
+ ```
52
+
53
+ ## Quick Start
54
+
55
+ ### 1. Project Structure
56
+
57
+ ```
58
+ your-django-project/
59
+ ├── manage.py
60
+ ├── your_app/
61
+ │ └── settings.py
62
+ └── djaploy/ # Deployment configuration
63
+ ├── config.py # Main configuration
64
+ ├── inventory/ # Host definitions
65
+ │ ├── production.py
66
+ │ └── staging.py
67
+ └── deploy_files/ # Environment-specific files
68
+ ├── production/
69
+ │ └── etc/systemd/system/app.service
70
+ └── staging/
71
+ ```
72
+
73
+ ### 2. Django Settings
74
+
75
+ Add to your Django `settings.py`:
76
+
77
+ ```python
78
+ # Required: Set project paths
79
+ BASE_DIR = '/path/to/django'
80
+ PROJECT_DIR = BASE_DIR # folder containing manage.py
81
+ DJAPLOY_CONFIG_DIR = BASE_DIR + '/djaploy'
82
+ GIT_DIR = BASE_DIR.parent # Git repository root
83
+ ```
84
+
85
+ ### 3. Create Configuration
86
+
87
+ Create `djaploy/config.py`:
88
+
89
+ ```python
90
+ from djaploy.config import DjaployConfig
91
+ from pathlib import Path
92
+
93
+ config = DjaployConfig(
94
+ # Required fields
95
+ project_name="myapp",
96
+ djaploy_dir=Path(__file__).parent, # REQUIRED: This djaploy directory
97
+ manage_py_path=Path("manage.py"), # REQUIRED: Path to manage.py (relative to project root)
98
+
99
+ # Python settings
100
+ python_version="3.11",
101
+ python_compile=False, # Set True to compile from source
102
+
103
+ # Server settings
104
+ app_user="app",
105
+ ssh_user="deploy",
106
+
107
+ # Modules to use
108
+ modules=[
109
+ "djaploy.modules.core", # Core setup (required)
110
+ "djaploy.modules.nginx", # Web server
111
+ "djaploy.modules.systemd", # Service management
112
+ ],
113
+
114
+ # Services to manage
115
+ services=["myapp", "myapp-worker"],
116
+ )
117
+ ```
118
+
119
+ ### 4. Define Inventory
120
+
121
+ Create `djaploy/inventory/production.py`:
122
+
123
+ ```python
124
+ from djaploy.config import HostConfig
125
+
126
+ hosts = [
127
+ HostConfig(
128
+ name="web-1",
129
+ ssh_host="192.168.1.100",
130
+ ssh_user="deploy",
131
+ app_user="app",
132
+ env="production",
133
+ services=["myapp", "myapp-worker"],
134
+ ),
135
+ ]
136
+ ```
137
+
138
+ ### 5. Deploy Files
139
+
140
+ Place service files in `djaploy/deploy_files/production/`:
141
+
142
+ ```ini
143
+ # etc/systemd/system/myapp.service
144
+ [Unit]
145
+ Description=My Django App
146
+ After=network.target
147
+
148
+ [Service]
149
+ Type=simple
150
+ User=app
151
+ WorkingDirectory=/home/app/apps/myapp
152
+ ExecStart=/home/app/.local/bin/poetry run gunicorn config.wsgi
153
+ Restart=on-failure
154
+
155
+ [Install]
156
+ WantedBy=multi-user.target
157
+ ```
158
+
159
+ ## Usage
160
+
161
+ ### Configure Server
162
+
163
+ ```bash
164
+ python manage.py configureserver --env production
165
+ ```
166
+
167
+ This will:
168
+ - Create application user
169
+ - Install/compile Python
170
+ - Install Poetry
171
+ - Set up directory structure
172
+
173
+ ### Deploy Application
174
+
175
+ ```bash
176
+ # Deploy local changes (for development)
177
+ python manage.py deploy --env production --local
178
+
179
+ # Deploy latest git commit
180
+ python manage.py deploy --env production --latest
181
+
182
+ # Deploy specific release
183
+ python manage.py deploy --env production --release v1.0.0
184
+ ```
185
+
186
+ Deployment process:
187
+ 1. Creates tar.gz artifact from git
188
+ 2. Uploads to servers
189
+ 3. Extracts application code
190
+ 4. Installs dependencies
191
+ 5. Runs migrations
192
+ 6. Collects static files
193
+ 7. Restarts services
194
+
195
+ ## Module System
196
+
197
+ Djaploy uses a modular architecture where each component (nginx, systemd, backups, etc.) is a separate module that can be enabled or disabled per project.
198
+
199
+ ### Available Modules
200
+
201
+ - `nginx`: NGINX web server configuration
202
+ - `systemd`: Systemd service management
203
+ - `litestream`: Litestream database backups
204
+ - `rclone`: Rclone-based backup system
205
+ - `tailscale`: Tailscale networking
206
+ - `ssl`: SSL certificate management
207
+ - `python_build`: Python compilation from source
208
+
209
+ ### Creating Custom Modules
210
+
211
+ Projects can create their own modules by extending the base module class:
212
+
213
+ ```python
214
+ from djaploy.modules.base import BaseModule
215
+
216
+ class MyCustomModule(BaseModule):
217
+ def configure_server(self, host):
218
+ # Server configuration logic
219
+ pass
220
+
221
+ def deploy(self, host, artifact_path):
222
+ # Deployment logic
223
+ pass
224
+ ```
225
+
226
+ ## Project Customization
227
+
228
+ ### prepare.py
229
+
230
+ Projects can include a `prepare.py` file for local build steps before deployment:
231
+
232
+ ```python
233
+ # prepare.py
234
+ from djaploy.prepare import run_command
235
+
236
+ def prepare():
237
+ run_command("npm run build")
238
+ run_command("python manage.py collectstatic --noinput")
239
+ ```
240
+
241
+ ### Custom Deploy Files
242
+
243
+ Projects can include environment-specific configuration files in a `deploy_files/` directory that will be copied to the server during deployment.
244
+
245
+ ## License
246
+
247
+ MIT
@@ -0,0 +1,14 @@
1
+ """
2
+ djaploy - Modular Django deployment system based on pyinfra
3
+ """
4
+
5
+ from .config import DjaployConfig
6
+ from .deploy import deploy_project, configure_server
7
+ from .version import __version__
8
+
9
+ __all__ = [
10
+ "DjaployConfig",
11
+ "deploy_project",
12
+ "configure_server",
13
+ "__version__",
14
+ ]
@@ -0,0 +1,124 @@
1
+ """
2
+ Artifact creation for deployments
3
+ """
4
+
5
+ import os
6
+ import subprocess
7
+ import tempfile
8
+ from pathlib import Path
9
+ from typing import Optional
10
+
11
+ from .config import DjaployConfig
12
+
13
+
14
+ def create_artifact(config: DjaployConfig,
15
+ mode: str = "latest",
16
+ release_tag: Optional[str] = None) -> Path:
17
+ """
18
+ Create deployment artifact based on mode
19
+
20
+ Args:
21
+ config: DjaployConfig instance
22
+ mode: Deployment mode ("local", "latest", "release")
23
+ release_tag: Release tag if mode is "release"
24
+
25
+ Returns:
26
+ Path to created artifact
27
+ """
28
+
29
+ # Ensure artifact directory exists
30
+ artifact_dir = config.git_dir / config.artifact_dir
31
+ artifact_dir.mkdir(parents=True, exist_ok=True)
32
+
33
+ if mode == "local":
34
+ return _create_local_artifact(config, artifact_dir)
35
+ elif mode == "latest":
36
+ return _create_latest_artifact(config, artifact_dir)
37
+ elif mode == "release":
38
+ if not release_tag:
39
+ raise ValueError("release_tag is required when mode is 'release'")
40
+ return _create_release_artifact(config, artifact_dir, release_tag)
41
+ else:
42
+ raise ValueError(f"Invalid deployment mode: {mode}")
43
+
44
+
45
+ def _create_local_artifact(config: DjaployConfig, artifact_dir: Path) -> Path:
46
+ """Create artifact from local uncommitted files"""
47
+
48
+ artifact_file = artifact_dir / f"{config.project_name}.local.tar.gz"
49
+
50
+ # Change to git directory
51
+ original_dir = os.getcwd()
52
+ os.chdir(config.git_dir)
53
+
54
+ try:
55
+ # Create artifact from git files (including uncommitted changes)
56
+ subprocess.run(
57
+ "git ls-files --others --exclude-standard --cached | tar Tzcf - {}".format(artifact_file),
58
+ shell=True,
59
+ check=True,
60
+ )
61
+
62
+ return artifact_file
63
+ finally:
64
+ os.chdir(original_dir)
65
+
66
+
67
+ def _create_latest_artifact(config: DjaployConfig, artifact_dir: Path) -> Path:
68
+ """Create artifact from latest git commit"""
69
+
70
+ # Get git hash
71
+ git_hash = subprocess.run(
72
+ ["git", "rev-parse", "--short", "HEAD"],
73
+ capture_output=True,
74
+ check=True,
75
+ text=True,
76
+ cwd=config.git_dir,
77
+ ).stdout.strip()
78
+
79
+ return _create_git_artifact(config, artifact_dir, git_hash)
80
+
81
+
82
+ def _create_release_artifact(config: DjaployConfig, artifact_dir: Path, release_tag: str) -> Path:
83
+ """Create artifact from a specific release tag"""
84
+
85
+ # Verify the tag exists
86
+ try:
87
+ subprocess.run(
88
+ ["git", "rev-parse", release_tag],
89
+ capture_output=True,
90
+ check=True,
91
+ cwd=config.git_dir,
92
+ )
93
+ except subprocess.CalledProcessError:
94
+ raise ValueError(f"Release tag '{release_tag}' does not exist")
95
+
96
+ return _create_git_artifact(config, artifact_dir, release_tag)
97
+
98
+
99
+ def _create_git_artifact(config: DjaployConfig, artifact_dir: Path, git_ref: str) -> Path:
100
+ """Create artifact from a git reference"""
101
+
102
+ artifact_tar = artifact_dir / f"{config.project_name}.{git_ref}.tar"
103
+ artifact_file = artifact_dir / f"{config.project_name}.{git_ref}.tar.gz"
104
+
105
+ # Change to git directory
106
+ original_dir = os.getcwd()
107
+ os.chdir(config.git_dir)
108
+
109
+ try:
110
+ # Create tar archive from git
111
+ subprocess.run(
112
+ ["git", "archive", "--format=tar", "-o", str(artifact_tar), git_ref],
113
+ check=True,
114
+ )
115
+
116
+ # Compress the tar file
117
+ subprocess.run(
118
+ ["gzip", "-f", str(artifact_tar)],
119
+ check=True,
120
+ )
121
+
122
+ return artifact_file
123
+ finally:
124
+ os.chdir(original_dir)