buildai-cli 0.3.30__tar.gz → 0.3.32__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.
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/CLAUDE.md +4 -5
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/PKG-INFO +1 -1
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/database.py +0 -1
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/dev.py +23 -5
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/search.py +1 -2
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/context.py +4 -3
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/dev_context.py +24 -6
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/ops_init.py +10 -11
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/pyproject.toml +1 -1
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/.gitignore +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/AGENTS.md +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/__init__.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/_has_core.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/__init__.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/api_proxy.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/assets_cli.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/auth_lite.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/clips.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/embed.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/external.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/inference.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/jobs.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/keys.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/medoid.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/operations.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/partners.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/permissions.py +1 -1
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/projection.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/query.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/query_api.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/reports.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/schema.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/stats.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/sync/ddl.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/sync/models.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/sync/queries.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/config.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/console.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/guard.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/main.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/nl_query/__init__.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/nl_query/dataset_tools.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/output.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/pagination.py +0 -0
- {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/sdk_client.py +0 -0
|
@@ -19,7 +19,7 @@ buildai admin schema describe core.clips # Table details
|
|
|
19
19
|
uv run buildai dev use local # Set this worktree's deployment profile
|
|
20
20
|
uv run buildai dev current # Show resolved worktree target
|
|
21
21
|
buildai admin --write database migrate all # Run migrations
|
|
22
|
-
buildai admin database
|
|
22
|
+
buildai admin database status # Migration status
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## Guards
|
|
@@ -28,10 +28,9 @@ buildai admin database diff --from preview --to production # Migration delta
|
|
|
28
28
|
- Writes require `--write` flag.
|
|
29
29
|
- Production migrations prompt for confirmation.
|
|
30
30
|
- Worktree app/runtime targeting comes from `uv run buildai dev use <profile>`.
|
|
31
|
-
- `buildai admin --env` selects the explicit DB lane: `production`, `
|
|
32
|
-
- Do not confuse `--env preview` with the deployment profiles `local`, `preview`, or `staging`.
|
|
31
|
+
- `buildai admin --env` selects the explicit DB lane: `production`, `dev`.
|
|
33
32
|
|
|
34
33
|
## Reference
|
|
35
34
|
|
|
36
|
-
CLI mode guide: `docs
|
|
37
|
-
Database roles: `docs
|
|
35
|
+
CLI mode guide: docs site Engineering section (run `make docs`)
|
|
36
|
+
Database roles: docs site Operations section (run `make docs`)
|
|
@@ -170,7 +170,9 @@ def use(
|
|
|
170
170
|
|
|
171
171
|
success(f"Saved worktree context to {context_path}")
|
|
172
172
|
if preview_name and context.get("branch"):
|
|
173
|
-
info(
|
|
173
|
+
info(
|
|
174
|
+
f"Saved preview alias `{preview_name}` for branch `{context['branch']}` in local git config."
|
|
175
|
+
)
|
|
174
176
|
info('Run `eval "$(uv run buildai dev env)"` in your shell to export it immediately.')
|
|
175
177
|
|
|
176
178
|
|
|
@@ -181,7 +183,9 @@ def claim_preview(
|
|
|
181
183
|
"--name",
|
|
182
184
|
help="Public preview alias to bind. Defaults to the saved preview_name or branch slug.",
|
|
183
185
|
),
|
|
184
|
-
force: bool = typer.Option(
|
|
186
|
+
force: bool = typer.Option(
|
|
187
|
+
False, "--force", help="Reassign an existing alias or branch binding."
|
|
188
|
+
),
|
|
185
189
|
) -> None:
|
|
186
190
|
"""Publish this worktree's preview alias binding into the external preview registry."""
|
|
187
191
|
context = load_dev_context()
|
|
@@ -194,14 +198,28 @@ def claim_preview(
|
|
|
194
198
|
error("Current worktree branch is unknown. Commit or check out the branch first.")
|
|
195
199
|
raise typer.Exit(1)
|
|
196
200
|
|
|
197
|
-
preview_name = (
|
|
201
|
+
preview_name = (
|
|
202
|
+
(name or "").strip()
|
|
203
|
+
or get_branch_preview_name(branch)
|
|
204
|
+
or str(context.get("preview_env_id") or "").strip()
|
|
205
|
+
)
|
|
198
206
|
if not preview_name:
|
|
199
|
-
error(
|
|
207
|
+
error(
|
|
208
|
+
"No preview alias available. Pass --name or save one with `uv run buildai dev use --preview-name ...`."
|
|
209
|
+
)
|
|
200
210
|
raise typer.Exit(1)
|
|
201
211
|
|
|
202
212
|
repo_root = Path(__file__).resolve().parents[4]
|
|
203
213
|
script = repo_root / "scripts" / "infra" / "preview_registry.py"
|
|
204
|
-
cmd = [
|
|
214
|
+
cmd = [
|
|
215
|
+
os.getenv("PYTHON", "python"),
|
|
216
|
+
str(script),
|
|
217
|
+
"bind",
|
|
218
|
+
"--branch",
|
|
219
|
+
branch,
|
|
220
|
+
"--env-id",
|
|
221
|
+
preview_name,
|
|
222
|
+
]
|
|
205
223
|
if force:
|
|
206
224
|
cmd.append("--force")
|
|
207
225
|
|
|
@@ -102,8 +102,7 @@ def text(
|
|
|
102
102
|
else:
|
|
103
103
|
for i, hit in enumerate(hits, 1):
|
|
104
104
|
console.print(
|
|
105
|
-
f" {i}. score={hit.score:.4f} clip={hit.clip_id} "
|
|
106
|
-
f"factory={hit.factory_id or '—'}"
|
|
105
|
+
f" {i}. score={hit.score:.4f} clip={hit.clip_id} factory={hit.factory_id or '—'}"
|
|
107
106
|
)
|
|
108
107
|
|
|
109
108
|
|
|
@@ -22,9 +22,10 @@ from dataclasses import dataclass
|
|
|
22
22
|
from typing import TYPE_CHECKING, AsyncGenerator
|
|
23
23
|
|
|
24
24
|
import asyncpg
|
|
25
|
-
from infra import Database, get_logger
|
|
26
25
|
from infra.settings import Settings, get_settings
|
|
27
26
|
|
|
27
|
+
from infra import Database, get_logger
|
|
28
|
+
|
|
28
29
|
if TYPE_CHECKING:
|
|
29
30
|
from dal.context import Context
|
|
30
31
|
|
|
@@ -85,14 +86,14 @@ def resolve_admin_connection_config(
|
|
|
85
86
|
deployment profile, then the production password fallback already used by
|
|
86
87
|
privileged database commands.
|
|
87
88
|
"""
|
|
88
|
-
from infra.deployment_profiles import
|
|
89
|
+
from infra.deployment_profiles import resolve_deployment_profile
|
|
89
90
|
|
|
90
91
|
admin_iam_user = settings.effective_alloydb_admin_iam_user
|
|
91
92
|
admin_impersonate_sa = settings.effective_alloydb_admin_impersonate_sa
|
|
92
93
|
|
|
93
94
|
if not admin_iam_user or not admin_impersonate_sa:
|
|
94
95
|
try:
|
|
95
|
-
profile_name =
|
|
96
|
+
profile_name = os.environ.get("BUILDAI_DEPLOYMENT_PROFILE", "production")
|
|
96
97
|
profile = resolve_deployment_profile(profile_name)
|
|
97
98
|
if profile.database_admin:
|
|
98
99
|
admin_iam_user = admin_iam_user or profile.database_admin.iam_user
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import hashlib
|
|
5
6
|
import json
|
|
6
7
|
import os
|
|
8
|
+
import re
|
|
7
9
|
import shlex
|
|
8
10
|
import subprocess
|
|
9
11
|
from datetime import datetime, timezone
|
|
@@ -12,10 +14,23 @@ from typing import Any
|
|
|
12
14
|
|
|
13
15
|
from infra.deployment_profiles import (
|
|
14
16
|
list_deployment_profiles,
|
|
15
|
-
normalize_preview_env_id,
|
|
16
17
|
resolve_deployment_profile,
|
|
17
18
|
)
|
|
18
19
|
|
|
20
|
+
_PREVIEW_ENV_ID_MAX_LEN = 26
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _normalize_env_id(branch_name: str) -> str:
|
|
24
|
+
"""Normalize a branch name into a DNS-safe env id (max 26 chars)."""
|
|
25
|
+
slug = re.sub(r"[^a-z0-9]+", "-", branch_name.lower()).strip("-")
|
|
26
|
+
if not slug:
|
|
27
|
+
slug = "preview"
|
|
28
|
+
if len(slug) <= _PREVIEW_ENV_ID_MAX_LEN:
|
|
29
|
+
return slug
|
|
30
|
+
digest = hashlib.sha256(branch_name.encode()).hexdigest()[:8]
|
|
31
|
+
return f"{slug[: _PREVIEW_ENV_ID_MAX_LEN - 1 - len(digest)]}-{digest}".rstrip("-")
|
|
32
|
+
|
|
33
|
+
|
|
19
34
|
DEV_CONTEXT_DIRNAME = ".buildai"
|
|
20
35
|
DEV_CONTEXT_FILENAME = "context.json"
|
|
21
36
|
DEV_CONTEXT_SUMMARY_FILENAME = "context.md"
|
|
@@ -90,15 +105,19 @@ def get_branch_preview_name(branch: str | None, start_path: Path | None = None)
|
|
|
90
105
|
return None
|
|
91
106
|
cwd = (start_path or Path.cwd()).resolve()
|
|
92
107
|
value = _git_output(["config", "--local", "--get", f"branch.{branch}.buildaiPreviewName"], cwd)
|
|
93
|
-
return
|
|
108
|
+
return _normalize_env_id(value) if value else None
|
|
94
109
|
|
|
95
110
|
|
|
96
|
-
def set_branch_preview_name(
|
|
111
|
+
def set_branch_preview_name(
|
|
112
|
+
branch: str | None,
|
|
113
|
+
preview_name: str,
|
|
114
|
+
start_path: Path | None = None,
|
|
115
|
+
) -> None:
|
|
97
116
|
"""Persist one branch-local preview alias into local git config."""
|
|
98
117
|
if not branch:
|
|
99
118
|
raise RuntimeError("Cannot save preview alias without an active git branch.")
|
|
100
119
|
cwd = (start_path or Path.cwd()).resolve()
|
|
101
|
-
normalized =
|
|
120
|
+
normalized = _normalize_env_id(preview_name)
|
|
102
121
|
subprocess.run(
|
|
103
122
|
["git", "config", "--local", f"branch.{branch}.buildaiPreviewName", normalized],
|
|
104
123
|
cwd=str(cwd),
|
|
@@ -129,7 +148,7 @@ def _repo_metadata(start_path: Path | None = None) -> dict[str, Any]:
|
|
|
129
148
|
cwd = (start_path or Path.cwd()).resolve()
|
|
130
149
|
branch = _git_output(["branch", "--show-current"], cwd) if repo_root else None
|
|
131
150
|
commit_sha = _git_output(["rev-parse", "HEAD"], cwd) if repo_root else None
|
|
132
|
-
preview_env_id =
|
|
151
|
+
preview_env_id = _normalize_env_id(branch) if branch else None
|
|
133
152
|
return {
|
|
134
153
|
"repo_root": str(repo_root) if repo_root else None,
|
|
135
154
|
"worktree_path": str(cwd),
|
|
@@ -145,7 +164,6 @@ def _profile_defaults(profile: str, metadata: dict[str, Any]) -> dict[str, Any]:
|
|
|
145
164
|
resolved = resolve_deployment_profile(
|
|
146
165
|
profile,
|
|
147
166
|
env_id=env_id,
|
|
148
|
-
override_key=metadata.get("branch"),
|
|
149
167
|
)
|
|
150
168
|
return {
|
|
151
169
|
"deployment_profile": resolved.name,
|
|
@@ -11,7 +11,7 @@ import os
|
|
|
11
11
|
from enum import Enum
|
|
12
12
|
|
|
13
13
|
import typer
|
|
14
|
-
from infra.deployment_profiles import
|
|
14
|
+
from infra.deployment_profiles import resolve_deployment_profile
|
|
15
15
|
|
|
16
16
|
from cli.console import error, info, warning
|
|
17
17
|
|
|
@@ -59,11 +59,6 @@ def _apply_context_database_target(
|
|
|
59
59
|
if isinstance(context, dict) and context.get("preview_env_id")
|
|
60
60
|
else None
|
|
61
61
|
),
|
|
62
|
-
override_key=(
|
|
63
|
-
str(context.get("branch")).strip()
|
|
64
|
-
if isinstance(context, dict) and context.get("branch")
|
|
65
|
-
else None
|
|
66
|
-
),
|
|
67
62
|
)
|
|
68
63
|
database_target = resolved_profile.database_target.as_context_dict()
|
|
69
64
|
runtime_target["region"] = resolved_profile.runtime_region
|
|
@@ -142,10 +137,11 @@ def init_ops_context(ctx: typer.Context):
|
|
|
142
137
|
|
|
143
138
|
require_core("this command")
|
|
144
139
|
|
|
145
|
-
from infra import init_observability
|
|
146
140
|
from infra.auth import AuthError, get_effective_user_for_iam, validate_auth_config
|
|
147
141
|
from infra.settings import Environment, ExecutionContext, Settings, get_settings
|
|
148
142
|
|
|
143
|
+
from infra import init_observability
|
|
144
|
+
|
|
149
145
|
verbose = ctx.obj.get("_verbose", False)
|
|
150
146
|
log_level = logging.DEBUG if verbose else logging.WARNING
|
|
151
147
|
init_observability("cli", log_level=log_level, enable_json_logs=False)
|
|
@@ -161,8 +157,7 @@ def init_ops_context(ctx: typer.Context):
|
|
|
161
157
|
app_env = Environment(_parse_env(env_flag))
|
|
162
158
|
except ValueError:
|
|
163
159
|
error(
|
|
164
|
-
f"Invalid environment '{env_flag}'. "
|
|
165
|
-
"Valid: development, preview, production, test."
|
|
160
|
+
f"Invalid environment '{env_flag}'. Valid: development, preview, production, test."
|
|
166
161
|
)
|
|
167
162
|
raise typer.Exit(1)
|
|
168
163
|
else:
|
|
@@ -189,10 +184,14 @@ def init_ops_context(ctx: typer.Context):
|
|
|
189
184
|
os.environ["BUILDAI_PREVIEW_ENV_ID"] = preview_env_id.strip()
|
|
190
185
|
if env_flag is not None:
|
|
191
186
|
deployment_profile = (
|
|
192
|
-
""
|
|
187
|
+
""
|
|
188
|
+
if app_env == Environment.TEST
|
|
189
|
+
else "local"
|
|
190
|
+
if app_env == Environment.DEVELOPMENT
|
|
191
|
+
else "production"
|
|
193
192
|
)
|
|
194
193
|
elif deployment_profile is None and app_env != Environment.TEST:
|
|
195
|
-
deployment_profile =
|
|
194
|
+
deployment_profile = "local" if app_env == Environment.DEVELOPMENT else "production"
|
|
196
195
|
if deployment_profile:
|
|
197
196
|
os.environ["BUILDAI_DEPLOYMENT_PROFILE"] = deployment_profile
|
|
198
197
|
_apply_context_database_target(workspace_context, deployment_profile=deployment_profile)
|
|
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
|
|
@@ -5,13 +5,13 @@ from pathlib import Path
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
|
-
from infra import permissions as perm_mod
|
|
9
8
|
from infra.settings import Settings
|
|
10
9
|
from typing_extensions import Annotated
|
|
11
10
|
|
|
12
11
|
from cli.config import resolve_cli_profile
|
|
13
12
|
from cli.console import console, error, info, success, warning
|
|
14
13
|
from cli.context import get_connection
|
|
14
|
+
from infra import permissions as perm_mod
|
|
15
15
|
|
|
16
16
|
app = typer.Typer(name="permissions", help="Permission preflight checks", no_args_is_help=True)
|
|
17
17
|
|
|
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
|