From 0532b2476cac76b6c2eae85989c01cc970a677e9 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 14 Oct 2026 12:37:20 +0400 Subject: [PATCH] =?UTF-8?q?fix(agent):=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B8=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D0=B9=20=D1=81=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BD=D0=B8=D0=B2=D0=B0=D1=8E=D1=82=D1=81=D1=8F=20=D0=B1=D0=B5?= =?UTF-8?q?=D0=B7=20=D1=80=D0=B0=D0=B7=D0=BB=D0=B8=D1=87=D0=B8=D1=8F=20CRL?= =?UTF-8?q?F/LF=20(#15)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit T3.9 (agent#4). Co-Authored-By: Claude Opus 5.5 --- src/agent.py | 9 +++++++-- tests/test_executor_fields.py | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/agent.py b/src/agent.py index 37144eb..c90bd55 100644 --- a/src/agent.py +++ b/src/agent.py @@ -453,6 +453,11 @@ def _date(value) -> Optional[str]: return (value or "")[:10] or None +def _nl(value) -> str: + r"""Текст для сравнения: Jira хранит правленное в UI с \r\n, команды приходят с \n (T3.9, проверено 13.10.2026).""" + return (value or "").replace("\r\n", "\n") + + class ConfigGap(Exception): """В настройках хаба нет того, что нужно команде (R-11): команда падает с понятным текстом, а не молча теряет поле.""" @@ -567,7 +572,7 @@ class Executor: if "summary" in p and (cur.get("summary") or "") != (p["summary"] or ""): fields["summary"] = p["summary"] changed.append("summary") - if "description" in p and (cur.get(self.fid("description")) or "") != (p["description"] or ""): + if "description" in p and _nl(cur.get(self.fid("description"))) != _nl(p["description"]): fields[self.fid("description")] = p["description"] changed.append("description") if "priority" in p: @@ -622,7 +627,7 @@ class Executor: start += len(comments) if not comments or page.get("total") is None or start >= int(page["total"]): break - if existing and (existing.get("body") or "") == body: + if existing and _nl(existing.get("body")) == _nl(body): return self._out("done", {"comment_id": existing["id"], "changed": False}) if existing: self.jira.put(API + "/issue/%s/comment/%s" % (key, existing["id"]), {"body": body}) diff --git a/tests/test_executor_fields.py b/tests/test_executor_fields.py index 8d29b78..aa0e949 100644 --- a/tests/test_executor_fields.py +++ b/tests/test_executor_fields.py @@ -101,6 +101,25 @@ class ExecutorFieldsTest(unittest.TestCase): self.assertEqual(len(self.fake.comments["AURORA-1"]), 1) self.assertEqual(self.fake.comments["AURORA-1"][0]["body"], "*Актуализация 10.10.2026.* Сделано: всё") + def test_fields_description_crlf_equals_lf(self): + self.fake.add("AURORA-1", description="а\r\nб") # так Jira хранит текст, правленный в UI + out = self.run_cmd("ensure_fields", key="AURORA-1", description="а\nб") + self.assertEqual(out["result"]["changed"], []) + out = self.run_cmd("ensure_fields", key="AURORA-1", description="а\nв") + self.assertEqual(out["result"]["changed"], ["description"]) + self.assertEqual(self.fake.issues["AURORA-1"]["description"], "а\nв") # отправлен текст команды как есть + + def test_fields_description_none_equals_empty(self): + self.fake.add("AURORA-1", description=None) + out = self.run_cmd("ensure_fields", key="AURORA-1", description="") + self.assertEqual(out["result"]["changed"], []) + + def test_comment_crlf_equals_lf(self): + self.fake.add("AURORA-1") + self.fake.comments["AURORA-1"] = [{"id": "10", "body": "*Актуализация 10.10.2026.* строка1\r\nстрока2"}] + out = self.run_cmd("ensure_comment", key="AURORA-1", marker="Актуализация 10.10.2026", body="строка1\nстрока2") + self.assertEqual(out["result"], {"comment_id": "10", "changed": False}) + def test_unknown_type(self): self.assertEqual(self.run_cmd("ensure_magic", key="x")["status"], "failed")