fujin-cli 0.22.2__tar.gz → 0.23.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.
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/CHANGELOG.md +7 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/PKG-INFO +1 -1
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-1password/pyproject.toml +2 -2
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-bitwarden/pyproject.toml +2 -2
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-doppler/pyproject.toml +2 -2
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/pyproject.toml +2 -2
- fujin_cli-0.23.0/src/fujin/__init__.py +1 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/_installer.py +0 -8
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/deploy.py +49 -4
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/uv.lock +4 -4
- fujin_cli-0.22.2/src/fujin/__init__.py +0 -1
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/.github/FUNDING.yml +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/.github/workflows/publish.yml +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/.github/workflows/test.yml +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/.gitignore +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/.pre-commit-config.yaml +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/.readthedocs.yaml +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/CLAUDE.md +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/LICENSE.txt +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/README.md +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/Vagrantfile +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-cat-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-exec-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-logs-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-restart-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-scale-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-shell-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-start-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-status-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/app-stop-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/audit-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/deploy-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/down-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/fa-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/fujin-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/init-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/migrate-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/new-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/prune-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/rollback-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/server-bootstrap-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/server-create-user-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/server-exec-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/server-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/server-setup-ssh-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/server-status-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/_static/images/help/up-help.png +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/changelog.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/app.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/audit.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/deploy.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/down.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/index.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/init.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/migrate.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/new.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/prune.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/rollback.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/server.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/commands/up.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/conf.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/configuration.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/guides/django-complete.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/guides/index.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/guides/templates.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/howtos/binary.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/howtos/django.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/howtos/index.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/index.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/installation.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/integrations.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/requirements.txt +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/secrets.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/docs/troubleshooting.rst +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/.fujin/Caddyfile +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/.fujin/systemd/health.service +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/.fujin/systemd/health.timer +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/.fujin/systemd/web.service +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/.fujin/systemd/worker@.service +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/README.md +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/bookstore/__init__.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/bookstore/__main__.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/bookstore/asgi.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/bookstore/management/commands/health.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/bookstore/settings.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/bookstore/urls.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/bookstore/wsgi.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/fujin.toml +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/manage.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/pyproject.toml +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/requirements.txt +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/justfile +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-1password/README.md +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-1password/src/fujin_secrets_1password/__init__.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-1password/src/fujin_secrets_1password/py.typed +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-bitwarden/README.md +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-bitwarden/src/fujin_secrets_bitwarden/__init__.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-bitwarden/src/fujin_secrets_bitwarden/py.typed +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-doppler/README.md +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-doppler/src/fujin_secrets_doppler/__init__.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/plugins/fujin-secrets-doppler/src/fujin_secrets_doppler/py.typed +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/__main__.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/audit.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/caddy.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/__init__.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/_base.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/app.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/audit.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/down.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/init.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/migrate.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/new.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/prune.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/rollback.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/server.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/showenv.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/commands/up.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/config.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/connection.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/discovery.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/errors.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/fa.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/formatting.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/secrets.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/src/fujin/templates.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/__init__.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/conftest.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/integration/Dockerfile +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/integration/__init__.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/integration/conftest.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/integration/helpers.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/integration/test_app_management.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/integration/test_full_deploy.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/integration/test_installation.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/integration/test_server_bootstrap.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_app.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_audit.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_caddy_domain.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_config.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_connection.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_deploy.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_discovery.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_down.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_init.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_new.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_prune.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_rollback.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_scale.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_secrets.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_server.py +0 -0
- {fujin_cli-0.22.2 → fujin_cli-0.23.0}/tests/test_up.py +0 -0
|
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.23.0] - 2026-03-21
|
|
8
|
+
|
|
9
|
+
### 🚀 Features
|
|
10
|
+
|
|
11
|
+
- Stream .env directly to server instead of bundling
|
|
12
|
+
- Add --bundle-dir option to preserve deployment bundle
|
|
13
|
+
|
|
7
14
|
## [0.22.2] - 2026-03-21
|
|
8
15
|
|
|
9
16
|
### 🐛 Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fujin-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
4
4
|
Summary: Get your project up and running in a few minutes on your own vps.
|
|
5
5
|
Project-URL: Documentation, https://github.com/Tobi-De/fujin#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/Tobi-De/fujin/issues
|
|
@@ -4,7 +4,7 @@ requires = [ "uv-build>=0.9.18,<0.10" ]
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fujin-secrets-1password"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.23.0"
|
|
8
8
|
description = "1Password secret adapter for Fujin"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -20,7 +20,7 @@ classifiers = [
|
|
|
20
20
|
"Programming Language :: Python :: 3.14",
|
|
21
21
|
]
|
|
22
22
|
dependencies = [
|
|
23
|
-
"fujin-cli>=0.
|
|
23
|
+
"fujin-cli>=0.23",
|
|
24
24
|
"python-dotenv>=1.0.1",
|
|
25
25
|
]
|
|
26
26
|
|
|
@@ -4,7 +4,7 @@ requires = [ "uv-build>=0.9.18,<0.10" ]
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fujin-secrets-bitwarden"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.23.0"
|
|
8
8
|
description = "Bitwarden secret adapter for Fujin"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -20,7 +20,7 @@ classifiers = [
|
|
|
20
20
|
"Programming Language :: Python :: 3.14",
|
|
21
21
|
]
|
|
22
22
|
dependencies = [
|
|
23
|
-
"fujin-cli>=0.
|
|
23
|
+
"fujin-cli>=0.23",
|
|
24
24
|
"python-dotenv>=1.0.1",
|
|
25
25
|
]
|
|
26
26
|
|
|
@@ -4,7 +4,7 @@ requires = [ "uv-build>=0.9.18,<0.10" ]
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fujin-secrets-doppler"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.23.0"
|
|
8
8
|
description = "Doppler secret adapter for Fujin"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -20,7 +20,7 @@ classifiers = [
|
|
|
20
20
|
"Programming Language :: Python :: 3.14",
|
|
21
21
|
]
|
|
22
22
|
dependencies = [
|
|
23
|
-
"fujin-cli>=0.
|
|
23
|
+
"fujin-cli>=0.23",
|
|
24
24
|
"python-dotenv>=1.0.1",
|
|
25
25
|
]
|
|
26
26
|
|
|
@@ -5,7 +5,7 @@ requires = [ "hatchling" ]
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "fujin-cli"
|
|
8
|
-
version = "0.
|
|
8
|
+
version = "0.23.0"
|
|
9
9
|
description = "Get your project up and running in a few minutes on your own vps."
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
keywords = [
|
|
@@ -149,7 +149,7 @@ markers = [
|
|
|
149
149
|
]
|
|
150
150
|
|
|
151
151
|
[tool.bumpversion]
|
|
152
|
-
current_version = "0.
|
|
152
|
+
current_version = "0.23.0"
|
|
153
153
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
154
154
|
serialize = [ "{major}.{minor}.{patch}" ]
|
|
155
155
|
search = "{current_version}"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.23.0"
|
|
@@ -135,13 +135,6 @@ def install(
|
|
|
135
135
|
install_dir = app_dir / ".install"
|
|
136
136
|
install_dir.mkdir(exist_ok=True)
|
|
137
137
|
|
|
138
|
-
# Move .env file to .install/
|
|
139
|
-
env_file = bundle_dir / ".env"
|
|
140
|
-
if env_file.exists():
|
|
141
|
-
shutil.move(env_file, install_dir / ".env")
|
|
142
|
-
env_file = install_dir / ".env"
|
|
143
|
-
logger.debug("Moved .env to %s", env_file)
|
|
144
|
-
|
|
145
138
|
# ==========================================================================
|
|
146
139
|
# PHASE 2: INSTALLATION
|
|
147
140
|
# ==========================================================================
|
|
@@ -221,7 +214,6 @@ export -f {config.app_name}
|
|
|
221
214
|
run(f"chown -R {config.deploy_user}:{config.app_user} {install_dir}")
|
|
222
215
|
# Make .install directory group-writable (deploy user can update, app user can read)
|
|
223
216
|
install_dir.chmod(0o775)
|
|
224
|
-
env_file.chmod(0o640)
|
|
225
217
|
|
|
226
218
|
# .venv permissions: readable/executable by group, writable by owner
|
|
227
219
|
# Use chmod -R with symbolic modes to traverse once instead of 3 find commands
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import base64
|
|
3
4
|
import json
|
|
4
5
|
import logging
|
|
5
6
|
import shlex
|
|
@@ -8,9 +9,10 @@ import hashlib
|
|
|
8
9
|
import subprocess
|
|
9
10
|
import tempfile
|
|
10
11
|
import zipapp
|
|
12
|
+
from contextlib import contextmanager
|
|
11
13
|
from dataclasses import dataclass
|
|
12
14
|
from pathlib import Path
|
|
13
|
-
from typing import Annotated
|
|
15
|
+
from typing import Annotated, Generator
|
|
14
16
|
|
|
15
17
|
import cappa
|
|
16
18
|
from rich.console import Console
|
|
@@ -61,6 +63,13 @@ class Deploy(BaseCommand):
|
|
|
61
63
|
help="Disable automatic rollback on deployment failure",
|
|
62
64
|
),
|
|
63
65
|
] = False
|
|
66
|
+
bundle_dir: Annotated[
|
|
67
|
+
Path | None,
|
|
68
|
+
cappa.Arg(
|
|
69
|
+
long="--bundle-dir",
|
|
70
|
+
help="Directory to create bundle in (preserved after deploy, fails if exists)",
|
|
71
|
+
),
|
|
72
|
+
] = None
|
|
64
73
|
|
|
65
74
|
def __call__(self):
|
|
66
75
|
logger.debug("Starting deployment for %s", self.config.app_name)
|
|
@@ -124,7 +133,7 @@ class Deploy(BaseCommand):
|
|
|
124
133
|
if not self.config.deployed_units:
|
|
125
134
|
raise DeploymentError("No systemd units found, nothing to deploy")
|
|
126
135
|
|
|
127
|
-
with
|
|
136
|
+
with self._bundle_directory() as tmpdir:
|
|
128
137
|
self.output.info("Preparing deployment bundle...")
|
|
129
138
|
zipapp_dir = Path(tmpdir) / "zipapp_source"
|
|
130
139
|
zipapp_dir.mkdir()
|
|
@@ -162,10 +171,9 @@ class Deploy(BaseCommand):
|
|
|
162
171
|
# Track unresolved variables across all files
|
|
163
172
|
all_unresolved = set()
|
|
164
173
|
|
|
165
|
-
#
|
|
174
|
+
# Resolve env file (uploaded separately, not bundled)
|
|
166
175
|
resolved_env, unresolved = safe_format(parsed_env, **context)
|
|
167
176
|
all_unresolved.update(unresolved)
|
|
168
|
-
(zipapp_dir / ".env").write_text(resolved_env)
|
|
169
177
|
|
|
170
178
|
logger.debug("Validating and resolving systemd units")
|
|
171
179
|
systemd_dir = zipapp_dir / "systemd"
|
|
@@ -351,6 +359,23 @@ class Deploy(BaseCommand):
|
|
|
351
359
|
conn.put(str(zipapp_path), remote_bundle_path_q, verify=True)
|
|
352
360
|
|
|
353
361
|
self.output.success("Bundle uploaded successfully.")
|
|
362
|
+
|
|
363
|
+
# Write .env file directly (not bundled for security)
|
|
364
|
+
remote_env_path = f"{self.config.install_dir}/.env"
|
|
365
|
+
remote_env_path_q = shlex.quote(remote_env_path)
|
|
366
|
+
install_dir_q = shlex.quote(self.config.install_dir)
|
|
367
|
+
logger.debug("Writing .env to %s", remote_env_path)
|
|
368
|
+
|
|
369
|
+
# Use base64 encoding to safely transfer content with special chars
|
|
370
|
+
encoded_env = base64.b64encode(resolved_env.encode()).decode()
|
|
371
|
+
conn.run(
|
|
372
|
+
f"mkdir -p {install_dir_q} && "
|
|
373
|
+
f"echo {shlex.quote(encoded_env)} | base64 -d > {remote_env_path_q} && "
|
|
374
|
+
f"chmod 640 {remote_env_path_q} && "
|
|
375
|
+
f"chown {self.selected_host.user}:{self.config.app_user} {remote_env_path_q}",
|
|
376
|
+
hide=True,
|
|
377
|
+
)
|
|
378
|
+
|
|
354
379
|
self.output.info("Executing remote installation...")
|
|
355
380
|
|
|
356
381
|
rollback_ran = False
|
|
@@ -425,6 +450,26 @@ class Deploy(BaseCommand):
|
|
|
425
450
|
url = f"https://{domain}"
|
|
426
451
|
self.output.info(f"Application is available at: {url}")
|
|
427
452
|
|
|
453
|
+
@contextmanager
|
|
454
|
+
def _bundle_directory(self) -> Generator[Path, None, None]:
|
|
455
|
+
"""Context manager for bundle directory.
|
|
456
|
+
|
|
457
|
+
If bundle_dir is specified, uses that directory (fails if exists).
|
|
458
|
+
Otherwise, creates a temporary directory that is cleaned up on exit.
|
|
459
|
+
"""
|
|
460
|
+
if self.bundle_dir:
|
|
461
|
+
if self.bundle_dir.exists():
|
|
462
|
+
raise DeploymentError(
|
|
463
|
+
f"Bundle directory already exists: {self.bundle_dir}"
|
|
464
|
+
)
|
|
465
|
+
self.bundle_dir.mkdir(parents=True)
|
|
466
|
+
logger.debug("Using bundle directory: %s", self.bundle_dir)
|
|
467
|
+
yield self.bundle_dir
|
|
468
|
+
self.output.info(f"Bundle preserved in: {self.bundle_dir}")
|
|
469
|
+
else:
|
|
470
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
471
|
+
yield Path(tmpdir)
|
|
472
|
+
|
|
428
473
|
def _show_deployment_summary(self, bundle_size: int, bundle_version: str):
|
|
429
474
|
console = Console()
|
|
430
475
|
|
|
@@ -345,7 +345,7 @@ wheels = [
|
|
|
345
345
|
|
|
346
346
|
[[package]]
|
|
347
347
|
name = "fujin-cli"
|
|
348
|
-
version = "0.22.
|
|
348
|
+
version = "0.22.2"
|
|
349
349
|
source = { editable = "." }
|
|
350
350
|
dependencies = [
|
|
351
351
|
{ name = "cappa" },
|
|
@@ -401,7 +401,7 @@ docs = [
|
|
|
401
401
|
|
|
402
402
|
[[package]]
|
|
403
403
|
name = "fujin-secrets-1password"
|
|
404
|
-
version = "0.22.
|
|
404
|
+
version = "0.22.2"
|
|
405
405
|
source = { editable = "plugins/fujin-secrets-1password" }
|
|
406
406
|
dependencies = [
|
|
407
407
|
{ name = "fujin-cli" },
|
|
@@ -416,7 +416,7 @@ requires-dist = [
|
|
|
416
416
|
|
|
417
417
|
[[package]]
|
|
418
418
|
name = "fujin-secrets-bitwarden"
|
|
419
|
-
version = "0.22.
|
|
419
|
+
version = "0.22.2"
|
|
420
420
|
source = { editable = "plugins/fujin-secrets-bitwarden" }
|
|
421
421
|
dependencies = [
|
|
422
422
|
{ name = "fujin-cli" },
|
|
@@ -431,7 +431,7 @@ requires-dist = [
|
|
|
431
431
|
|
|
432
432
|
[[package]]
|
|
433
433
|
name = "fujin-secrets-doppler"
|
|
434
|
-
version = "0.22.
|
|
434
|
+
version = "0.22.2"
|
|
435
435
|
source = { editable = "plugins/fujin-secrets-doppler" }
|
|
436
436
|
dependencies = [
|
|
437
437
|
{ name = "fujin-cli" },
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.22.2"
|
|
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
|
|
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
|
{fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/.fujin/systemd/health.service
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fujin_cli-0.22.2 → fujin_cli-0.23.0}/examples/django/bookstore/.fujin/systemd/worker@.service
RENAMED
|
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
|
|
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
|