Skip to content

Commit aa04266

Browse files
committed
Add support for changelog conflict resolution for attribute properties
1 parent 85e5c1d commit aa04266

File tree

2 files changed

+76
-20
lines changed

2 files changed

+76
-20
lines changed

backend/infrahub/core/changelog/diff.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -92,29 +92,33 @@ def _process_node_attribute(
9292
changelog_attribute.value = attr_property.new_value
9393
changelog_attribute.value_previous = attr_property.previous_value
9494
case DatabaseEdgeType.IS_PROTECTED:
95-
changelog_attribute.add_property(
96-
name="is_protected",
97-
value_current=self._convert_string_boolean_value(value=attr_property.new_value),
98-
value_previous=self._convert_string_boolean_value(value=attr_property.previous_value),
99-
)
95+
if _keep_branch_update(diff_property=attr_property):
96+
changelog_attribute.add_property(
97+
name="is_protected",
98+
value_current=self._convert_string_boolean_value(value=attr_property.new_value),
99+
value_previous=self._convert_string_boolean_value(value=attr_property.previous_value),
100+
)
100101
case DatabaseEdgeType.IS_VISIBLE:
101-
changelog_attribute.add_property(
102-
name="is_visible",
103-
value_current=self._convert_string_boolean_value(value=attr_property.new_value),
104-
value_previous=self._convert_string_boolean_value(value=attr_property.previous_value),
105-
)
102+
if _keep_branch_update(diff_property=attr_property):
103+
changelog_attribute.add_property(
104+
name="is_visible",
105+
value_current=self._convert_string_boolean_value(value=attr_property.new_value),
106+
value_previous=self._convert_string_boolean_value(value=attr_property.previous_value),
107+
)
106108
case DatabaseEdgeType.HAS_SOURCE:
107-
changelog_attribute.add_property(
108-
name="source",
109-
value_current=attr_property.new_value,
110-
value_previous=attr_property.previous_value,
111-
)
109+
if _keep_branch_update(diff_property=attr_property):
110+
changelog_attribute.add_property(
111+
name="source",
112+
value_current=attr_property.new_value,
113+
value_previous=attr_property.previous_value,
114+
)
112115
case DatabaseEdgeType.HAS_OWNER:
113-
changelog_attribute.add_property(
114-
name="owner",
115-
value_current=attr_property.new_value,
116-
value_previous=attr_property.previous_value,
117-
)
116+
if _keep_branch_update(diff_property=attr_property):
117+
changelog_attribute.add_property(
118+
name="owner",
119+
value_current=attr_property.new_value,
120+
value_previous=attr_property.previous_value,
121+
)
118122

119123
node.add_attribute(attribute=changelog_attribute)
120124

backend/tests/unit/core/changelog/test_diff.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,55 @@ async def test_diff_and_merge_with_attribute_value_conflict(
212212
assert action == DiffAction.UPDATED
213213
assert node_changelog.attributes["name"].value == "John-branch"
214214
assert node_changelog.attributes["name"].value_previous == "John"
215+
216+
@pytest.mark.parametrize(
217+
"conflict_selection",
218+
[ConflictSelection.BASE_BRANCH, ConflictSelection.DIFF_BRANCH],
219+
)
220+
async def test_diff_and_merge_with_attribute_property_conflict(
221+
self,
222+
db: InfrahubDatabase,
223+
default_branch: Branch,
224+
diff_repository: DiffRepository,
225+
person_john_main: Node,
226+
person_jane_main: Node,
227+
person_alfred_main: Node,
228+
car_accord_main: Node,
229+
conflict_selection: ConflictSelection,
230+
):
231+
branch2 = await create_branch(db=db, branch_name="branch2")
232+
john_main = await NodeManager.get_one(db=db, id=person_john_main.id)
233+
john_main.name.source = person_alfred_main
234+
await john_main.save(db=db)
235+
john_branch = await NodeManager.get_one(db=db, branch=branch2, id=person_john_main.id)
236+
john_branch.name.source = person_jane_main
237+
await john_branch.save(db=db)
238+
239+
at = Timestamp()
240+
diff_coordinator = await self._get_diff_coordinator(db=db, branch=branch2)
241+
enriched_diff_metadata = await diff_coordinator.update_branch_diff(
242+
base_branch=default_branch, diff_branch=branch2
243+
)
244+
enriched_diff = await diff_repository.get_one(
245+
diff_branch_name=enriched_diff_metadata.diff_branch_name, diff_id=enriched_diff_metadata.uuid
246+
)
247+
conflicts_map = enriched_diff.get_all_conflicts()
248+
assert len(conflicts_map) == 1
249+
conflict = next(iter(conflicts_map.values()))
250+
await diff_repository.update_conflict_by_id(conflict_id=conflict.uuid, selection=conflict_selection)
251+
diff_merger = await self._get_diff_merger(db=db, branch=branch2)
252+
diff = await diff_merger.merge_graph(at=at)
253+
diff_events = DiffChangelogCollector(diff=diff, db=db, branch=branch2)
254+
events = diff_events.collect_changelogs()
255+
match conflict_selection:
256+
case ConflictSelection.BASE_BRANCH:
257+
# When we want to keep the conflict in the base branch we don't expect to see any updates after the merge
258+
assert len(events) == 0
259+
case ConflictSelection.DIFF_BRANCH:
260+
# Expect to see changes on the diff branch when we keep changes from that branch
261+
assert len(events) == 1
262+
event = events[0]
263+
action, node_changelog = event
264+
assert action == DiffAction.UPDATED
265+
assert node_changelog.attributes["name"].properties["source"].value == person_jane_main.id
266+
assert node_changelog.attributes["name"].properties["source"].value_previous is None

0 commit comments

Comments
 (0)