diff --git a/lib/galaxy/config/sample/tool_conf.xml.sample b/lib/galaxy/config/sample/tool_conf.xml.sample
index 57810365641a..218898880631 100644
--- a/lib/galaxy/config/sample/tool_conf.xml.sample
+++ b/lib/galaxy/config/sample/tool_conf.xml.sample
@@ -37,6 +37,7 @@
+
diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py
index 4bfccbf1dd0c..063f2c6aad36 100644
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -3601,6 +3601,62 @@ def produce_outputs(self, trans, out_data, output_collections, incoming, history
)
+class HarmonizeTool(DatabaseOperationTool):
+ tool_type = "harmonize_list"
+ require_terminal_states = False
+ require_dataset_ok = False
+
+ def produce_outputs(self, trans, out_data, output_collections, incoming, history, **kwds):
+ # Get the 2 input collections
+ hdca1 = incoming["input1"]
+ hdca2 = incoming["input2"]
+ # Get the elements of both collections
+ elements1 = hdca1.collection.elements
+ elements2 = hdca2.collection.elements
+ # Put elements in dictionary with identifiers:
+ old_elements1_dict = {}
+ for element in elements1:
+ old_elements1_dict[element.element_identifier] = element
+ old_elements2_dict = {}
+ for element in elements2:
+ old_elements2_dict[element.element_identifier] = element
+ # Get the list of final identifiers
+ final_sorted_identifiers = [
+ element.element_identifier for element in elements1 if element.element_identifier in old_elements2_dict
+ ]
+ # Raise Exception if it is empty
+ if len(final_sorted_identifiers) == 0:
+ # Create empty collections:
+ output_collections.create_collection(
+ next(iter(self.outputs.values())), "output1", elements={}, propagate_hda_tags=False
+ )
+ output_collections.create_collection(
+ next(iter(self.outputs.values())), "output2", elements={}, propagate_hda_tags=False
+ )
+ return
+
+ def output_with_selected_identifiers(old_elements_dict, output_label):
+ # Create a new dictionary with the elements in the good order
+ new_elements = {}
+ for identifier in final_sorted_identifiers:
+ dce_object = old_elements_dict[identifier].element_object
+ if getattr(dce_object, "history_content_type", None) == "dataset":
+ copied_dataset = dce_object.copy(copy_tags=dce_object.tags, flush=False)
+ else:
+ copied_dataset = dce_object.copy(flush=False)
+ new_elements[identifier] = copied_dataset
+ # Add datasets:
+ self._add_datasets_to_history(history, new_elements.values())
+ # Create collections:
+ output_collections.create_collection(
+ next(iter(self.outputs.values())), output_label, elements=new_elements, propagate_hda_tags=False
+ )
+
+ # Create outputs:
+ output_with_selected_identifiers(old_elements1_dict, "output1")
+ output_with_selected_identifiers(old_elements2_dict, "output2")
+
+
class RelabelFromFileTool(DatabaseOperationTool):
tool_type = "relabel_from_file"
diff --git a/lib/galaxy/tools/harmonize_two_collections_list.xml b/lib/galaxy/tools/harmonize_two_collections_list.xml
new file mode 100644
index 000000000000..7828ec5138e6
--- /dev/null
+++ b/lib/galaxy/tools/harmonize_two_collections_list.xml
@@ -0,0 +1,213 @@
+
+
+
+
+
+ operation_0335
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/functional/tools/sample_tool_conf.xml b/test/functional/tools/sample_tool_conf.xml
index 8df30a78eff6..f05e6574cb53 100644
--- a/test/functional/tools/sample_tool_conf.xml
+++ b/test/functional/tools/sample_tool_conf.xml
@@ -293,6 +293,7 @@
+