package org.wamblee.jenkins.pipelinelib @Grab('org.yaml:snakeyaml:1.25') import org.yaml.snakeyaml.Yaml import org.yaml.snakeyaml.constructor.SafeConstructor /* Original reference: https://github.com/OndraZizka/yaml-merge/blob/master/src/main/java/org/cobbzilla/util/yml/YmlMerger.java */ class MyYaml { private final Yaml parser MyYaml() { parser = new Yaml(new SafeConstructor()) } String merge(List yamls) { Map mergedResult = new LinkedHashMap(); for (yaml in yamls) { final Map yamlToMerge = parser.load(yaml) // Merge into results map. mergeStructures(mergedResult, yamlToMerge) } return parser.dump(mergedResult) } private static Object addToMergedResult(Map mergedResult, String key, Object yamlValue) { return mergedResult.put(key, yamlValue) } private static IllegalArgumentException unknownValueType(String key, Object yamlValue) { final String msg = "Cannot mergeYamlFiles element of unknown type: " + key + ": " + yamlValue.getClass().getName() return new IllegalArgumentException(msg) } private void mergeLists(Map mergedResult, String key, Object yamlValue) { if (!(yamlValue instanceof List && mergedResult.get(key) instanceof List)) { throw new IllegalArgumentException("Cannot mergeYamlFiles a list with a non-list: " + key) } List originalList = (List) mergedResult.get(key) // original implementation // originalList.addAll((List) yamlValue) // my implementation // below is non-standard approach as I assume a key:value mapping called (name->value) to identify a Map List yamlList = (List) yamlValue Map originalCache = new LinkedHashMap<>() String name for (ori in originalList) { if (ori instanceof Map) { name = ori.get('name') if (name) { originalCache.put(name, ori) } } } def merged for (item in yamlList) { merged = false if (item instanceof Map) { name = item.get('name') if (name && originalCache.containsKey(name)) { mergeStructures((Map) originalCache.get(name), (Map) item) merged = true } } if (!merged) { originalList.add(item) } } } private void mergeStructures(Map targetTree, Map sourceTree) { if (sourceTree == null) return for (String key : sourceTree.keySet()) { Object yamlValue = sourceTree.get(key) if (yamlValue == null) { addToMergedResult(targetTree, key, yamlValue) continue } Object existingValue = targetTree.get(key); if (existingValue != null) { if (yamlValue instanceof Map) { if (existingValue instanceof Map) { mergeStructures((Map) existingValue, (Map) yamlValue); } else if (existingValue instanceof String) { throw new IllegalArgumentException("Cannot mergeYamlFiles complex element into a simple element: " + key) } else { throw unknownValueType(key, yamlValue) } } else if (yamlValue instanceof List) { mergeLists(targetTree, key, yamlValue) } else if (yamlValue instanceof String || yamlValue instanceof Boolean || yamlValue instanceof Double || yamlValue instanceof Integer) { addToMergedResult(targetTree, key, yamlValue) } else { throw unknownValueType(key, yamlValue) } } else { if (yamlValue instanceof Map || yamlValue instanceof List || yamlValue instanceof String || yamlValue instanceof Boolean || yamlValue instanceof Integer || yamlValue instanceof Double) { addToMergedResult(targetTree, key, yamlValue) } else { throw unknownValueType(key, yamlValue) } } } } }