fix(release): align image smoke with migration 0030
This commit is contained in:
+1
-1
@@ -372,7 +372,7 @@
|
|||||||
|
|
||||||
- Alembic revisions in migrations/versions/ are the ordered schema history for persistent environments.
|
- Alembic revisions in migrations/versions/ are the ordered schema history for persistent environments.
|
||||||
- app/repositories/postgres.py includes ensure_schema() for bootstrap safety, but long-term schema evolution should run through Alembic.
|
- app/repositories/postgres.py includes ensure_schema() for bootstrap safety, but long-term schema evolution should run through Alembic.
|
||||||
- Current Alembic head is `20260814_0029`; its strategy columns, default seed, and constraints are guarded for ensure_schema-first and repeatable execution.
|
- Current Alembic head is `20260820_0030`; the preceding `0029` strategy columns, default seed, and constraints and the `0030` unified-ledger keyset index are guarded for ensure_schema-first and repeatable execution.
|
||||||
- Comments, tags, auth tokens, and ledger rows are normalized into dedicated tables keyed to users or portfolios.
|
- Comments, tags, auth tokens, and ledger rows are normalized into dedicated tables keyed to users or portfolios.
|
||||||
|
|
||||||
## Current Gaps / Planned Changes
|
## Current Gaps / Planned Changes
|
||||||
|
|||||||
@@ -138,7 +138,7 @@
|
|||||||
|-----------|-----------|------|
|
|-----------|-----------|------|
|
||||||
| ensure_schema() 전용 | `idx_auth_tokens_service_name_unique` (partial index, BAT-006/REQ-017: `AND revoked_at IS NULL` 조건 추가) | Alembic revision 20260520_0022에도 CONCURRENTLY 버전 존재 |
|
| ensure_schema() 전용 | `idx_auth_tokens_service_name_unique` (partial index, BAT-006/REQ-017: `AND revoked_at IS NULL` 조건 추가) | Alembic revision 20260520_0022에도 CONCURRENTLY 버전 존재 |
|
||||||
| Alembic 전용 | `portfolios.market`, `auth_tokens.runtime_id`, `idx_auth_tokens_runtime_id_unique`, `broker_credentials`, `ledger_trades` | ensure_schema()에 없음 — v1 API 전제 조건 |
|
| Alembic 전용 | `portfolios.market`, `auth_tokens.runtime_id`, `idx_auth_tokens_runtime_id_unique`, `broker_credentials`, `ledger_trades` | ensure_schema()에 없음 — v1 API 전제 조건 |
|
||||||
| 양쪽 공유 (IF NOT EXISTS 보호) | users, auth_tokens, strategy_sets (`status`, `revision`, `updated_at` 포함), portfolios, portfolio_ledger, portfolio_comments, portfolio_tags + 대부분의 인덱스 | ensure_schema() 우선 실행 후 Alembic `20260814_0029` 실행 시 충돌 없음; 기본 전략 seed/constraints도 존재 여부 guard 적용 |
|
| 양쪽 공유 (IF NOT EXISTS 보호) | users, auth_tokens, strategy_sets (`status`, `revision`, `updated_at` 포함), portfolios, portfolio_ledger, portfolio_comments, portfolio_tags + 대부분의 인덱스 | ensure_schema() 우선 실행 후 Alembic `20260820_0030`까지 실행 시 충돌 없음; 기본 전략 seed/constraints와 unified-ledger keyset index도 존재 여부 guard 적용 |
|
||||||
|
|
||||||
### 허용 실행 순서
|
### 허용 실행 순서
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ COMMIT_RE = re.compile(r"^[0-9a-f]{40}$")
|
|||||||
VERSION_REF_RE = re.compile(r"^refs/tags/v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$")
|
VERSION_REF_RE = re.compile(r"^refs/tags/v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$")
|
||||||
IMAGE_ID_RE = re.compile(r"^sha256:[0-9a-f]{64}$")
|
IMAGE_ID_RE = re.compile(r"^sha256:[0-9a-f]{64}$")
|
||||||
DIGEST_RE = re.compile(r"(?:^|\s)digest:\s*(sha256:[0-9a-f]{64})(?:\s|$)")
|
DIGEST_RE = re.compile(r"(?:^|\s)digest:\s*(sha256:[0-9a-f]{64})(?:\s|$)")
|
||||||
EXPECTED_MIGRATION_COUNT = 29
|
EXPECTED_MIGRATION_COUNT = 30
|
||||||
EXPECTED_ALEMBIC_HEAD = "20260814_0029"
|
EXPECTED_ALEMBIC_HEAD = "20260820_0030"
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Result:
|
class Result:
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ class RecordingRunner:
|
|||||||
if command[:3] == ["docker", "run", "--rm"] and "urllib.request" in command[-1]:
|
if command[:3] == ["docker", "run", "--rm"] and "urllib.request" in command[-1]:
|
||||||
enabled = "TARGET:8000" not in command[-1] and "plain" not in command[-1]
|
enabled = "TARGET:8000" not in command[-1] and "plain" not in command[-1]
|
||||||
return image_release.Result('{"status":"ok","db_enabled":' + str(enabled).lower() + '}')
|
return image_release.Result('{"status":"ok","db_enabled":' + str(enabled).lower() + '}')
|
||||||
if command[:3] == ["docker", "run", "--rm"] and "alembic_version" in command[-1]: return image_release.Result("20260814_0029\n")
|
if command[:3] == ["docker", "run", "--rm"] and "alembic_version" in command[-1]: return image_release.Result("20260820_0030\n")
|
||||||
if command[:3] == ["docker", "run", "--rm"] and "health-check" in command: return image_release.Result('{"database_revision":"20260814_0029"}\n')
|
if command[:3] == ["docker", "run", "--rm"] and "health-check" in command: return image_release.Result('{"database_revision":"20260820_0030"}\n')
|
||||||
return image_release.Result()
|
return image_release.Result()
|
||||||
|
|
||||||
def artifacts(tmp_path: Path):
|
def artifacts(tmp_path: Path):
|
||||||
@@ -73,13 +73,13 @@ def test_project_version_must_match_release_tag(tmp_path):
|
|||||||
|
|
||||||
def test_installed_smoke_has_import_cli_exact_inventory_and_cleanup():
|
def test_installed_smoke_has_import_cli_exact_inventory_and_cleanup():
|
||||||
inventory = tuple(
|
inventory = tuple(
|
||||||
[f"202601{i:02d}_{i:04d}_migration.py" for i in range(1, 29)]
|
[f"202601{i:02d}_{i:04d}_migration.py" for i in range(1, 30)]
|
||||||
+ ["20260814_0029_strategy_catalog_v1.py"]
|
+ ["20260820_0030_portfolio_ledger_keyset_index.py"]
|
||||||
)
|
)
|
||||||
runner = RecordingRunner(); image_release.smoke_installed_image("candidate", inventory, runner, 17)
|
runner = RecordingRunner(); image_release.smoke_installed_image("candidate", inventory, runner, 17)
|
||||||
runs = [x[0] for x in runner.commands if x[0][:2] == ["docker","run"]]
|
runs = [x[0] for x in runner.commands if x[0][:2] == ["docker","run"]]
|
||||||
assert len(runs) == 3 and all("--read-only" in x and "none" in x for x in runs)
|
assert len(runs) == 3 and all("--read-only" in x and "none" in x for x in runs)
|
||||||
assert "migration_inventory" in runs[-1][-1] and "20260814_0029" in runs[-1][-1]
|
assert "migration_inventory" in runs[-1][-1] and "20260820_0030" in runs[-1][-1]
|
||||||
assert len([x for x in runner.commands if x[0][:3] == ["docker","rm","--force"]]) == 3
|
assert len([x for x in runner.commands if x[0][:3] == ["docker","rm","--force"]]) == 3
|
||||||
|
|
||||||
def _assert_exact_startup_cleanup(commands: list[list[str]]) -> None:
|
def _assert_exact_startup_cleanup(commands: list[list[str]]) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user