/// <summary> /// Deserialize an Azure DevOps Pipeline with a complex trigger and simple variable list /// </summary> /// <param name="yaml">yaml to convert</param> /// <returns>Azure DevOps Pipeline with complex trigger and simple variables</returns> public static AzurePipelinesRoot <AzurePipelines.Trigger, Dictionary <string, string> > DeserializeComplexTriggerAndSimpleVariables(string yaml) { AzurePipelinesRoot <AzurePipelines.Trigger, Dictionary <string, string> > azurePipeline = null; try { yaml = CleanYamlBeforeDeserialization(yaml); azurePipeline = GenericObjectSerialization.DeserializeYaml <AzurePipelinesRoot <AzurePipelines.Trigger, Dictionary <string, string> > >(yaml); } catch (Exception ex) { ConversionUtility.WriteLine($"{nameof(DeserializeComplexTriggerAndSimpleVariables)} swallowed an exception: " + ex.Message, true); //Do nothing } return(azurePipeline); }
private static string CleanYamlBeforeDeserialization(string yaml) { //Handle a null input if (yaml == null) { yaml = ""; } //Not well documented, but repo:self is redundent, and hence we remove it if detected (https://stackoverflow.com/questions/53860194/azure-devops-resources-repo-self) yaml = yaml.Replace("- repo: self", ""); //Fix some variables that we can't use for property names because the "-" character is not allowed in c# properties, or it's a reserved word (e.g. if) yaml = yaml.Replace("ref:", "_ref:"); //Handle condition variable insertion syntax. This is a bit ugly. if (yaml.IndexOf("variables") >= 0) { StringBuilder processedYaml = new StringBuilder(); using (StringReader reader = new StringReader(yaml)) { int variablesIndentLevel = 0; bool scanningForVariables = false; string line; while ((line = reader.ReadLine()) != null) { //Find the lines with variables if (line.IndexOf("variables:") >= 0) { //Start tracking variables and record the variables indent level scanningForVariables = true; variablesIndentLevel = ConversionUtility.CountSpacesBeforeText(line); } else if (scanningForVariables == true) { //While scanning for variables, get the indent level. It should be (variablesIndentLevel + 2), if it's more than that, we have a variable insert. ConversionUtility.WriteLine("Scanning for vars: " + line, true); int lineIndentLevel = ConversionUtility.CountSpacesBeforeText(line); if ((variablesIndentLevel - (lineIndentLevel - 2)) == 0) { //If the line starts with a conditional insertation, then comment it out if (line.Trim().StartsWith("${{") == true) { line = "#" + line; } } else if (variablesIndentLevel - (lineIndentLevel - 2) <= 0) { //we found a variable insert and need to remove the first two spaces from the front of the variable line = line.Substring(2, line.Length - 2); } else if (variablesIndentLevel - (lineIndentLevel - 2) >= 0) //we are done with variables, and back at the next root node { scanningForVariables = false; } } processedYaml.AppendLine(line); } } yaml = processedYaml.ToString(); } return(yaml); }