doover-cli 0.6.2__tar.gz → 0.6.4__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 (91) hide show
  1. {doover_cli-0.6.2 → doover_cli-0.6.4}/PKG-INFO +1 -1
  2. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/__init__.py +1 -1
  3. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/apps/apps.py +42 -12
  4. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/config_schema.py +6 -3
  5. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/ui_schema.py +6 -3
  6. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/apps.py +23 -0
  7. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_apps.py +2 -2
  8. {doover_cli-0.6.2 → doover_cli-0.6.4}/.github/CONTRIBUTING.md +0 -0
  9. {doover_cli-0.6.2 → doover_cli-0.6.4}/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -0
  10. {doover_cli-0.6.2 → doover_cli-0.6.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  11. {doover_cli-0.6.2 → doover_cli-0.6.4}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  12. {doover_cli-0.6.2 → doover_cli-0.6.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  13. {doover_cli-0.6.2 → doover_cli-0.6.4}/.github/workflows/lint-test.yml +0 -0
  14. {doover_cli-0.6.2 → doover_cli-0.6.4}/.github/workflows/release-brew.yml +0 -0
  15. {doover_cli-0.6.2 → doover_cli-0.6.4}/.github/workflows/release-pypi.yml +0 -0
  16. {doover_cli-0.6.2 → doover_cli-0.6.4}/.github/workflows/release.yml +0 -0
  17. {doover_cli-0.6.2 → doover_cli-0.6.4}/.gitignore +0 -0
  18. {doover_cli-0.6.2 → doover_cli-0.6.4}/.pre-commit-config.yaml +0 -0
  19. {doover_cli-0.6.2 → doover_cli-0.6.4}/AGENT.md +0 -0
  20. {doover_cli-0.6.2 → doover_cli-0.6.4}/LICENSE +0 -0
  21. {doover_cli-0.6.2 → doover_cli-0.6.4}/README.md +0 -0
  22. {doover_cli-0.6.2 → doover_cli-0.6.4}/debian/changelog +0 -0
  23. {doover_cli-0.6.2 → doover_cli-0.6.4}/debian/control +0 -0
  24. {doover_cli-0.6.2 → doover_cli-0.6.4}/debian/rules +0 -0
  25. {doover_cli-0.6.2 → doover_cli-0.6.4}/docs/user_stories.md +0 -0
  26. {doover_cli-0.6.2 → doover_cli-0.6.4}/pyproject.toml +0 -0
  27. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/agent.py +0 -0
  28. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/api/__init__.py +0 -0
  29. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/api/auth.py +0 -0
  30. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/api/errors.py +0 -0
  31. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/api/session.py +0 -0
  32. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/apps/app_install.py +0 -0
  33. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/apps/device.py +0 -0
  34. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/apps/device_type.py +0 -0
  35. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/apps/tunnel.py +0 -0
  36. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/channel.py +0 -0
  37. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/colours.py +0 -0
  38. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/dda_logs.py +0 -0
  39. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/doover_config.py +0 -0
  40. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/grpc.py +0 -0
  41. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/login.py +0 -0
  42. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/registry.py +0 -0
  43. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/renderer/__init__.py +0 -0
  44. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/renderer/_base.py +0 -0
  45. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/renderer/_basic.py +0 -0
  46. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/renderer/_default.py +0 -0
  47. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/renderer/_json.py +0 -0
  48. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/report.py +0 -0
  49. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/simulator.py +0 -0
  50. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/user.py +0 -0
  51. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/__init__.py +0 -0
  52. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/api.py +0 -0
  53. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/context.py +0 -0
  54. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/crud/__init__.py +0 -0
  55. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/crud/commands.py +0 -0
  56. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/crud/lookup.py +0 -0
  57. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/crud/prompting.py +0 -0
  58. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/crud/schema.py +0 -0
  59. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/crud/values.py +0 -0
  60. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/errors.py +0 -0
  61. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/formatters.py +0 -0
  62. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/misc.py +0 -0
  63. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/parsers.py +0 -0
  64. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/prompt.py +0 -0
  65. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/sentry.py +0 -0
  66. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/shell_commands.py +0 -0
  67. {doover_cli-0.6.2 → doover_cli-0.6.4}/src/doover_cli/utils/state.py +0 -0
  68. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/__init__.py +0 -0
  69. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/conftest.py +0 -0
  70. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_agent.py +0 -0
  71. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_app_install.py +0 -0
  72. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_auth_integration.py +0 -0
  73. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_auth_unit.py +0 -0
  74. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_basic.py +0 -0
  75. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_crud_commands.py +0 -0
  76. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_crud_lookup.py +0 -0
  77. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_crud_prompting.py +0 -0
  78. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_crud_schema.py +0 -0
  79. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_crud_values.py +0 -0
  80. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_default_renderer.py +0 -0
  81. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_device.py +0 -0
  82. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_device_cli_integration.py +0 -0
  83. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_device_type.py +0 -0
  84. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_device_type_cli_integration.py +0 -0
  85. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_discover.py +0 -0
  86. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_prompt.py +0 -0
  87. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_registry.py +0 -0
  88. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_sentry.py +0 -0
  89. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_user.py +0 -0
  90. {doover_cli-0.6.2 → doover_cli-0.6.4}/tests/test_utils_apps.py +0 -0
  91. {doover_cli-0.6.2 → doover_cli-0.6.4}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: doover-cli
3
- Version: 0.6.2
3
+ Version: 0.6.4
4
4
  Summary: CLI for Doover
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.11
@@ -1,7 +1,7 @@
1
1
  from doover_cli.renderer import Renderer
2
2
  from typing import Annotated, Optional
3
3
 
4
- __version__ = "0.6.2"
4
+ __version__ = "0.6.4"
5
5
 
6
6
  import click
7
7
  import typer
@@ -299,6 +299,21 @@ def _resolve_application_id(client, app_config, *, staging: bool) -> int | None:
299
299
  return None
300
300
 
301
301
 
302
+ def _image_package_uri(app_config) -> str | None:
303
+ """The ECR image a processor deploys from, or None if it ships a package.zip.
304
+
305
+ A processor whose dependencies cannot fit Lambda's 250MB unzipped zip limit declares
306
+ `PackageType: "Image"` in `lambda_config` and names an image instead. Such an app has
307
+ no source archive at all, so the whole build-and-upload-a-zip path has to be skipped:
308
+ there is no ./build.sh to run, and the control plane rejects a processor_source
309
+ upload for it.
310
+ """
311
+ lambda_config = getattr(app_config, "lambda_config", None) or {}
312
+ if lambda_config.get("PackageType") != "Image":
313
+ return None
314
+ return (lambda_config.get("Code") or {}).get("ImageUri")
315
+
316
+
302
317
  def _publish_processor_package(
303
318
  client,
304
319
  app_id: int,
@@ -1172,20 +1187,32 @@ def publish(
1172
1187
  rich.print("[green]Widget uploaded.[/green]")
1173
1188
 
1174
1189
  if app_config.type in PACKAGE_APP_TYPES:
1175
- if build_package:
1176
- print("\nBuilding package.zip for upload...")
1177
- shell_run("./build.sh", cwd=root_fp)
1178
- else:
1190
+ image_uri = _image_package_uri(app_config)
1191
+ if image_uri:
1192
+ # Nothing to build or upload: the deployable is already in ECR, and the
1193
+ # release below is what points the function at it.
1179
1194
  print(
1180
- "\nSkipping package.zip build (--no-build-package); using existing package.zip."
1195
+ f"\nProcessor deploys from a container image; skipping package.zip.\n"
1196
+ f" image: {image_uri}\n"
1197
+ f"Push the image before releasing, or the release will deploy whatever "
1198
+ f"that tag currently points at."
1181
1199
  )
1182
- print("Uploading package.zip to Doover...")
1183
- processor_response = _publish_processor_package(
1184
- client,
1185
- application_id,
1186
- root_fp,
1187
- )
1188
- print("Done!")
1200
+ processor_response = None
1201
+ else:
1202
+ if build_package:
1203
+ print("\nBuilding package.zip for upload...")
1204
+ shell_run("sh ./build.sh", cwd=root_fp)
1205
+ else:
1206
+ print(
1207
+ "\nSkipping package.zip build (--no-build-package); using existing package.zip."
1208
+ )
1209
+ print("Uploading package.zip to Doover...")
1210
+ processor_response = _publish_processor_package(
1211
+ client,
1212
+ application_id,
1213
+ root_fp,
1214
+ )
1215
+ print("Done!")
1189
1216
  renderer.render(processor_response or response)
1190
1217
  if release:
1191
1218
  ctx.invoke(
@@ -1303,6 +1330,9 @@ def discover(
1303
1330
  )
1304
1331
  raise typer.Exit(1)
1305
1332
 
1333
+ for entry in found:
1334
+ entry["dir"] = os.path.normpath(os.path.join(root, entry["dir"]))
1335
+
1306
1336
  if as_json:
1307
1337
  # Compact and on one line so it can be captured straight into a step output.
1308
1338
  print(json.dumps(found, separators=(",", ":")))
@@ -8,6 +8,7 @@ import typer
8
8
  import jsf
9
9
 
10
10
  from .utils.apps import (
11
+ app_names_in_config,
11
12
  get_app_directory,
12
13
  call_with_uv,
13
14
  get_app_config,
@@ -94,10 +95,12 @@ def validate(
94
95
  config_file = root_fp / "doover_config.json"
95
96
 
96
97
  if export_ is True:
97
- # Validate the schema the Python *currently* generates, without leaving
98
- # doover_config.json modified (e.g. when run as a pre-commit hook).
98
+ targets = [app_name] if app_name else app_names_in_config(root_fp) or [None]
99
99
  with preserve_file(config_file):
100
- ctx.invoke(export, ctx, app_fp=root_fp, validate_=False, app_name=app_name)
100
+ for target in targets:
101
+ ctx.invoke(
102
+ export, ctx, app_fp=root_fp, validate_=False, app_name=target
103
+ )
101
104
  _validate_config_file(config_file)
102
105
  else:
103
106
  _validate_config_file(config_file)
@@ -7,6 +7,7 @@ import rich
7
7
  import typer
8
8
 
9
9
  from .utils.apps import (
10
+ app_names_in_config,
10
11
  get_app_directory,
11
12
  call_with_uv,
12
13
  get_app_config,
@@ -86,10 +87,12 @@ def validate(
86
87
  config_file = root_fp / "doover_config.json"
87
88
 
88
89
  if export_ is True:
89
- # Validate the schema the Python *currently* generates, without leaving
90
- # doover_config.json modified (e.g. when run as a pre-commit hook).
90
+ targets = [app_name] if app_name else app_names_in_config(root_fp) or [None]
91
91
  with preserve_file(config_file):
92
- ctx.invoke(export, ctx, app_fp=root_fp, validate_=False, app_name=app_name)
92
+ for target in targets:
93
+ ctx.invoke(
94
+ export, ctx, app_fp=root_fp, validate_=False, app_name=target
95
+ )
93
96
  _validate_ui_file(config_file)
94
97
  else:
95
98
  _validate_ui_file(config_file)
@@ -459,6 +459,29 @@ def get_docker_path() -> Path:
459
459
  _selected_app_name: dict[Path, str] = {}
460
460
 
461
461
 
462
+ def app_names_in_config(root_fp: Path) -> list[str]:
463
+ """Every app name declared in this directory's doover_config.json.
464
+
465
+ Never prompts, unlike `get_app_config`. For commands that act on the whole
466
+ file rather than one app — schema validation checks every app's schema, so
467
+ prompting for one would be asking a question whose answer does not matter, and
468
+ aborts outright when stdin is not a terminal (pre-commit, CI).
469
+ """
470
+ config_path = root_fp / "doover_config.json"
471
+ if not config_path.exists():
472
+ return []
473
+
474
+ with open(config_path, "r") as file:
475
+ data = json.load(file)
476
+
477
+ # Same rule as get_app_config: `type` marks an app entry.
478
+ return [
479
+ v.get("name") or k
480
+ for k, v in data.items()
481
+ if isinstance(v, dict) and "type" in v
482
+ ]
483
+
484
+
462
485
  def get_app_config(root_fp: Path, app_name: str | None = None) -> Any:
463
486
  config_path = root_fp / "doover_config.json"
464
487
  if not config_path.exists():
@@ -706,7 +706,7 @@ def test_app_publish_processor_type_without_ui_skips_ui_export(monkeypatch, tmp_
706
706
 
707
707
  assert result.exit_code == 0
708
708
  assert "export_ui_called" not in captured
709
- assert captured["build_script"] == ("./build.sh", tmp_path)
709
+ assert captured["build_script"] == ("sh ./build.sh", tmp_path)
710
710
  assert captured["processor_source"] == ("303", {"file": package_fp})
711
711
  # publish uploads the package but no longer cuts a version (that's `release`)
712
712
  assert "processor_version" not in captured
@@ -981,7 +981,7 @@ def test_app_publish_processor_builds_package_without_release(monkeypatch, tmp_p
981
981
  result = runner.invoke(app, ["app", "publish", str(tmp_path), "--no-release"])
982
982
 
983
983
  assert result.exit_code == 0
984
- assert captured["build_script"] == ("./build.sh", tmp_path)
984
+ assert captured["build_script"] == ("sh ./build.sh", tmp_path)
985
985
  assert captured["application_id"] == "303"
986
986
  assert captured["body"] == {"file": package_fp}
987
987
  # publish uploads the package; the version is cut by `doover app release`
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