Repository navigation
Expand file tree
/
Copy pathtest_github_sync_preserves_issue.py
More file actions
120 lines (85 loc) · 4.13 KB
/
Copy pathtest_github_sync_preserves_issue.py
File metadata and controls
120 lines (85 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""An outbound sync must not delete or resurrect what a tracker already holds.
`semcod/fixos#46` lost 28 lines of evidence and a dated title on 2026-09-16,
when a sync replaced its body with the ticket description. The issue state is a
separate question, recorded in #125: the reopen that resurrected
`subactor/onedev-agent#395` is asserted deliberately by ticket-101's routing
tests, so it is the owner's call and not changed here.
"""
from __future__ import annotations
from types import SimpleNamespace
from planfile.sync.github import GitHubBackend
class FakeIssue(SimpleNamespace):
def __init__(self, **kwargs):
super().__init__(edits=[], **kwargs)
def edit(self, **kwargs):
self.edits.append(kwargs)
if "body" in kwargs:
self.body = kwargs["body"]
if "title" in kwargs:
self.title = kwargs["title"]
if "state" in kwargs:
self.state = kwargs["state"]
class FakeRepo:
full_name = "semcod/fixos"
def __init__(self, issue):
self.issue = issue
def get_issue(self, number):
return self.issue
def get_labels(self):
return []
def _backend(issue: FakeIssue) -> GitHubBackend:
backend = GitHubBackend.__new__(GitHubBackend)
backend.config = {"repo": "semcod/fixos"}
backend.repo = FakeRepo(issue)
return backend
EVIDENCE = (
"<!-- planfile:deduplication-key=DFU0915-001 -->\n"
"## Kontekst\n\n"
"`uv lock --check`: exit 0 on 5016406^, exit 1 on main.\n\n"
"## Blokery\n\n- GOV-WORKSTREAM-002\n"
)
def test_update_keeps_the_issue_body_and_owns_only_its_section():
issue = FakeIssue(number=46, title="Kontynuacja 2026-09-15: relock uv.lock", state="open", body=EVIDENCE)
_backend(issue)._update_ticket("46", name="Kontynuacja: relock uv.lock", body="Planning-only record.")
assert "## Kontekst" in issue.body
assert "GOV-WORKSTREAM-002" in issue.body
assert "<!-- planfile:deduplication-key=DFU0915-001 -->" in issue.body
assert GitHubBackend.DESCRIPTION_START in issue.body
assert "Planning-only record." in issue.body
# A rename is a deliberate action on the issue, not a sync side effect.
assert issue.title == "Kontynuacja 2026-09-15: relock uv.lock"
assert all("title" not in edit for edit in issue.edits)
def test_second_update_replaces_the_section_without_stacking_it():
issue = FakeIssue(number=46, title="t", state="open", body=EVIDENCE)
backend = _backend(issue)
backend._update_ticket("46", body="first")
backend._update_ticket("46", body="second")
assert issue.body.count(GitHubBackend.DESCRIPTION_START) == 1
assert "second" in issue.body
assert "first" not in issue.body
assert "## Kontekst" in issue.body
def test_update_writes_nothing_when_the_body_already_matches():
issue = FakeIssue(number=46, title="t", state="open", body=EVIDENCE)
backend = _backend(issue)
backend._update_ticket("46", body="same")
edits_after_first = len(issue.edits)
backend._update_ticket("46", body="same")
assert len(issue.edits) == edits_after_first
def test_an_empty_issue_body_becomes_just_the_section():
issue = FakeIssue(number=7, title="t", state="open", body=None)
_backend(issue)._update_ticket("7", body="only record")
assert issue.body == f"{GitHubBackend.DESCRIPTION_START}\nonly record\n{GitHubBackend.DESCRIPTION_END}"
def test_outbound_body_update_respects_github_title_policy(tmp_path):
from planfile.core.store import Store
from planfile.sync.outbound import sync_to_external
issue = FakeIssue(number=46, title='Deliberate remote title', state='open', body=EVIDENCE,
html_url='https://github.com/semcod/fixos/issues/46')
store = Store(tmp_path)
store.init()
ticket = {'id': 'PLF-1', 'name': 'Local planning label', 'description': 'Updated plan',
'sync': {'github': {'id': '46', 'repository': 'semcod/fixos'}}}
result = sync_to_external(_backend(issue), [('PLF-1', ticket)], False, store, 'github')
assert result.succeeded == ('PLF-1',)
assert result.failed == ()
assert issue.title == 'Deliberate remote title'
assert 'Updated plan' in issue.body