magicbox-dk 0.0.2.dev1__tar.gz → 0.0.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.
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/.bumpversion.toml +3 -3
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/CLAUDE.md +8 -6
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/PKG-INFO +62 -1
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/README.md +61 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/_base.py +17 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/dashboard.py +2 -2
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/prepare.py +52 -1
- magicbox_dk-0.0.2.dev1/cli/commands/update.py → magicbox_dk-0.0.3/cli/commands/pull.py +4 -4
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/start.py +5 -4
- magicbox_dk-0.0.3/cli/commands/update.py +140 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/compose/__init__.py +9 -0
- magicbox_dk-0.0.3/cli/compose/build_state.py +281 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/compose/builder.py +12 -9
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/compose/healthcheck.py +7 -40
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/compose/network.py +63 -12
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/compose/runtime.py +39 -21
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/core/context.py +3 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/core/paths.py +7 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/main.py +39 -4
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/runner/docker.py +26 -2
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/settings.py +4 -0
- magicbox_dk-0.0.3/cli/version_check.py +149 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/services/back.config.yml +7 -4
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/pyproject.toml +1 -1
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/uv.lock +1 -1
- magicbox_dk-0.0.2.dev1/cli/commands/version.py +0 -30
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/.github/workflows/ci.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/.github/workflows/cleanup-prereleases.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/.github/workflows/release.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/.gitignore +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/LICENSE +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/cleanup.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/clean.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/create.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/credentials.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/delete.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/doctor.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/edit.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/env.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/init.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/list.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/logs.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/restart.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/settings.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/shell.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/show.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/status.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/stop.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/switch.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/commands/validate.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/compose/templates.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/core/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/core/cmd.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/core/profile_io.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/debug.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/_readiness.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/_state.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/env.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/frontend.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/infra.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/kin.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/profile.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/profile_meta.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/runnable.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/editors/settings.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/env/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/env/dotenv.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/env/loaders.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/env/regenerate.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/env/resolver.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/models/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/models/env.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/models/profile.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/models/service.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/runner/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/runner/base.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/runner/binaries.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/runner/git.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/runner/process.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/runner/redaction.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/cli/ui.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/credentials.base.yaml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/globals.base.yaml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/profile.base.yaml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/services/chainlit.config.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/services/horizon.config.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/services/module.config.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/services/node-service-provider.config.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/services/s3.config.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/services/surrealdb.config.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/configs/settings.base.yaml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/docker/archetypes/docker-compose.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/docker/back/docker-compose.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/docker/chainlit/docker-compose.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/docker/docker-compose.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/docker/horizon/docker-compose.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/docker/node-service-provider/docker-compose.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/docker/redis/docker-compose.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/docker/s3/docker-compose.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/docker/surrealdb/docker-compose.yml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/profile.example.yaml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/Dockerfile/Dockerfile +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/Dockerfile/digitalkin-1.0.0.dev0.tar.gz +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/Dockerfile/entrypoint.sh +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/Dockerfile/generate_certificates.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/README.md +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/application.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/config.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/handlers/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/handlers/input_factory.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/handlers/output_handler.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/main.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/models/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/models/config.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/models/protocols.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/pyproject.toml +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/services/__init__.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/services/filesystem.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/services/gateway_client.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/services/module_client.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/services/registry.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/services/setup.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/chainlit/uv.lock +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/horizon/Dockerfile/Dockerfile +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/services/horizon/Dockerfile/nginx.conf +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/conftest.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_base.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_binaries.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_docker.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_docker_validators.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_git.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_git_repo_ops.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_git_validators.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_process.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_redaction.py +0 -0
- {magicbox_dk-0.0.2.dev1 → magicbox_dk-0.0.3}/tests/test_settings.py +0 -0
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
# https://peps.python.org/pep-0440/
|
|
4
4
|
|
|
5
5
|
[tool.bumpversion]
|
|
6
|
-
current_version = "0.0.
|
|
6
|
+
current_version = "0.0.3"
|
|
7
7
|
|
|
8
8
|
allow_dirty = false # Require clean working directory
|
|
9
|
-
commit =
|
|
10
|
-
tag = true
|
|
9
|
+
commit = true # Auto-commit the version bump
|
|
10
|
+
tag = true # Auto-create the git tag (v{new_version})
|
|
11
11
|
sign_tags = false # Don't sign tags
|
|
12
12
|
|
|
13
13
|
# major.minor.patch with an optional `.devN` pre-release.
|
|
@@ -118,7 +118,7 @@ Point d'entrée : `from cli.runner import docker, git` (singletons).
|
|
|
118
118
|
schéma non autorisé). Primitives validées
|
|
119
119
|
(`status_porcelain`, `head_branch`, `rev_list_counts`…, `clone`/`fetch`/`checkout`/`pull_ff`) **et** orchestration UI
|
|
120
120
|
repliée depuis l'ancien `git_ops`
|
|
121
|
-
(`sync_repo`/`pull_repo`/`repo_status` + `RepoStatus`/`report_repo_statuses`). Consommé par `dk prepare`/`
|
|
121
|
+
(`sync_repo`/`pull_repo`/`repo_status` + `RepoStatus`/`report_repo_statuses`). Consommé par `dk prepare`/`pull`/
|
|
122
122
|
`start`.
|
|
123
123
|
|
|
124
124
|
### `cli/core/` — runtime state
|
|
@@ -238,16 +238,16 @@ class DeleteCommand(BaseCommand):
|
|
|
238
238
|
`cli` est **l'unique méthode publique** : elle construit l'instance depuis la CLI
|
|
239
239
|
et déclenche `_dispatch()` (le cycle de vie partagé). `BaseCommand` fournit un
|
|
240
240
|
**`cli` par défaut** (classmethod `cls()._dispatch()`) : une commande **sans
|
|
241
|
-
argument** (`
|
|
241
|
+
argument** (`dashboard`, `settings`) ne redéfinit pas `cli`, elle
|
|
242
242
|
hérite du défaut (on passe `help=` au montage pour garder une description
|
|
243
|
-
distincte : `app.command("
|
|
243
|
+
distincte : `app.command("dashboard", help="…")(DashboardCommand.cli)`). Toute
|
|
244
244
|
commande avec arguments/options **redéfinit** `cli` en `@staticmethod` typée.
|
|
245
245
|
|
|
246
246
|
- `cli/commands/_base.py` — `BaseCommand` (ABC). Cycle de vie via attributs de
|
|
247
247
|
classe surchargeables : `requires_profile` (bootstrap vs bootstrap_no_profile),
|
|
248
248
|
`require_existing`, `require_prepared`, `requires_init` (False ⇒ pas de
|
|
249
249
|
`require_initialized`, ex. `init`/`dashboard`/`doctor`), `loads_context`
|
|
250
|
-
(False ⇒ aucun contexte, ex. `
|
|
250
|
+
(False ⇒ aucun contexte, ex. `update`). `_dispatch()` fait le préambule +
|
|
251
251
|
`run()`, et enveloppe `run()` d'une **frontière `CmdError`** (échec d'une
|
|
252
252
|
commande externe `check=True` → panneau d'erreur, sortie déjà masquée).
|
|
253
253
|
Helpers : `fail(msg, code=, cause=)`, `confirm(msg, yes=)`,
|
|
@@ -295,10 +295,12 @@ Verbs (with aliases) :
|
|
|
295
295
|
| `status, stats, ps` | Container state, section by section. |
|
|
296
296
|
| `logs [service]` | `docker compose logs`. |
|
|
297
297
|
| `shell, exec <service>` | `docker exec -it` into a container of the active profile. |
|
|
298
|
-
| `
|
|
298
|
+
| `pull, sync [name...]` | `git pull --ff-only` on clones of the active profile. |
|
|
299
299
|
| `validate [profile]` | Validate YAML (Pydantic), no side effects. |
|
|
300
300
|
| `doctor` | Check Docker, Compose, git, user structure. |
|
|
301
|
-
| `
|
|
301
|
+
| `update [--check]` | Update the CLI itself (`magicbox-dk`) from PyPI. |
|
|
302
|
+
|
|
303
|
+
The root `dk --version` (`-V`) prints the current CLI version and exits (there is no `version` sub-command).
|
|
302
304
|
|
|
303
305
|
The entrypoint `dk = "cli.main:app"` is declared in `pyproject.toml`.
|
|
304
306
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: magicbox-dk
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: Magicbox for help DigitalKin developpers.
|
|
5
5
|
Author-email: Alexandre TRESALLET <a.tresall@digitalkin.ai>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,6 +41,7 @@ stack — le tout stocké hors du repo, dans le dossier de config standard de vo
|
|
|
41
41
|
- [Settings, globals & credentials](#settings-globals--credentials)
|
|
42
42
|
- [Multi-profils](#multi-profils)
|
|
43
43
|
- [Auth git](#auth-git)
|
|
44
|
+
- [Versioning & release](#versioning--release)
|
|
44
45
|
- [Dépannage](#dépannage)
|
|
45
46
|
- [License](#license)
|
|
46
47
|
|
|
@@ -304,6 +305,66 @@ Magicbox délègue l'authentification au système : configurez votre credential
|
|
|
304
305
|
|
|
305
306
|
---
|
|
306
307
|
|
|
308
|
+
## Versioning & release
|
|
309
|
+
|
|
310
|
+
Le versionnage suit **PEP 440** : `major.minor.patch` avec un pré-release `.devN` optionnel,
|
|
311
|
+
piloté par [`bump-my-version`](https://github.com/callowayproject/bump-my-version) (config dans
|
|
312
|
+
`.bumpversion.toml`). Chaque `bump` met à jour `pyproject.toml` **et** `uv.lock`, puis **commit +
|
|
313
|
+
tag** automatiquement (`commit = true`, `tag = true`).
|
|
314
|
+
|
|
315
|
+
> Le binaire Homebrew de `bump-my-version` peut être cassé (interpréteur Python obsolète) —
|
|
316
|
+
> préfixe les commandes par `uv run` pour utiliser celui du venv.
|
|
317
|
+
|
|
318
|
+
**Règle d'or** : un `.devN` est toujours un pré-release de la **prochaine** version pas encore
|
|
319
|
+
sortie (`0.0.2.dev1 < 0.0.2`). La base `major.minor.patch` ne fait que **monter** — on ne colle
|
|
320
|
+
jamais un `.dev` sur une version déjà publiée.
|
|
321
|
+
|
|
322
|
+
### Les cas
|
|
323
|
+
|
|
324
|
+
| Cas | Commande | Exemple |
|
|
325
|
+
|-----------------------------------------------|------------------------------------|-----------------------------|
|
|
326
|
+
| **Ouvrir un cycle dev** (depuis une finale) | `bump patch` \| `minor` \| `major` | `0.0.1` → `0.0.2.dev1` |
|
|
327
|
+
| **Itérer en dev** | `bump dev` | `0.0.2.dev1` → `0.0.2.dev2` |
|
|
328
|
+
| **Passer d'une dev à la release** (finaliser) | `bump --new-version X.Y.Z` | `0.0.2.dev2` → `0.0.2` |
|
|
329
|
+
|
|
330
|
+
> `bump dev` depuis une **finale** échoue (`value 0 is lower than the first value 1`) : c'est voulu
|
|
331
|
+
> (`first_value = 1`). Depuis une finale, on ouvre le cycle avec `patch`/`minor`/`major`, jamais `dev`.
|
|
332
|
+
> Et « finaliser » (retirer le `.dev`) se fait avec `--new-version`, car un compteur `.dev` ne peut
|
|
333
|
+
> pas redescendre à 0 tout seul.
|
|
334
|
+
|
|
335
|
+
### Procédure complète (pour chaque version)
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
# 1. bump : édite pyproject.toml + uv.lock, commit + tag automatiques
|
|
339
|
+
uv run bump-my-version bump patch # 0.0.1 → 0.0.2.dev1
|
|
340
|
+
|
|
341
|
+
# 2. pousse le commit ET son tag
|
|
342
|
+
git push --follow-tags origin main
|
|
343
|
+
|
|
344
|
+
# 3. crée la GitHub Release → déclenche la publication (.github/workflows/release.yml)
|
|
345
|
+
gh release create v0.0.2.dev1 --prerelease --generate-notes # --prerelease pour un .dev
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Exemple d'un cycle complet `0.0.1 → 0.0.2` :
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
uv run bump-my-version bump patch # 0.0.1 → 0.0.2.dev1
|
|
352
|
+
git push --follow-tags origin main
|
|
353
|
+
gh release create v0.0.2.dev1 --prerelease --generate-notes
|
|
354
|
+
|
|
355
|
+
uv run bump-my-version bump dev # 0.0.2.dev1 → 0.0.2.dev2
|
|
356
|
+
git push --follow-tags origin main
|
|
357
|
+
gh release create v0.0.2.dev2 --prerelease --generate-notes
|
|
358
|
+
|
|
359
|
+
uv run bump-my-version bump --new-version 0.0.2 # finalise : 0.0.2.dev2 → 0.0.2
|
|
360
|
+
git push --follow-tags origin main
|
|
361
|
+
gh release create v0.0.2 --generate-notes # release finale (sans --prerelease)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
`bump-my-version show-bump` affiche à tout moment les transitions possibles depuis la version courante.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
307
368
|
## Dépannage
|
|
308
369
|
|
|
309
370
|
| Symptôme | Remède |
|
|
@@ -24,6 +24,7 @@ stack — le tout stocké hors du repo, dans le dossier de config standard de vo
|
|
|
24
24
|
- [Settings, globals & credentials](#settings-globals--credentials)
|
|
25
25
|
- [Multi-profils](#multi-profils)
|
|
26
26
|
- [Auth git](#auth-git)
|
|
27
|
+
- [Versioning & release](#versioning--release)
|
|
27
28
|
- [Dépannage](#dépannage)
|
|
28
29
|
- [License](#license)
|
|
29
30
|
|
|
@@ -287,6 +288,66 @@ Magicbox délègue l'authentification au système : configurez votre credential
|
|
|
287
288
|
|
|
288
289
|
---
|
|
289
290
|
|
|
291
|
+
## Versioning & release
|
|
292
|
+
|
|
293
|
+
Le versionnage suit **PEP 440** : `major.minor.patch` avec un pré-release `.devN` optionnel,
|
|
294
|
+
piloté par [`bump-my-version`](https://github.com/callowayproject/bump-my-version) (config dans
|
|
295
|
+
`.bumpversion.toml`). Chaque `bump` met à jour `pyproject.toml` **et** `uv.lock`, puis **commit +
|
|
296
|
+
tag** automatiquement (`commit = true`, `tag = true`).
|
|
297
|
+
|
|
298
|
+
> Le binaire Homebrew de `bump-my-version` peut être cassé (interpréteur Python obsolète) —
|
|
299
|
+
> préfixe les commandes par `uv run` pour utiliser celui du venv.
|
|
300
|
+
|
|
301
|
+
**Règle d'or** : un `.devN` est toujours un pré-release de la **prochaine** version pas encore
|
|
302
|
+
sortie (`0.0.2.dev1 < 0.0.2`). La base `major.minor.patch` ne fait que **monter** — on ne colle
|
|
303
|
+
jamais un `.dev` sur une version déjà publiée.
|
|
304
|
+
|
|
305
|
+
### Les cas
|
|
306
|
+
|
|
307
|
+
| Cas | Commande | Exemple |
|
|
308
|
+
|-----------------------------------------------|------------------------------------|-----------------------------|
|
|
309
|
+
| **Ouvrir un cycle dev** (depuis une finale) | `bump patch` \| `minor` \| `major` | `0.0.1` → `0.0.2.dev1` |
|
|
310
|
+
| **Itérer en dev** | `bump dev` | `0.0.2.dev1` → `0.0.2.dev2` |
|
|
311
|
+
| **Passer d'une dev à la release** (finaliser) | `bump --new-version X.Y.Z` | `0.0.2.dev2` → `0.0.2` |
|
|
312
|
+
|
|
313
|
+
> `bump dev` depuis une **finale** échoue (`value 0 is lower than the first value 1`) : c'est voulu
|
|
314
|
+
> (`first_value = 1`). Depuis une finale, on ouvre le cycle avec `patch`/`minor`/`major`, jamais `dev`.
|
|
315
|
+
> Et « finaliser » (retirer le `.dev`) se fait avec `--new-version`, car un compteur `.dev` ne peut
|
|
316
|
+
> pas redescendre à 0 tout seul.
|
|
317
|
+
|
|
318
|
+
### Procédure complète (pour chaque version)
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
# 1. bump : édite pyproject.toml + uv.lock, commit + tag automatiques
|
|
322
|
+
uv run bump-my-version bump patch # 0.0.1 → 0.0.2.dev1
|
|
323
|
+
|
|
324
|
+
# 2. pousse le commit ET son tag
|
|
325
|
+
git push --follow-tags origin main
|
|
326
|
+
|
|
327
|
+
# 3. crée la GitHub Release → déclenche la publication (.github/workflows/release.yml)
|
|
328
|
+
gh release create v0.0.2.dev1 --prerelease --generate-notes # --prerelease pour un .dev
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Exemple d'un cycle complet `0.0.1 → 0.0.2` :
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
uv run bump-my-version bump patch # 0.0.1 → 0.0.2.dev1
|
|
335
|
+
git push --follow-tags origin main
|
|
336
|
+
gh release create v0.0.2.dev1 --prerelease --generate-notes
|
|
337
|
+
|
|
338
|
+
uv run bump-my-version bump dev # 0.0.2.dev1 → 0.0.2.dev2
|
|
339
|
+
git push --follow-tags origin main
|
|
340
|
+
gh release create v0.0.2.dev2 --prerelease --generate-notes
|
|
341
|
+
|
|
342
|
+
uv run bump-my-version bump --new-version 0.0.2 # finalise : 0.0.2.dev2 → 0.0.2
|
|
343
|
+
git push --follow-tags origin main
|
|
344
|
+
gh release create v0.0.2 --generate-notes # release finale (sans --prerelease)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
`bump-my-version show-bump` affiche à tout moment les transitions possibles depuis la version courante.
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
290
351
|
## Dépannage
|
|
291
352
|
|
|
292
353
|
| Symptôme | Remède |
|
|
@@ -21,6 +21,7 @@ est délégué à :class:`cli.ui.StepReporter` exposé via ``self.steps``.
|
|
|
21
21
|
from __future__ import annotations
|
|
22
22
|
|
|
23
23
|
import itertools
|
|
24
|
+
import sys
|
|
24
25
|
import threading
|
|
25
26
|
import time
|
|
26
27
|
from abc import ABC, abstractmethod
|
|
@@ -32,6 +33,7 @@ from typing import Annotated, Any, NoReturn, TypeVar
|
|
|
32
33
|
import questionary
|
|
33
34
|
import typer
|
|
34
35
|
|
|
36
|
+
from cli import version_check
|
|
35
37
|
from cli.core.cmd import bootstrap, bootstrap_no_profile, resolve_target
|
|
36
38
|
from cli.core.context import MagicboxContext
|
|
37
39
|
from cli.debug import dlog, set_debug, set_verbose
|
|
@@ -77,6 +79,10 @@ class BaseCommand(ABC):
|
|
|
77
79
|
#: commandes « profil courant » (``start``/``edit``/``prepare``…) gardent
|
|
78
80
|
#: ``False`` (défaut → profil actif, pas de prompt).
|
|
79
81
|
picks_profile: bool = False
|
|
82
|
+
#: ``True`` ⇒ affiche (sur stderr, TTY uniquement) une ligne d'info si une
|
|
83
|
+
#: version plus récente est publiée sur PyPI. Désactivé sur ``version`` (qui
|
|
84
|
+
#: l'affiche à sa façon) et ``update`` (c'est déjà la mise à jour du CLI).
|
|
85
|
+
notifies_upgrade: bool = True
|
|
80
86
|
|
|
81
87
|
def __init__(
|
|
82
88
|
self, profile: str | None = None, *,
|
|
@@ -119,6 +125,13 @@ class BaseCommand(ABC):
|
|
|
119
125
|
# Verbose déroule le détail des étapes (cf. ``-v/--verbose``) — posé avant
|
|
120
126
|
# tout pour couvrir aussi le préambule. ``set_debug`` est géré par bootstrap.
|
|
121
127
|
set_verbose(self.verbose)
|
|
128
|
+
# Vérif de version : uniquement en terminal interactif (jamais en
|
|
129
|
+
# script/CI/pipe). Le rafraîchissement du cache est lancé en tâche de
|
|
130
|
+
# fond ici (max de temps pour finir pendant `run`) ; la notice, lue au
|
|
131
|
+
# cache, est affichée après un `run` réussi.
|
|
132
|
+
notify_upgrade = self.notifies_upgrade and sys.stderr.isatty()
|
|
133
|
+
if notify_upgrade:
|
|
134
|
+
version_check.trigger_background_refresh()
|
|
122
135
|
if self.requires_profile:
|
|
123
136
|
self.ctx, self.profile_id = bootstrap(
|
|
124
137
|
self.profile_name,
|
|
@@ -140,6 +153,10 @@ class BaseCommand(ABC):
|
|
|
140
153
|
|
|
141
154
|
try:
|
|
142
155
|
self.run()
|
|
156
|
+
if notify_upgrade:
|
|
157
|
+
notice = version_check.notice_if_outdated()
|
|
158
|
+
if notice:
|
|
159
|
+
typer.secho(notice, fg=typer.colors.YELLOW, err=True)
|
|
143
160
|
except CmdError as exc:
|
|
144
161
|
# Échec d'une commande externe en mode ``check=True`` (git/docker).
|
|
145
162
|
# ``exc.output`` est déjà masqué des secrets par le runner.
|
|
@@ -14,9 +14,9 @@ import typer
|
|
|
14
14
|
import yaml
|
|
15
15
|
|
|
16
16
|
from cli.commands._base import BaseCommand
|
|
17
|
-
from cli.commands.version import package_version
|
|
18
17
|
from cli.core.context import MagicboxContext
|
|
19
18
|
from cli.ui import GREY_FG, Report, short_home_path
|
|
19
|
+
from cli.version_check import current_version
|
|
20
20
|
|
|
21
21
|
# Sous-commandes mises en avant dans le mémo de démarrage (verbe → résumé).
|
|
22
22
|
QUICK_COMMANDS: tuple[tuple[str, str], ...] = (
|
|
@@ -42,7 +42,7 @@ class DashboardCommand(BaseCommand):
|
|
|
42
42
|
# ── En-tête : titre + description ─────────────────────────────────── #
|
|
43
43
|
r.blank()
|
|
44
44
|
title = typer.style("Magicbox", fg=typer.colors.CYAN, bold=True)
|
|
45
|
-
ver = typer.style(f"v{
|
|
45
|
+
ver = typer.style(f"v{current_version()}", fg=GREY_FG)
|
|
46
46
|
typer.echo(f" {title} · {ver}")
|
|
47
47
|
r.detail(
|
|
48
48
|
"Orchestrateur d'environnements de dev pour les services & archetypes DigitalKin.",
|
|
@@ -46,7 +46,9 @@ from cli.compose import (
|
|
|
46
46
|
generate_horizon_compose,
|
|
47
47
|
generate_node_compose,
|
|
48
48
|
generate_nsp_compose,
|
|
49
|
+
plan_build,
|
|
49
50
|
report_compose_failure,
|
|
51
|
+
save_manifest,
|
|
50
52
|
)
|
|
51
53
|
from cli.compose.network import (
|
|
52
54
|
AllocatedPorts,
|
|
@@ -272,6 +274,7 @@ class PrepareCommand(StepCommand):
|
|
|
272
274
|
self.project = self.ctx.compose_project(self.profile_id)
|
|
273
275
|
self.repos_dir = self.ctx.profile_repos_dir(self.profile_id)
|
|
274
276
|
self.overrides_dir = self.ctx.profile_overrides_dir(self.profile_id)
|
|
277
|
+
self.manifest_path = self.ctx.profile_build_manifest(self.profile_id)
|
|
275
278
|
self.env_dir = self.ctx.profile_env_dir(self.profile_id)
|
|
276
279
|
self.network_path = self.ctx.profile_network_yaml(self.profile_id)
|
|
277
280
|
self.settings_ports = self.ctx.settings.ports
|
|
@@ -290,6 +293,7 @@ class PrepareCommand(StepCommand):
|
|
|
290
293
|
self.infra_vars: dict[str, str] = {}
|
|
291
294
|
self.build_failed = False
|
|
292
295
|
self.build_result: Any = None
|
|
296
|
+
self.build_plan: Any = None # cli.compose.BuildPlan | None (rempli au build)
|
|
293
297
|
|
|
294
298
|
self.steps.section(f"Profil : {self.ctx.profile_name(self.profile_id)}")
|
|
295
299
|
|
|
@@ -816,11 +820,36 @@ class PrepareCommand(StepCommand):
|
|
|
816
820
|
def prebuild_images(self) -> None:
|
|
817
821
|
files, profiles = compose_args_for(self.profile, self.overrides_dir)
|
|
818
822
|
build_env = compute_compose_env(self.ctx, self.profile, self.profile_id)
|
|
823
|
+
# Rebuild incrémental : on ne (re)construit que les images dont un input
|
|
824
|
+
# de build a changé (build args, HEAD du dépôt, Dockerfile, image
|
|
825
|
+
# absente, contexte dev dirty). Cf. `cli.compose.build_state`. Le calcul
|
|
826
|
+
# du plan lit `docker compose config` → sous le même env que le build.
|
|
827
|
+
with compose_env_context(build_env):
|
|
828
|
+
plan = plan_build(
|
|
829
|
+
self.project, files, profiles, self.manifest_path, force=self.force,
|
|
830
|
+
)
|
|
831
|
+
self.build_plan = plan
|
|
832
|
+
|
|
833
|
+
if plan.nothing_to_do:
|
|
834
|
+
# Toutes les images sont à jour : aucun `docker compose build` lancé.
|
|
835
|
+
self.steps.set_activity("images à jour — aucun rebuild")
|
|
836
|
+
return
|
|
837
|
+
|
|
838
|
+
if plan.degraded:
|
|
839
|
+
# Config compose illisible : repli sûr = tout reconstruire.
|
|
840
|
+
services: list[str] = []
|
|
841
|
+
else:
|
|
842
|
+
services = plan.to_build
|
|
843
|
+
self.steps.set_activity(
|
|
844
|
+
f"reconstruction de {len(services)} image(s) : {', '.join(services)}",
|
|
845
|
+
)
|
|
846
|
+
|
|
819
847
|
# Le viewer affiche la progression BuildKit + un rappel de touche, et
|
|
820
848
|
# permet d'expand/collapse la sortie Docker complète (touche ``o``/espace).
|
|
821
849
|
with compose_env_context(build_env), _BuildOutputViewer(self.steps) as viewer:
|
|
822
850
|
result = docker.compose_build(
|
|
823
851
|
self.project, files, profiles,
|
|
852
|
+
services=services,
|
|
824
853
|
no_cache=self.force,
|
|
825
854
|
on_progress=viewer.feed_progress,
|
|
826
855
|
on_output=viewer.feed_output,
|
|
@@ -831,6 +860,10 @@ class PrepareCommand(StepCommand):
|
|
|
831
860
|
# l'échec et ``finish()`` affiche l'extrait borné hors panneau.
|
|
832
861
|
self.build_failed = True
|
|
833
862
|
self.build_result = result
|
|
863
|
+
elif not plan.degraded:
|
|
864
|
+
# Build réussi : on fige les signatures courantes (celles des services
|
|
865
|
+
# skippés matchent déjà, celles des reconstruits sont désormais à jour).
|
|
866
|
+
save_manifest(self.manifest_path, plan.signatures)
|
|
834
867
|
|
|
835
868
|
# ── Panneau final ────────────────────────────────────────────────────── #
|
|
836
869
|
|
|
@@ -848,7 +881,25 @@ class PrepareCommand(StepCommand):
|
|
|
848
881
|
"`dk start` re-tentera le build au démarrage",
|
|
849
882
|
)
|
|
850
883
|
else:
|
|
851
|
-
|
|
884
|
+
detail = "\n".join(
|
|
885
|
+
d for d in ("Étape suivante : dk start", self._build_summary()) if d
|
|
886
|
+
)
|
|
887
|
+
self.steps.panel_ok(f"Profil « {label} » préparé", detail)
|
|
888
|
+
|
|
889
|
+
def _build_summary(self) -> str | None:
|
|
890
|
+
"""Résumé du rebuild incrémental (images reconstruites vs à jour)."""
|
|
891
|
+
plan = self.build_plan
|
|
892
|
+
if plan is None or self.no_build:
|
|
893
|
+
return None
|
|
894
|
+
if plan.degraded:
|
|
895
|
+
return "Build : plan incrémental indisponible — toutes les images (re)construites."
|
|
896
|
+
if not plan.to_build:
|
|
897
|
+
return f"Build : {len(plan.skipped)} image(s) déjà à jour — aucun rebuild."
|
|
898
|
+
built = ", ".join(plan.to_build)
|
|
899
|
+
line = f"Build : {len(plan.to_build)} image(s) reconstruite(s) ({built})"
|
|
900
|
+
if plan.skipped:
|
|
901
|
+
line += f" · {len(plan.skipped)} à jour (skip)"
|
|
902
|
+
return line
|
|
852
903
|
|
|
853
904
|
# ── Helpers (tout dans la classe) ────────────────────────────────────── #
|
|
854
905
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""dk
|
|
1
|
+
"""dk pull — git pull --ff-only sur les clones du profil actif."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -15,7 +15,7 @@ from cli.models.profile import runnable_entries
|
|
|
15
15
|
from cli.runner import git
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class
|
|
18
|
+
class PullCommand(StepCommand):
|
|
19
19
|
"""git pull --ff-only sur les clones du profil actif.
|
|
20
20
|
|
|
21
21
|
Chaque clone est mis à jour comme une étape numérotée ``[i/N] <repo>`` sous
|
|
@@ -23,7 +23,7 @@ class UpdateCommand(StepCommand):
|
|
|
23
23
|
est capturé en mode collapse, déroulé en verbose/non-TTY.
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
|
-
command_label = "
|
|
26
|
+
command_label = "Récupération des dépôts (git pull)"
|
|
27
27
|
|
|
28
28
|
def __init__(
|
|
29
29
|
self, names: list[str] | None = None, *,
|
|
@@ -93,4 +93,4 @@ class UpdateCommand(StepCommand):
|
|
|
93
93
|
] = False,
|
|
94
94
|
) -> None:
|
|
95
95
|
"""git pull --ff-only sur les clones du profil actif."""
|
|
96
|
-
|
|
96
|
+
PullCommand(names, debug=debug, verbose=verbose)._dispatch()
|
|
@@ -435,10 +435,11 @@ class StartCommand(StepCommand):
|
|
|
435
435
|
la progression (lancement puis état par service) alimente le panneau Live
|
|
436
436
|
de la commande (``set_activity`` / ``set_detail``).
|
|
437
437
|
"""
|
|
438
|
-
# Budget santé = valeur LIVE des settings (``timeouts.health_wait_s``)
|
|
439
|
-
#
|
|
440
|
-
# le
|
|
441
|
-
#
|
|
438
|
+
# Budget santé = valeur LIVE des settings (``timeouts.health_wait_s``).
|
|
439
|
+
# ``started_at`` (avant le ``compose up``) ancre le **plafond global**
|
|
440
|
+
# tant que le frontend n'est pas healthy. Le **décompte de skip** affiché
|
|
441
|
+
# en phase 2 est, lui, ré-ancré à l'instant où le front devient healthy et
|
|
442
|
+
# part donc de ``health_wait_s`` plein (cf. ``wait_until_healthy``).
|
|
442
443
|
started_at = time.monotonic()
|
|
443
444
|
health_timeout = self.ctx.settings.timeouts.health_wait_s
|
|
444
445
|
if is_debug():
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""dk update — met à jour le package ``magicbox-dk`` depuis PyPI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
from importlib.metadata import distribution
|
|
10
|
+
from typing import Annotated
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
|
|
14
|
+
from cli.commands._base import BaseCommand
|
|
15
|
+
from cli.ui import spinner
|
|
16
|
+
from cli.version_check import PACKAGE, current_version, fetch_latest
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _is_editable_install() -> bool:
|
|
20
|
+
"""Vrai si ``magicbox-dk`` est installé en mode éditable (``pip install -e``).
|
|
21
|
+
|
|
22
|
+
On lit ``direct_url.json`` (PEP 610) de la distribution : les installs
|
|
23
|
+
éditables portent ``dir_info.editable = true``. Sert à **refuser** l'upgrade
|
|
24
|
+
dans un checkout de dev — sinon un ``pip install --upgrade`` remplacerait le
|
|
25
|
+
lien éditable par la release PyPI et casserait l'environnement de travail.
|
|
26
|
+
"""
|
|
27
|
+
try:
|
|
28
|
+
raw = distribution(PACKAGE).read_text("direct_url.json")
|
|
29
|
+
if not raw:
|
|
30
|
+
return False
|
|
31
|
+
return bool(json.loads(raw).get("dir_info", {}).get("editable"))
|
|
32
|
+
except (OSError, ValueError, ImportError):
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _upgrade_argv() -> tuple[list[str], str]:
|
|
37
|
+
"""``(argv, méthode)`` pour mettre à jour selon le mode d'installation.
|
|
38
|
+
|
|
39
|
+
Détecte pipx / uv-tool via le préfixe d'environnement (ces gestionnaires
|
|
40
|
+
isolent le CLI dans un venv dédié où ``pip install`` ne conviendrait pas) ;
|
|
41
|
+
sinon retombe sur ``python -m pip install --upgrade`` de l'interpréteur
|
|
42
|
+
courant (cas pip / venv classique).
|
|
43
|
+
"""
|
|
44
|
+
prefix = sys.prefix.replace("\\", "/").lower()
|
|
45
|
+
pipx = shutil.which("pipx")
|
|
46
|
+
if "/pipx/" in prefix and pipx:
|
|
47
|
+
return [pipx, "upgrade", PACKAGE], "pipx"
|
|
48
|
+
uv = shutil.which("uv")
|
|
49
|
+
if "/uv/tools/" in prefix and uv:
|
|
50
|
+
return [uv, "tool", "upgrade", PACKAGE], "uv tool"
|
|
51
|
+
return [sys.executable, "-m", "pip", "install", "--upgrade", PACKAGE], "pip"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class UpdateCommand(BaseCommand):
|
|
55
|
+
"""Met à jour Magicbox vers la dernière version publiée sur PyPI."""
|
|
56
|
+
|
|
57
|
+
requires_profile = False
|
|
58
|
+
requires_init = False
|
|
59
|
+
loads_context = False
|
|
60
|
+
notifies_upgrade = False # c'est déjà la commande de mise à jour
|
|
61
|
+
|
|
62
|
+
def __init__(self, *, check: bool = False, debug: bool = False) -> None:
|
|
63
|
+
super().__init__(debug=debug)
|
|
64
|
+
self.check = check
|
|
65
|
+
|
|
66
|
+
def run(self) -> None:
|
|
67
|
+
current = current_version()
|
|
68
|
+
self.steps.section(f"Magicbox {current}")
|
|
69
|
+
|
|
70
|
+
with spinner("Recherche d'une version plus récente sur PyPI…"):
|
|
71
|
+
latest = fetch_latest()
|
|
72
|
+
if latest is None:
|
|
73
|
+
self.steps.warn("Impossible de contacter PyPI — réessaie plus tard.")
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
if not self._is_newer(current, latest):
|
|
77
|
+
self.steps.ok(f"déjà à jour (dernière version : {latest})")
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
self.steps.info(f"version {latest} disponible (installée : {current})")
|
|
81
|
+
if self.check:
|
|
82
|
+
self.steps.info("lance `dk update` (sans `--check`) pour l'installer")
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
if _is_editable_install():
|
|
86
|
+
self.steps.warn(
|
|
87
|
+
"Installation éditable (dépôt de dev) détectée — upgrade désactivé "
|
|
88
|
+
"pour ne pas écraser ton checkout.",
|
|
89
|
+
"Mets à jour via `git pull` dans le dépôt.",
|
|
90
|
+
)
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
argv, method = _upgrade_argv()
|
|
94
|
+
self.steps.info(f"mise à jour via {method}…")
|
|
95
|
+
# Sortie de l'installeur héritée directement (progression pip/uv en direct).
|
|
96
|
+
result = subprocess.run(argv, check=False) # noqa: S603 (argv construit en interne)
|
|
97
|
+
if result.returncode == 0:
|
|
98
|
+
self.steps.panel_ok(
|
|
99
|
+
f"Magicbox mis à jour vers {latest}",
|
|
100
|
+
"relance une commande `dk` pour utiliser la nouvelle version",
|
|
101
|
+
)
|
|
102
|
+
else:
|
|
103
|
+
self.fail(
|
|
104
|
+
f"Échec de la mise à jour (code {result.returncode}). "
|
|
105
|
+
f"Essaie manuellement : {' '.join(argv)}",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def _is_newer(current: str, latest: str) -> bool:
|
|
110
|
+
"""Vrai si ``latest`` est strictement plus récent que ``current`` (PEP 440).
|
|
111
|
+
|
|
112
|
+
Sans ``packaging`` ou avec une version courante non standard (``dev`` /
|
|
113
|
+
install source), on renvoie ``True`` par défaut : l'utilisateur a lancé
|
|
114
|
+
``dk update`` explicitement, on ne le bloque pas sur une comparaison
|
|
115
|
+
impossible (le garde-fou install-éditable protège déjà le cas dev).
|
|
116
|
+
"""
|
|
117
|
+
if current == latest:
|
|
118
|
+
return False
|
|
119
|
+
try:
|
|
120
|
+
from packaging.version import InvalidVersion, Version
|
|
121
|
+
except ImportError:
|
|
122
|
+
return True
|
|
123
|
+
try:
|
|
124
|
+
return Version(latest) > Version(current)
|
|
125
|
+
except InvalidVersion:
|
|
126
|
+
return True
|
|
127
|
+
|
|
128
|
+
@staticmethod
|
|
129
|
+
def cli(
|
|
130
|
+
check: Annotated[
|
|
131
|
+
bool,
|
|
132
|
+
typer.Option("--check", help="Vérifie seulement (sans installer) s'il y a une mise à jour."),
|
|
133
|
+
] = False,
|
|
134
|
+
debug: Annotated[
|
|
135
|
+
bool,
|
|
136
|
+
typer.Option("--debug", "-d", help="Logs détaillés."),
|
|
137
|
+
] = False,
|
|
138
|
+
) -> None:
|
|
139
|
+
"""Met à jour Magicbox vers la dernière version publiée sur PyPI."""
|
|
140
|
+
UpdateCommand(check=check, debug=debug)._dispatch()
|
|
@@ -23,6 +23,12 @@ le port pré-alloué par ``dk prepare`` : ils ne consultent plus les endpoints.
|
|
|
23
23
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
|
+
# ── Rebuild incrémental des images ──────────────────────────────────────────── #
|
|
27
|
+
from cli.compose.build_state import (
|
|
28
|
+
BuildPlan,
|
|
29
|
+
plan_build,
|
|
30
|
+
save_manifest,
|
|
31
|
+
)
|
|
26
32
|
# ── Builder (génération d'overrides) ────────────────────────────────────────── #
|
|
27
33
|
from cli.compose.builder import (
|
|
28
34
|
generate_back_compose,
|
|
@@ -63,6 +69,7 @@ from cli.compose.runtime import (
|
|
|
63
69
|
)
|
|
64
70
|
|
|
65
71
|
__all__ = [
|
|
72
|
+
"BuildPlan",
|
|
66
73
|
"RESTART_LIMIT",
|
|
67
74
|
"allocate_back_port",
|
|
68
75
|
"allocate_back_worker_port",
|
|
@@ -88,8 +95,10 @@ __all__ = [
|
|
|
88
95
|
"generate_nsp_compose",
|
|
89
96
|
"magicbox_container_publishing",
|
|
90
97
|
"magicbox_orphan_resources",
|
|
98
|
+
"plan_build",
|
|
91
99
|
"project_built_images",
|
|
92
100
|
"report_compose_failure",
|
|
93
101
|
"running_compose_projects",
|
|
102
|
+
"save_manifest",
|
|
94
103
|
"wait_until_healthy",
|
|
95
104
|
]
|