Схема v8: без статуса по факту и его настроек (#104)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5b01b91710
commit
8bab76e043
@ -8,7 +8,7 @@ from pathlib import Path
|
||||
|
||||
from . import backup, paths
|
||||
|
||||
SCHEMA_VERSION = 7
|
||||
SCHEMA_VERSION = 8
|
||||
|
||||
CORE_SCHEMA = """
|
||||
CREATE TABLE IF NOT EXISTS setting (
|
||||
@ -67,6 +67,11 @@ def _project_fields_v7(conn) -> None:
|
||||
projects.migrate_v6(conn)
|
||||
|
||||
|
||||
def _note_fields_v8(conn) -> None:
|
||||
from ..modules.jira import settings
|
||||
settings.migrate_v7(conn)
|
||||
|
||||
|
||||
def _fill_comment_utc(conn) -> None:
|
||||
from ..modules.jira import history
|
||||
history.fill_comment_utc(conn)
|
||||
@ -130,6 +135,7 @@ MIGRATIONS = {
|
||||
5: [], # v5 → v6: issue_attachment и attachment_file создаются схемой (CREATE TABLE IF NOT EXISTS), данных переносить не нужно
|
||||
6: [_tokens_v7, _agent_status_v7,
|
||||
_project_fields_v7], # v6 → v7: токены и статус по агентам модулей (wiki-module, решение 15)
|
||||
7: [_note_fields_v8], # v7 → v8: без статуса по факту и его настроек (fact-status-removal)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -77,7 +77,6 @@ CREATE INDEX IF NOT EXISTS ix_issue_change_at ON issue_change(at);
|
||||
CREATE INDEX IF NOT EXISTS ix_issue_change_key ON issue_change(key, at);
|
||||
CREATE TABLE IF NOT EXISTS issue_note (
|
||||
key TEXT PRIMARY KEY,
|
||||
fact_status TEXT,
|
||||
work_kind TEXT,
|
||||
done_text TEXT,
|
||||
rest_text TEXT,
|
||||
|
||||
@ -17,18 +17,16 @@ DEFAULTS = {
|
||||
"priority_map": {},
|
||||
"priority_value_key": "name",
|
||||
"labels": [],
|
||||
"status_labels": {},
|
||||
"kind_labels": {},
|
||||
"comment_marker": "",
|
||||
"transitions_map": {},
|
||||
"link_types": {},
|
||||
"closed_statuses": ["Готово", "Снято"], # статусы Jira закрытых задач: список и доска приложения (hide-closed)
|
||||
}
|
||||
|
||||
# Что получает агент от модуля (без токенов и служебных ключей хаба); settings_version добавляет ядро
|
||||
AGENT_KEYS = ["project_key", "issue_types", "epic_name_field_id", "field_ids", "epic_link",
|
||||
"priority_map", "priority_value_key", "labels", "status_labels", "kind_labels", "comment_marker",
|
||||
"transitions_map", "link_types", "pacing", "min_agent_version"]
|
||||
"priority_map", "priority_value_key", "labels", "kind_labels", "comment_marker",
|
||||
"link_types", "pacing", "min_agent_version"]
|
||||
|
||||
|
||||
def _is_int(v) -> bool:
|
||||
@ -85,9 +83,20 @@ def _issue_types(cfg: dict) -> dict:
|
||||
return out
|
||||
|
||||
|
||||
def migrate_v7(conn) -> None:
|
||||
"""Шаг миграции v7 → v8 (fact-status-removal): колонка issue_note.fact_status и ключи status_labels, transitions_map
|
||||
удаляются безвозвратно; settings_version поднимается, если удалён хотя бы один ключ и строка версии есть."""
|
||||
if "fact_status" in {r["name"] for r in conn.execute("PRAGMA table_info(issue_note)")}:
|
||||
conn.execute("ALTER TABLE issue_note DROP COLUMN fact_status")
|
||||
gone = conn.execute("DELETE FROM setting WHERE key IN ('status_labels', 'transitions_map')").rowcount
|
||||
if gone:
|
||||
conn.execute("UPDATE setting SET value = CAST(value AS INTEGER) + 1 WHERE key = 'settings_version'")
|
||||
|
||||
|
||||
def init_from_config(conn, cfg: dict, force=False) -> list[str]:
|
||||
"""Перенести из config.example.json всё, что относится к проекту Jira. Учётные данные и адрес Jira
|
||||
(auth, base_url, verify_ssl, ca_bundle) остаются у агента и сюда не попадают."""
|
||||
(auth, base_url, verify_ssl, ca_bundle) остаются у агента и сюда не попадают; status_labels и transitions — тоже
|
||||
(статуса по факту в хабе нет, fact-status-removal)."""
|
||||
if core_settings.get(conn, "initialized") and not force:
|
||||
raise RuntimeError("хаб уже инициализирован; повторный init — с --force")
|
||||
project = cfg["project_key"]
|
||||
@ -100,10 +109,8 @@ def init_from_config(conn, cfg: dict, force=False) -> list[str]:
|
||||
"priority_map": cfg.get("priority_map", {}),
|
||||
"priority_value_key": cfg.get("priority_value_key", "name"),
|
||||
"labels": cfg.get("labels", []),
|
||||
"status_labels": cfg.get("status_labels", {}),
|
||||
"kind_labels": cfg.get("kind_labels", {}),
|
||||
"comment_marker": cfg.get("comment_marker", ""),
|
||||
"transitions_map": cfg.get("transitions", {}).get("map", {}),
|
||||
"link_types": cfg.get("link_types", {}),
|
||||
"pacing": pacing_from_config(cfg.get("pacing", {})),
|
||||
}
|
||||
|
||||
4
tests/fixtures/baseline/schema.expected.json
vendored
4
tests/fixtures/baseline/schema.expected.json
vendored
@ -73,7 +73,7 @@
|
||||
[
|
||||
"table",
|
||||
"issue_note",
|
||||
"CREATE TABLE issue_note (\n key TEXT PRIMARY KEY,\n fact_status TEXT,\n work_kind TEXT,\n done_text TEXT,\n rest_text TEXT,\n owner_note TEXT,\n updated_at TEXT,\n updated_by TEXT\n)"
|
||||
"CREATE TABLE issue_note (\n key TEXT PRIMARY KEY,\n work_kind TEXT,\n done_text TEXT,\n rest_text TEXT,\n owner_note TEXT,\n updated_at TEXT,\n updated_by TEXT\n)"
|
||||
],
|
||||
[
|
||||
"table",
|
||||
@ -116,5 +116,5 @@
|
||||
"CREATE TABLE wiki_sync_stage (\n command_id INTEGER NOT NULL,\n code TEXT NOT NULL,\n payload TEXT NOT NULL,\n PRIMARY KEY (command_id, code)\n)"
|
||||
]
|
||||
],
|
||||
"schema_version": 7
|
||||
"schema_version": 8
|
||||
}
|
||||
|
||||
@ -8,10 +8,8 @@
|
||||
"priority_map",
|
||||
"priority_value_key",
|
||||
"labels",
|
||||
"status_labels",
|
||||
"kind_labels",
|
||||
"comment_marker",
|
||||
"transitions_map",
|
||||
"link_types",
|
||||
"pacing",
|
||||
"min_agent_version",
|
||||
@ -51,8 +49,6 @@
|
||||
"project_key": "AURORA",
|
||||
"relay_dir": null,
|
||||
"settings_version": 1,
|
||||
"status_labels": {},
|
||||
"transitions_map": {},
|
||||
"wiki_auto_sync_hours": 24,
|
||||
"wiki_min_agent_version": 1,
|
||||
"wiki_pacing": 0.2
|
||||
|
||||
@ -22,7 +22,7 @@ def test_v6_upgrade_keeps_jira_agent(tmp_path):
|
||||
assert tok == "T-agent"
|
||||
code, body = api.h_claim(hub, conn, None, {"_agent": "jira"}, {"agent_version": 14})
|
||||
assert code == 200 and body["agent_release"]["version"] == 14 # релиз v14 перенесён в release/jira/
|
||||
assert db._schema_version(conn) == 7
|
||||
assert db._schema_version(conn) == db.SCHEMA_VERSION
|
||||
tok = settings.tokens(conn)
|
||||
assert tok["client"] == "T-client" and tok["agents"]["jira"] == "T-agent" and "agent" not in tok
|
||||
row = conn.execute("SELECT * FROM agent_status WHERE agent = 'jira'").fetchone()
|
||||
@ -79,7 +79,8 @@ def test_module_agent_route_requires_own_module(hub_server_two_modules):
|
||||
def test_agent_settings_per_module(hub_server_two_modules):
|
||||
jira = hub_server_two_modules["agents"]["jira"].get("/agent/settings")
|
||||
stub = hub_server_two_modules["agents"]["stub"].get("/agent/settings")
|
||||
assert "project_key" in jira and "transitions_map" in jira and "settings_version" in jira
|
||||
assert "project_key" in jira and "link_types" in jira and "settings_version" in jira
|
||||
assert "transitions_map" not in jira and "status_labels" not in jira
|
||||
assert "stub_key" not in jira and "board_id" not in jira
|
||||
assert set(stub) == {"stub_key", "settings_version"}
|
||||
|
||||
@ -318,7 +319,7 @@ def test_v14_agent_over_http_on_v6_base(tmp_path):
|
||||
conn.close()
|
||||
expected = json.loads((Path(__file__).parent / "fixtures" / "settings_v6.json").read_text(encoding="utf-8"))["agent_keys"]
|
||||
got = a.get("/agent/settings")
|
||||
assert set(got) == set(expected) - {"board_id"}
|
||||
assert set(got) == set(expected) - {"board_id", "status_labels", "transitions_map"} # fact-status-removal
|
||||
assert a.get("/agent/release")["version"] == 14
|
||||
assert a.post("/agent/state", {"issues": [{"key": "A-1", "summary": "Т", "labels": []}], "links": [],
|
||||
"neighbor_keys": []}) == {"issues": 1, "links": 0}
|
||||
|
||||
@ -119,7 +119,7 @@ def test_interface_routes(hub, add_project):
|
||||
assert e.value.status == 422 and "неизвестные поля заметки: fact_status" in e.value.detail
|
||||
assert c.get("/issues/A-1")["note"] is None # и work_kind не записан
|
||||
note = c.put("/issues/A-1/note", {"work_kind": "Аналитика", "updated_by": "owner"})
|
||||
assert note["work_kind"] == "Аналитика" and note["updated_by"] == "owner" and note.get("fact_status") is None
|
||||
assert note["work_kind"] == "Аналитика" and note["updated_by"] == "owner" and "fact_status" not in note
|
||||
with pytest.raises(HubError) as e:
|
||||
c.put("/issues/A-1/note", {"summary": "x"})
|
||||
assert e.value.status == 422
|
||||
|
||||
@ -13,7 +13,7 @@ def test_init_import_tokens(tmp_path, monkeypatch, capsys, open_db):
|
||||
monkeypatch.setenv("SDLC_HUB_HOME", str(tmp_path / "home"))
|
||||
assert cli.main(["init", "--config", str(FIXTURE)]) == 0
|
||||
out = capsys.readouterr().out
|
||||
assert "transitions_map" in out and "агент jira: " in out
|
||||
assert "link_types" in out and "transitions_map" not in out and "агент jira: " in out
|
||||
assert cli.main(["init", "--config", str(FIXTURE)]) == 1
|
||||
assert "уже инициализирован" in capsys.readouterr().err
|
||||
conn = open_db(paths.db_path())
|
||||
|
||||
102
tests/test_db.py
102
tests/test_db.py
@ -19,12 +19,23 @@ def test_connect_creates_schema(open_db):
|
||||
assert "created_at" in {r["name"] for r in conn.execute("PRAGMA table_info(issue_comment)")}
|
||||
assert "history_at" in {r["name"] for r in conn.execute("PRAGMA table_info(sync_run)")}
|
||||
assert "project" in {r["name"] for r in conn.execute("PRAGMA table_info(batch)")}
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == "7"
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == str(db.SCHEMA_VERSION)
|
||||
assert conn.execute("SELECT COUNT(*) AS n FROM agent_status").fetchone()["n"] == 2
|
||||
cols = {r["name"] for r in conn.execute("PRAGMA table_info(command)")}
|
||||
assert "deliveries" in cols
|
||||
|
||||
|
||||
def _add_fact_status(conn):
|
||||
"""Колонка issue_note.fact_status, как в базах до v8 (fact-status-removal)."""
|
||||
conn.execute("ALTER TABLE issue_note ADD COLUMN fact_status TEXT")
|
||||
|
||||
|
||||
def _note_after_v8(conn, key):
|
||||
"""После миграции до v8: колонки fact_status нет; work_kind заметки."""
|
||||
assert "fact_status" not in {r["name"] for r in conn.execute("PRAGMA table_info(issue_note)")}
|
||||
return conn.execute("SELECT work_kind FROM issue_note WHERE key = ?", (key,)).fetchone()["work_kind"]
|
||||
|
||||
|
||||
def _drop_v6(conn):
|
||||
"""Снять с базы текущей схемы то, что добавила v6 (вложения)."""
|
||||
conn.execute("DROP TABLE attachment_file")
|
||||
@ -46,7 +57,8 @@ def _v1_database(path):
|
||||
for status in ("claimed", "done", "queued"):
|
||||
conn.execute("INSERT INTO command(batch_id, seq, type, params, status, claimed_at) VALUES (1, 1, 'refresh', '{}', ?, ?)",
|
||||
(status, "2026-10-13T00:00:00+00:00" if status == "claimed" else None))
|
||||
conn.execute("INSERT INTO issue_note(key, fact_status) VALUES ('A-1', 'В работе')")
|
||||
_add_fact_status(conn)
|
||||
conn.execute("INSERT INTO issue_note(key, fact_status, work_kind) VALUES ('A-1', 'В работе', 'Аналитика')")
|
||||
_drop_v5(conn)
|
||||
conn.execute("ALTER TABLE command DROP COLUMN deliveries")
|
||||
conn.execute("ALTER TABLE batch DROP COLUMN project")
|
||||
@ -59,10 +71,10 @@ def test_migrates_v1_with_backup(tmp_path):
|
||||
path = tmp_path / "hub.sqlite"
|
||||
_v1_database(path)
|
||||
conn = db.connect(path)
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == "7"
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == str(db.SCHEMA_VERSION)
|
||||
rows = conn.execute("SELECT status, deliveries FROM command ORDER BY id").fetchall()
|
||||
assert [(r["status"], r["deliveries"]) for r in rows] == [("claimed", 1), ("done", 0), ("queued", 0)]
|
||||
assert conn.execute("SELECT fact_status FROM issue_note WHERE key = 'A-1'").fetchone()["fact_status"] == "В работе"
|
||||
assert _note_after_v8(conn, "A-1") == "Аналитика"
|
||||
copies = list((tmp_path / "backups").glob("*-schema-v1.sqlite"))
|
||||
assert len(copies) == 1
|
||||
old = sqlite3.connect(copies[0]) # не db.connect — он бы мигрировал копию
|
||||
@ -206,7 +218,7 @@ def test_parallel_connect_makes_one_backup(tmp_path):
|
||||
assert errors == []
|
||||
assert len(list((tmp_path / "backups").glob("*-schema-v1.sqlite"))) == 1
|
||||
conn = db.connect(path)
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == "7"
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == str(db.SCHEMA_VERSION)
|
||||
conn.close()
|
||||
|
||||
|
||||
@ -215,7 +227,8 @@ def test_migrates_v2_with_backup(tmp_path):
|
||||
path = tmp_path / "hub.sqlite"
|
||||
conn = db.connect(path)
|
||||
conn.execute("INSERT INTO issue(key, summary, fetched_at) VALUES ('A-1', 'Т', '2026-10-15T00:00:00+00:00')")
|
||||
conn.execute("INSERT INTO issue_note(key, fact_status) VALUES ('A-1', 'В работе')")
|
||||
_add_fact_status(conn)
|
||||
conn.execute("INSERT INTO issue_note(key, fact_status, work_kind) VALUES ('A-1', 'В работе', 'Аналитика')")
|
||||
_drop_v5(conn)
|
||||
conn.execute("DROP TABLE issue_comment")
|
||||
conn.execute("ALTER TABLE batch DROP COLUMN project")
|
||||
@ -223,10 +236,10 @@ def test_migrates_v2_with_backup(tmp_path):
|
||||
conn.execute("UPDATE setting SET value = '2' WHERE key = 'schema_version'")
|
||||
conn.close()
|
||||
conn = db.connect(path)
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == "7"
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == str(db.SCHEMA_VERSION)
|
||||
assert conn.execute("SELECT COUNT(*) AS n FROM issue_comment").fetchone()["n"] == 0
|
||||
assert conn.execute("SELECT summary FROM issue WHERE key = 'A-1'").fetchone()["summary"] == "Т"
|
||||
assert conn.execute("SELECT fact_status FROM issue_note WHERE key = 'A-1'").fetchone()["fact_status"] == "В работе"
|
||||
assert _note_after_v8(conn, "A-1") == "Аналитика"
|
||||
copies = list((tmp_path / "backups").glob("*-schema-v2.sqlite"))
|
||||
assert len(copies) == 1
|
||||
conn.close()
|
||||
@ -267,7 +280,8 @@ def _v3_database(path, base_jql="project = AURORA AND labels = AWPCA", board_id=
|
||||
conn.execute("INSERT INTO sync_run(started_at, finished_at, kind, query, command_id) VALUES (?, ?, 'jql', ?, ?)",
|
||||
(ts, ts, base_jql, cid))
|
||||
conn.execute("INSERT INTO issue(key, summary, fetched_at) VALUES ('A-1', 'Т', ?)", (ts,))
|
||||
conn.execute("INSERT INTO issue_note(key, fact_status) VALUES ('A-1', 'В работе')")
|
||||
_add_fact_status(conn)
|
||||
conn.execute("INSERT INTO issue_note(key, fact_status, work_kind) VALUES ('A-1', 'В работе', 'Аналитика')")
|
||||
_drop_v5(conn)
|
||||
conn.execute("ALTER TABLE batch DROP COLUMN project")
|
||||
conn.execute("DROP TABLE project")
|
||||
@ -292,7 +306,7 @@ def test_migrates_v3_creates_awpca(tmp_path):
|
||||
queued = [json.loads(r["params"])["jql"] for r in conn.execute("SELECT params FROM command WHERE status = 'queued'")]
|
||||
assert sorted(queued) == sorted([new, "key = A-1"])
|
||||
assert conn.execute("SELECT project FROM batch").fetchall()[0]["project"] is None
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == "7"
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == str(db.SCHEMA_VERSION)
|
||||
assert len(list((tmp_path / "backups").glob("*-schema-v3.sqlite"))) == 1
|
||||
conn.close()
|
||||
|
||||
@ -311,7 +325,7 @@ def test_migrates_v3_unparsed_jql_keeps_running(tmp_path, caplog):
|
||||
conn = db.connect(tmp_path / "hub.sqlite")
|
||||
assert projects.list_projects(conn) == []
|
||||
assert "ORDER BY key" in caplog.text
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == "7"
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == str(db.SCHEMA_VERSION)
|
||||
conn.close()
|
||||
|
||||
|
||||
@ -345,7 +359,7 @@ def test_migrates_v4(tmp_path):
|
||||
path = tmp_path / "hub.sqlite"
|
||||
_v4_database(path)
|
||||
conn = db.connect(path)
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == "7"
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == str(db.SCHEMA_VERSION)
|
||||
rows = {r["comment_id"]: (r["created"], r["created_at"]) for r in conn.execute("SELECT * FROM issue_comment")}
|
||||
assert rows == {"1": ("2026-10-22T13:05:11.000+0300", "2026-10-22T10:05:11+00:00"), "2": ("мусор", None)}
|
||||
assert conn.execute("SELECT history_at FROM sync_run").fetchone()["history_at"] is None
|
||||
@ -361,8 +375,70 @@ def test_migrate_v5_to_v6(tmp_path):
|
||||
conn.execute("UPDATE setting SET value = '5' WHERE key = 'schema_version'")
|
||||
conn.close()
|
||||
conn = db.connect(path)
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == "7"
|
||||
assert conn.execute("SELECT value FROM setting WHERE key = 'schema_version'").fetchone()["value"] == str(db.SCHEMA_VERSION)
|
||||
assert conn.execute("SELECT COUNT(*) AS n FROM issue_attachment").fetchone()["n"] == 0
|
||||
assert conn.execute("SELECT COUNT(*) AS n FROM attachment_file").fetchone()["n"] == 0
|
||||
assert len(list((tmp_path / "backups").glob("*-schema-v5.sqlite"))) == 1
|
||||
conn.close()
|
||||
|
||||
|
||||
def _v7_database(path, settings_version=12, with_keys=True):
|
||||
"""База v7: заметка со статусом по факту, ключи status_labels/transitions_map в setting (fact-status-removal)."""
|
||||
conn = db.connect(path)
|
||||
settings.ensure_defaults(conn)
|
||||
_add_fact_status(conn)
|
||||
conn.execute("INSERT INTO issue_note(key, fact_status, work_kind, updated_at, updated_by) "
|
||||
"VALUES ('A-1', 'В работе', 'Аналитика', '2026-10-20T00:00:00+00:00', 'import')")
|
||||
rows = [("settings_version", settings_version)]
|
||||
if with_keys:
|
||||
rows += [("status_labels", {"В работе": "fact-in-progress"}), ("transitions_map", {"Снято": "Снято"})]
|
||||
for key, value in rows:
|
||||
conn.execute("INSERT OR REPLACE INTO setting(key, value) VALUES (?, ?)", (key, json.dumps(value, ensure_ascii=False)))
|
||||
conn.execute("UPDATE setting SET value = '7' WHERE key = 'schema_version'")
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_migrates_v7_drops_fact_status(tmp_path):
|
||||
path = tmp_path / "hub.sqlite"
|
||||
_v7_database(path)
|
||||
conn = db.connect(path)
|
||||
assert db._schema_version(conn) == 8
|
||||
assert _note_after_v8(conn, "A-1") == "Аналитика"
|
||||
row = conn.execute("SELECT updated_at, updated_by FROM issue_note WHERE key = 'A-1'").fetchone()
|
||||
assert (row["updated_at"], row["updated_by"]) == ("2026-10-20T00:00:00+00:00", "import")
|
||||
assert settings.get(conn, "status_labels") is None and settings.get(conn, "transitions_map") is None
|
||||
assert settings.get(conn, "settings_version") == 13
|
||||
assert len(list((tmp_path / "backups").glob("*-schema-v7.sqlite"))) == 1
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_migrates_v7_without_keys_keeps_settings_version(tmp_path):
|
||||
path = tmp_path / "hub.sqlite"
|
||||
_v7_database(path, with_keys=False)
|
||||
conn = db.connect(path)
|
||||
assert db._schema_version(conn) == 8 and settings.get(conn, "settings_version") == 12
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_migrates_v7_without_settings_version(tmp_path):
|
||||
path = tmp_path / "hub.sqlite"
|
||||
_v7_database(path)
|
||||
raw = sqlite3.connect(path)
|
||||
raw.execute("DELETE FROM setting WHERE key = 'settings_version'")
|
||||
raw.commit()
|
||||
raw.close()
|
||||
conn = db.connect(path)
|
||||
assert db._schema_version(conn) == 8
|
||||
assert conn.execute("SELECT COUNT(*) AS n FROM setting WHERE key = 'settings_version'").fetchone()["n"] == 0
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_v8_reconnect_is_stable(tmp_path):
|
||||
path = tmp_path / "hub.sqlite"
|
||||
_v7_database(path)
|
||||
db.connect(path).close()
|
||||
conn = db.connect(path)
|
||||
settings.ensure_defaults(conn)
|
||||
assert settings.get(conn, "settings_version") == 13
|
||||
assert "status_labels" not in settings.get_all(conn) and "transitions_map" not in settings.get_all(conn)
|
||||
conn.close()
|
||||
|
||||
@ -48,7 +48,7 @@ def test_import_notes_and_report(conn, tmp_path):
|
||||
rep = importer.import_package(conn, tmp_path)
|
||||
assert rep["notes"] == 6
|
||||
n = mirror.get_note(conn, "AURORA-1533")
|
||||
assert n["work_kind"] == "тестирование" and n.get("fact_status") is None # колонка CSV пропускается (fact-status-removal)
|
||||
assert n["work_kind"] == "тестирование" and "fact_status" not in n # колонка CSV пропускается (fact-status-removal)
|
||||
assert n["rest_text"] == "Прогнать на стенде" and n["owner_note"] == "Актуализация 10.10.2026. Порядок" and n["updated_by"] == "import"
|
||||
assert mirror.get_note(conn, "AURORA-1416")["done_text"] == "Сделан список"
|
||||
assert mirror.get_note(conn, "AURORA-1586")["rest_text"] == "решение 11.10"
|
||||
|
||||
@ -55,7 +55,9 @@ def test_protected_keys(conn, key):
|
||||
def test_init_from_config(conn):
|
||||
cfg = json.loads(FIXTURE.read_text(encoding="utf-8"))
|
||||
keys = jira_settings.init_from_config(conn, cfg)
|
||||
assert "transitions_map" in keys and "base_jql" not in keys and "board_id" not in keys
|
||||
assert "link_types" in keys and "base_jql" not in keys and "board_id" not in keys
|
||||
assert "transitions_map" not in keys and "status_labels" not in keys # fact-status-removal
|
||||
assert {"transitions_map", "status_labels"}.isdisjoint(settings.get_all(conn))
|
||||
assert "base_jql" not in settings.get_all(conn) and "board_id" not in settings.get_all(conn)
|
||||
assert settings.get(conn, "field_ids")["planned_end"] == "customfield_10802"
|
||||
assert settings.get(conn, "issue_types")["epic"] == {"name": "Фича", "id": "12300"}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user