From 8bab76e043c54ec4ffc0f11ff04bdcab067f46a3 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sat, 24 Oct 2026 16:59:05 +0400 Subject: [PATCH] =?UTF-8?q?=D0=A1=D1=85=D0=B5=D0=BC=D0=B0=20v8:=20=D0=B1?= =?UTF-8?q?=D0=B5=D0=B7=20=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=84=D0=B0=D0=BA=D1=82=D1=83=20=D0=B8=20=D0=B5?= =?UTF-8?q?=D0=B3=D0=BE=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B5=D0=BA?= =?UTF-8?q?=20(#104)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- src/sdlc_hub/core/db.py | 8 +- src/sdlc_hub/modules/jira/schema.py | 1 - src/sdlc_hub/modules/jira/settings.py | 21 ++-- tests/fixtures/baseline/schema.expected.json | 4 +- .../fixtures/baseline/settings.expected.json | 4 - tests/test_agents.py | 7 +- tests/test_api.py | 2 +- tests/test_cli.py | 2 +- tests/test_db.py | 102 +++++++++++++++--- tests/test_importer.py | 2 +- tests/test_settings.py | 4 +- 11 files changed, 122 insertions(+), 35 deletions(-) diff --git a/src/sdlc_hub/core/db.py b/src/sdlc_hub/core/db.py index 6b064d0..45a88fc 100644 --- a/src/sdlc_hub/core/db.py +++ b/src/sdlc_hub/core/db.py @@ -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) } diff --git a/src/sdlc_hub/modules/jira/schema.py b/src/sdlc_hub/modules/jira/schema.py index 1248ee7..e728f11 100644 --- a/src/sdlc_hub/modules/jira/schema.py +++ b/src/sdlc_hub/modules/jira/schema.py @@ -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, diff --git a/src/sdlc_hub/modules/jira/settings.py b/src/sdlc_hub/modules/jira/settings.py index 2d78e91..dbb0af6 100644 --- a/src/sdlc_hub/modules/jira/settings.py +++ b/src/sdlc_hub/modules/jira/settings.py @@ -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", {})), } diff --git a/tests/fixtures/baseline/schema.expected.json b/tests/fixtures/baseline/schema.expected.json index 545b629..c7288d8 100644 --- a/tests/fixtures/baseline/schema.expected.json +++ b/tests/fixtures/baseline/schema.expected.json @@ -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 } diff --git a/tests/fixtures/baseline/settings.expected.json b/tests/fixtures/baseline/settings.expected.json index 79ac8d9..2e3eaa1 100644 --- a/tests/fixtures/baseline/settings.expected.json +++ b/tests/fixtures/baseline/settings.expected.json @@ -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 diff --git a/tests/test_agents.py b/tests/test_agents.py index 9a6d2f6..9cf1078 100644 --- a/tests/test_agents.py +++ b/tests/test_agents.py @@ -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} diff --git a/tests/test_api.py b/tests/test_api.py index 6688986..6abe76b 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -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 diff --git a/tests/test_cli.py b/tests/test_cli.py index 0799e63..57e443d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -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()) diff --git a/tests/test_db.py b/tests/test_db.py index f1076f7..8417898 100644 --- a/tests/test_db.py +++ b/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() diff --git a/tests/test_importer.py b/tests/test_importer.py index 634ce12..7c032a2 100644 --- a/tests/test_importer.py +++ b/tests/test_importer.py @@ -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" diff --git a/tests/test_settings.py b/tests/test_settings.py index 337bf24..ecf0971 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -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"}