doover-cli 0.4.1__tar.gz → 0.4.2__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.
- {doover_cli-0.4.1 → doover_cli-0.4.2}/PKG-INFO +1 -1
- {doover_cli-0.4.1 → doover_cli-0.4.2}/pyproject.toml +1 -1
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/apps/apps.py +25 -1
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/apps.py +14 -10
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_apps.py +8 -9
- {doover_cli-0.4.1 → doover_cli-0.4.2}/uv.lock +1 -1
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.github/CONTRIBUTING.md +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.github/workflows/lint-test.yml +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.github/workflows/release-brew.yml +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.github/workflows/release-pypi.yml +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.github/workflows/release.yml +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.gitignore +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/.pre-commit-config.yaml +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/AGENT.md +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/LICENSE +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/README.md +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/debian/changelog +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/debian/control +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/debian/rules +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/docs/user_stories.md +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/__init__.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/agent.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/api/__init__.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/api/auth.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/api/errors.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/api/session.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/apps/app_install.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/apps/device.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/apps/device_type.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/apps/tunnel.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/channel.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/colours.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/config_schema.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/dda_logs.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/doover_config.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/grpc.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/login.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/renderer/__init__.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/renderer/_base.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/renderer/_basic.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/renderer/_default.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/renderer/_json.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/report.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/simulator.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/ui_schema.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/user.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/__init__.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/api.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/context.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/crud/__init__.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/crud/commands.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/crud/lookup.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/crud/prompting.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/crud/schema.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/crud/values.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/errors.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/formatters.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/misc.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/parsers.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/prompt.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/sentry.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/shell_commands.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/src/doover_cli/utils/state.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/__init__.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/conftest.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_agent.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_app_install.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_auth_integration.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_auth_unit.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_basic.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_crud_commands.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_crud_lookup.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_crud_prompting.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_crud_schema.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_crud_values.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_default_renderer.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_device.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_device_cli_integration.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_device_type.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_device_type_cli_integration.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_prompt.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_sentry.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_user.py +0 -0
- {doover_cli-0.4.1 → doover_cli-0.4.2}/tests/test_utils_apps.py +0 -0
|
@@ -104,6 +104,21 @@ def _resolve_staging(staging: bool | None) -> bool:
|
|
|
104
104
|
return ".staging." in _control_base_url()
|
|
105
105
|
|
|
106
106
|
|
|
107
|
+
def _detect_git_commit(root_fp: Path) -> str:
|
|
108
|
+
"""Best-effort current git commit SHA for the app dir (empty if unavailable)."""
|
|
109
|
+
try:
|
|
110
|
+
result = subprocess.run(
|
|
111
|
+
["git", "rev-parse", "HEAD"],
|
|
112
|
+
cwd=root_fp,
|
|
113
|
+
capture_output=True,
|
|
114
|
+
text=True,
|
|
115
|
+
check=False,
|
|
116
|
+
)
|
|
117
|
+
except OSError:
|
|
118
|
+
return ""
|
|
119
|
+
return result.stdout.strip() if result.returncode == 0 else ""
|
|
120
|
+
|
|
121
|
+
|
|
107
122
|
def _build_container(
|
|
108
123
|
root_fp: Path, *, buildx: bool, build_args: str, image_name: str
|
|
109
124
|
) -> None:
|
|
@@ -1087,7 +1102,13 @@ def release(
|
|
|
1087
1102
|
] = None,
|
|
1088
1103
|
tag: Annotated[
|
|
1089
1104
|
str | None,
|
|
1090
|
-
typer.Option(help="Optional version label (e.g.
|
|
1105
|
+
typer.Option(help="Optional version label (e.g. semver / image tag)."),
|
|
1106
|
+
] = None,
|
|
1107
|
+
commit: Annotated[
|
|
1108
|
+
str | None,
|
|
1109
|
+
typer.Option(
|
|
1110
|
+
help="Source git commit SHA (for browsing the code). Defaults to the repo's HEAD."
|
|
1111
|
+
),
|
|
1091
1112
|
] = None,
|
|
1092
1113
|
notes: Annotated[str, typer.Option(help="Optional release notes.")] = "",
|
|
1093
1114
|
staging: Annotated[
|
|
@@ -1124,12 +1145,15 @@ def release(
|
|
|
1124
1145
|
)
|
|
1125
1146
|
raise typer.Exit(1)
|
|
1126
1147
|
|
|
1148
|
+
resolved_commit = commit if commit is not None else _detect_git_commit(root_fp)
|
|
1149
|
+
|
|
1127
1150
|
client, renderer = get_state()
|
|
1128
1151
|
with renderer.loading("Creating application version..."):
|
|
1129
1152
|
version = client.create_application_version(
|
|
1130
1153
|
application_id,
|
|
1131
1154
|
digest=digest,
|
|
1132
1155
|
tag=tag or "",
|
|
1156
|
+
commit=resolved_commit or "",
|
|
1133
1157
|
notes=notes or "",
|
|
1134
1158
|
)
|
|
1135
1159
|
rich.print("[green]Released a new application version.[/green]")
|
|
@@ -306,16 +306,20 @@ def get_app_directory(root: Path | None = None) -> Path:
|
|
|
306
306
|
|
|
307
307
|
|
|
308
308
|
def get_uv_path() -> Path:
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
)
|
|
318
|
-
|
|
309
|
+
# Prefer uv on PATH (covers CI where uv is installed to a tool cache dir),
|
|
310
|
+
# then common fixed locations.
|
|
311
|
+
found = shutil.which("uv")
|
|
312
|
+
if found:
|
|
313
|
+
return Path(found)
|
|
314
|
+
|
|
315
|
+
for candidate in (
|
|
316
|
+
Path("/opt/homebrew/bin/uv"),
|
|
317
|
+
Path.home() / ".local" / "bin" / "uv",
|
|
318
|
+
):
|
|
319
|
+
if candidate.exists():
|
|
320
|
+
return candidate
|
|
321
|
+
|
|
322
|
+
raise RuntimeError("uv not found in your PATH. Please install it and try again.")
|
|
319
323
|
|
|
320
324
|
|
|
321
325
|
def call_with_uv(
|
|
@@ -662,7 +662,9 @@ def test_app_publish_processor_type_without_ui_skips_ui_export(monkeypatch, tmp_
|
|
|
662
662
|
assert "export_ui_called" not in captured
|
|
663
663
|
assert captured["build_script"] == ("./build.sh", tmp_path)
|
|
664
664
|
assert captured["processor_source"] == ("303", {"file": package_fp})
|
|
665
|
-
|
|
665
|
+
# publish uploads the package but no longer cuts a version (that's `release`)
|
|
666
|
+
assert "processor_version" not in captured
|
|
667
|
+
assert renderer.render_calls == [{"id": 303}]
|
|
666
668
|
|
|
667
669
|
|
|
668
670
|
def test_app_publish_skips_ui_export_when_config_disables_generation(
|
|
@@ -769,9 +771,7 @@ def test_app_publish_honours_explicit_staging(monkeypatch, tmp_path):
|
|
|
769
771
|
lambda ctx, app_fp, validate_: None,
|
|
770
772
|
)
|
|
771
773
|
|
|
772
|
-
result = runner.invoke(
|
|
773
|
-
app, ["app", "publish", str(tmp_path), "--staging"]
|
|
774
|
-
)
|
|
774
|
+
result = runner.invoke(app, ["app", "publish", str(tmp_path), "--staging"])
|
|
775
775
|
|
|
776
776
|
assert result.exit_code == 0
|
|
777
777
|
assert captured["body"]["deployment_data"] == "staging-data"
|
|
@@ -872,9 +872,7 @@ def test_app_publish_skips_build_when_requested_by_config(monkeypatch, tmp_path)
|
|
|
872
872
|
assert renderer.render_calls == [{"id": 101}]
|
|
873
873
|
|
|
874
874
|
|
|
875
|
-
def
|
|
876
|
-
monkeypatch, tmp_path
|
|
877
|
-
):
|
|
875
|
+
def test_app_publish_processor_builds_package_without_release(monkeypatch, tmp_path):
|
|
878
876
|
captured = {}
|
|
879
877
|
renderer = FakeRenderer()
|
|
880
878
|
app_config = FakeAppConfig(app_id=303)
|
|
@@ -938,10 +936,11 @@ def test_app_publish_processor_builds_package_and_releases_version(
|
|
|
938
936
|
assert captured["build_script"] == ("./build.sh", tmp_path)
|
|
939
937
|
assert captured["application_id"] == "303"
|
|
940
938
|
assert captured["body"] == {"file": package_fp}
|
|
941
|
-
|
|
939
|
+
# publish uploads the package; the version is cut by `doover app release`
|
|
940
|
+
assert "version" not in captured
|
|
942
941
|
assert "build_called" not in captured
|
|
943
942
|
assert "push_called" not in captured
|
|
944
|
-
assert renderer.render_calls == [{"id": 303
|
|
943
|
+
assert renderer.render_calls == [{"id": 303}]
|
|
945
944
|
|
|
946
945
|
|
|
947
946
|
def test_publish_processor_package_uses_package_zip(tmp_path):
|
|
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
|
|
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
|