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")