Esempio n. 1
0
        /// <summary>
        /// Convert an entire Azure DevOps Pipeline to a GitHub Actions
        /// </summary>
        /// <param name="input">Yaml to convert</param>
        /// <returns>Converion object, with original yaml, processed yaml, and comments on the conversion</returns>
        public ConversionResponse ConvertAzurePipelineToGitHubAction(string input)
        {
            List <string>     variableList = new List <string>();
            string            yaml;
            GitHubActionsRoot gitHubActions = null;

            //Triggers and variables are hard, as there are two data types for each that can exist, so we need to go with the most common type and handle the less common type with exceptions.
            //There are 4 combinations here, simple/simple, simple/complex, complex/simple, and complex/complex
            AzurePipelinesRoot <string[], Dictionary <string, string> > azurePipelineWithSimpleTriggerAndSimpleVariables  = null;
            AzurePipelinesRoot <string[], AzurePipelines.Variable[]>    azurePipelineWithSimpleTriggerAndComplexVariables = null;
            AzurePipelinesRoot <AzurePipelines.Trigger, Dictionary <string, string> > azurePipelineWithComplexTriggerAndSimpleVariables  = null;
            AzurePipelinesRoot <AzurePipelines.Trigger, AzurePipelines.Variable[]>    azurePipelineWithComplexTriggerAndComplexVariables = null;

            try
            {
                azurePipelineWithSimpleTriggerAndSimpleVariables = AzurePipelinesSerialization <string[], Dictionary <string, string> > .DeserializeSimpleTriggerAndSimpleVariables(input);
            }
            catch
            {
                try
                {
                    azurePipelineWithComplexTriggerAndSimpleVariables = AzurePipelinesSerialization <AzurePipelines.Trigger, Dictionary <string, string> > .DeserializeComplexTriggerAndSimpleVariables(input);
                }
                catch
                {
                    try
                    {
                        azurePipelineWithSimpleTriggerAndComplexVariables = AzurePipelinesSerialization <string[], AzurePipelines.Variable[]> .DeserializeSimpleTriggerAndComplexVariables(input);
                    }
                    catch
                    {
                        azurePipelineWithComplexTriggerAndComplexVariables = AzurePipelinesSerialization <AzurePipelines.Trigger, AzurePipelines.Variable[]> .DeserializeComplexTriggerAndComplexVariables(input);
                    }
                }
            }
            //Generate the github actions
            if (azurePipelineWithSimpleTriggerAndSimpleVariables != null)
            {
                PipelineProcessing <string[], Dictionary <string, string> > processing = new PipelineProcessing <string[], Dictionary <string, string> >();
                gitHubActions = processing.ProcessPipeline(azurePipelineWithSimpleTriggerAndSimpleVariables, azurePipelineWithSimpleTriggerAndSimpleVariables.trigger, null, azurePipelineWithSimpleTriggerAndSimpleVariables.variables, null);
                if (processing.MatrixVariableName != null)
                {
                    _matrixVariableName = processing.MatrixVariableName;
                }
                variableList.AddRange(processing.VariableList);
            }
            else if (azurePipelineWithSimpleTriggerAndComplexVariables != null)
            {
                PipelineProcessing <string[], AzurePipelines.Variable[]> processing = new PipelineProcessing <string[], AzurePipelines.Variable[]>();
                gitHubActions = processing.ProcessPipeline(azurePipelineWithSimpleTriggerAndComplexVariables, azurePipelineWithSimpleTriggerAndComplexVariables.trigger, null, null, azurePipelineWithSimpleTriggerAndComplexVariables.variables);
                if (processing.MatrixVariableName != null)
                {
                    _matrixVariableName = processing.MatrixVariableName;
                }
                variableList.AddRange(processing.VariableList);
            }
            else if (azurePipelineWithComplexTriggerAndSimpleVariables != null)
            {
                PipelineProcessing <AzurePipelines.Trigger, Dictionary <string, string> > processing = new PipelineProcessing <AzurePipelines.Trigger, Dictionary <string, string> >();
                gitHubActions = processing.ProcessPipeline(azurePipelineWithComplexTriggerAndSimpleVariables, null, azurePipelineWithComplexTriggerAndSimpleVariables.trigger, azurePipelineWithComplexTriggerAndSimpleVariables.variables, null);
                if (processing.MatrixVariableName != null)
                {
                    _matrixVariableName = processing.MatrixVariableName;
                }
                variableList.AddRange(processing.VariableList);
            }
            else if (azurePipelineWithComplexTriggerAndComplexVariables != null)
            {
                PipelineProcessing <AzurePipelines.Trigger, AzurePipelines.Variable[]> processing = new PipelineProcessing <AzurePipelines.Trigger, AzurePipelines.Variable[]>();
                gitHubActions = processing.ProcessPipeline(azurePipelineWithComplexTriggerAndComplexVariables, null, azurePipelineWithComplexTriggerAndComplexVariables.trigger, null, azurePipelineWithComplexTriggerAndComplexVariables.variables);
                if (processing.MatrixVariableName != null)
                {
                    _matrixVariableName = processing.MatrixVariableName;
                }
                variableList.AddRange(processing.VariableList);
            }

            //Commented out the new solution, as it doesn't process failed/invalid documents.
            //var success = false;
            //if (!success)
            //{
            //    var azurePipelineWithSimpleTriggerAndSimpleVariables = AzurePipelinesSerialization<string[], Dictionary<string, string>>.DeserializeSimpleTriggerAndSimpleVariables(input);
            //    if (azurePipelineWithSimpleTriggerAndSimpleVariables != null)
            //    {
            //        success = true;
            //        PipelineProcessing<string[], Dictionary<string, string>> processing = new PipelineProcessing<string[], Dictionary<string, string>>();
            //        gitHubActions = processing.ProcessPipeline(azurePipelineWithSimpleTriggerAndSimpleVariables, azurePipelineWithSimpleTriggerAndSimpleVariables.trigger, null, azurePipelineWithSimpleTriggerAndSimpleVariables.variables, null);
            //        if (processing.MatrixVariableName != null)
            //        {
            //            _matrixVariableName = processing.MatrixVariableName;
            //        }
            //        variableList.AddRange(processing.VariableList);
            //    }
            //}

            //if (!success)
            //{
            //    var azurePipelineWithSimpleTriggerAndComplexVariables = AzurePipelinesSerialization<string[], AzurePipelines.Variable[]>.DeserializeSimpleTriggerAndComplexVariables(input);
            //    if (azurePipelineWithSimpleTriggerAndComplexVariables != null)
            //    {
            //        success = true;
            //        PipelineProcessing<string[], AzurePipelines.Variable[]> processing = new PipelineProcessing<string[], AzurePipelines.Variable[]>();
            //        gitHubActions = processing.ProcessPipeline(azurePipelineWithSimpleTriggerAndComplexVariables, azurePipelineWithSimpleTriggerAndComplexVariables.trigger, null, null, azurePipelineWithSimpleTriggerAndComplexVariables.variables);
            //        if (processing.MatrixVariableName != null)
            //        {
            //            _matrixVariableName = processing.MatrixVariableName;
            //        }
            //        variableList.AddRange(processing.VariableList);
            //    }
            //}

            //if (!success)
            //{
            //    var azurePipelineWithComplexTriggerAndSimpleVariables = AzurePipelinesSerialization<AzurePipelines.Trigger, Dictionary<string, string>>.DeserializeComplexTriggerAndSimpleVariables(input);
            //    if (azurePipelineWithComplexTriggerAndSimpleVariables != null)
            //    {
            //        success = true;
            //        PipelineProcessing<AzurePipelines.Trigger, Dictionary<string, string>> processing = new PipelineProcessing<AzurePipelines.Trigger, Dictionary<string, string>>();
            //        gitHubActions = processing.ProcessPipeline(azurePipelineWithComplexTriggerAndSimpleVariables, null, azurePipelineWithComplexTriggerAndSimpleVariables.trigger, azurePipelineWithComplexTriggerAndSimpleVariables.variables, null);
            //        if (processing.MatrixVariableName != null)
            //        {
            //            _matrixVariableName = processing.MatrixVariableName;
            //        }
            //        variableList.AddRange(processing.VariableList);
            //    }
            //}

            //if (!success)
            //{
            //    var azurePipelineWithComplexTriggerAndComplexVariables = AzurePipelinesSerialization<AzurePipelines.Trigger, AzurePipelines.Variable[]>.DeserializeComplexTriggerAndComplexVariables(input);
            //    if (azurePipelineWithComplexTriggerAndComplexVariables != null)
            //    {
            //        PipelineProcessing<AzurePipelines.Trigger, AzurePipelines.Variable[]> processing = new PipelineProcessing<AzurePipelines.Trigger, AzurePipelines.Variable[]>();
            //        gitHubActions = processing.ProcessPipeline(azurePipelineWithComplexTriggerAndComplexVariables, null, azurePipelineWithComplexTriggerAndComplexVariables.trigger, null, azurePipelineWithComplexTriggerAndComplexVariables.variables);
            //        if (processing.MatrixVariableName != null)
            //        {
            //            _matrixVariableName = processing.MatrixVariableName;
            //        }
            //        variableList.AddRange(processing.VariableList);
            //    }
            //}
            //if (!success)
            //{
            //    throw new NotSupportedException("All deserialisation methods failed... oops! Please create a GitHub issue so we can fix this");
            //}

            //Search for any other variables. Duplicates are ok, they are processed the same
            variableList.AddRange(SearchForVariables(input));

            //Create the YAML and apply some adjustments
            if (gitHubActions != null)
            {
                yaml = GitHubActionsSerialization.Serialize(gitHubActions, variableList, _matrixVariableName);
            }
            else
            {
                yaml = "";
            }

            //Load failed task comments for processing
            List <string> stepComments = new List <string>();

            if (gitHubActions != null)
            {
                //Add any header messages
                if (gitHubActions.messages != null)
                {
                    foreach (string message in gitHubActions.messages)
                    {
                        stepComments.Add(ConvertMessageToYamlComment(message));
                    }
                }
                if (gitHubActions.jobs != null)
                {
                    //Add each individual step comments
                    foreach (KeyValuePair <string, GitHubActions.Job> job in gitHubActions.jobs)
                    {
                        if (job.Value.steps != null)
                        {
                            if (job.Value.job_message != null)
                            {
                                stepComments.Add(ConvertMessageToYamlComment(job.Value.job_message));
                            }
                            foreach (GitHubActions.Step step in job.Value.steps)
                            {
                                if (step != null && string.IsNullOrEmpty(step.step_message) == false)
                                {
                                    stepComments.Add(ConvertMessageToYamlComment(step.step_message));
                                }
                            }
                        }
                    }
                }
            }

            //Append all of the comments to the top of the file
            foreach (string item in stepComments)
            {
                yaml = item + Environment.NewLine + yaml;
            }

            //Return the final conversion result, with the original (pipeline) yaml, processed (actions) yaml, and any comments
            return(new ConversionResponse
            {
                pipelinesYaml = input,
                actionsYaml = yaml,
                comments = stepComments
            });
        }
Esempio n. 2
0
        /// <summary>
        /// V1 plan:
        /// 1. get the yaml
        /// 2. try to deserialize the entire doc on a few common combinations
        /// 3. convert the azure pipelines objects into a github action
        /// </summary>
        /// <param name="yaml"></param>
        /// <returns></returns>
        private ConversionResponse ConvertAzurePipelineToGitHubActionV1(string yaml)
        {
            string            gitHubYaml;
            List <string>     variableList  = new List <string>();
            List <string>     stepComments  = new List <string>();
            GitHubActionsRoot gitHubActions = null;

            //Run some processing to convert simple pools and demands to the complex editions, to avoid adding to the combinations below.
            //Also clean and remove variables with reserved words that get into trouble during deserialization. HACK alert... :(
            string processedInput = ConversionUtility.CleanYamlBeforeDeserialization(yaml);

            //Start the main deserialization methods
            bool success = false;

            if (success == false)
            {
                var azurePipelineWithSimpleTriggerAndSimpleVariables = AzurePipelinesSerialization <string[], Dictionary <string, string> > .DeserializeSimpleTriggerAndSimpleVariables(processedInput);

                if (azurePipelineWithSimpleTriggerAndSimpleVariables != null)
                {
                    success = true;
                    var pp = new PipelineProcessing <string[], Dictionary <string, string> >(_verbose);
                    gitHubActions = pp.ProcessPipeline(azurePipelineWithSimpleTriggerAndSimpleVariables, azurePipelineWithSimpleTriggerAndSimpleVariables.trigger, null, azurePipelineWithSimpleTriggerAndSimpleVariables.variables, null);
                    if (pp.MatrixVariableName != null)
                    {
                        _matrixVariableName = pp.MatrixVariableName;
                    }
                    variableList.AddRange(pp.VariableList);
                }
            }

            if (success == false)
            {
                var azurePipelineWithSimpleTriggerAndComplexVariables = AzurePipelinesSerialization <string[], AzurePipelines.Variable[]> .DeserializeSimpleTriggerAndComplexVariables(processedInput);

                if (azurePipelineWithSimpleTriggerAndComplexVariables != null)
                {
                    success = true;
                    var pp = new PipelineProcessing <string[], AzurePipelines.Variable[]>(_verbose);
                    gitHubActions = pp.ProcessPipeline(azurePipelineWithSimpleTriggerAndComplexVariables, azurePipelineWithSimpleTriggerAndComplexVariables.trigger, null, null, azurePipelineWithSimpleTriggerAndComplexVariables.variables);
                    if (pp.MatrixVariableName != null)
                    {
                        _matrixVariableName = pp.MatrixVariableName;
                    }
                    variableList.AddRange(pp.VariableList);
                }
            }

            if (success == false)
            {
                var azurePipelineWithComplexTriggerAndSimpleVariables = AzurePipelinesSerialization <AzurePipelines.Trigger, Dictionary <string, string> > .DeserializeComplexTriggerAndSimpleVariables(processedInput);

                if (azurePipelineWithComplexTriggerAndSimpleVariables != null)
                {
                    success = true;
                    var pp = new PipelineProcessing <AzurePipelines.Trigger, Dictionary <string, string> >(_verbose);
                    gitHubActions = pp.ProcessPipeline(azurePipelineWithComplexTriggerAndSimpleVariables, null, azurePipelineWithComplexTriggerAndSimpleVariables.trigger, azurePipelineWithComplexTriggerAndSimpleVariables.variables, null);
                    if (pp.MatrixVariableName != null)
                    {
                        _matrixVariableName = pp.MatrixVariableName;
                    }
                    variableList.AddRange(pp.VariableList);
                }
            }

            if (success == false)
            {
                var azurePipelineWithComplexTriggerAndComplexVariables = AzurePipelinesSerialization <AzurePipelines.Trigger, AzurePipelines.Variable[]> .DeserializeComplexTriggerAndComplexVariables(processedInput);

                if (azurePipelineWithComplexTriggerAndComplexVariables != null)
                {
                    success = true;
                    var pp = new PipelineProcessing <AzurePipelines.Trigger, AzurePipelines.Variable[]>(_verbose);
                    gitHubActions = pp.ProcessPipeline(azurePipelineWithComplexTriggerAndComplexVariables, null, azurePipelineWithComplexTriggerAndComplexVariables.trigger, null, azurePipelineWithComplexTriggerAndComplexVariables.variables);
                    if (pp.MatrixVariableName != null)
                    {
                        _matrixVariableName = pp.MatrixVariableName;
                    }
                    variableList.AddRange(pp.VariableList);
                }
            }
            if (success == false && string.IsNullOrEmpty(processedInput?.Trim()) == false)
            {
                throw new NotSupportedException("All deserialisation methods failed... oops! Please create a GitHub issue so we can fix this");
            }

            //Search for any other variables. Duplicates are ok, they are processed the same
            VariablesProcessing vp = new VariablesProcessing(_verbose);

            variableList.AddRange(vp.SearchForVariables(processedInput));

            //Create the GitHub YAML and apply some adjustments
            if (gitHubActions != null)
            {
                gitHubYaml = GitHubActionsSerialization.Serialize(gitHubActions, variableList, _matrixVariableName);
            }
            else
            {
                gitHubYaml = "";
            }

            //Load failed task comments for processing
            if (gitHubActions != null)
            {
                //Add any header messages
                if (gitHubActions.messages != null)
                {
                    foreach (string message in gitHubActions.messages)
                    {
                        stepComments.Add(ConversionUtility.ConvertMessageToYamlComment(message));
                    }
                }
                if (gitHubActions.jobs != null)
                {
                    //Add each individual step comments
                    foreach (KeyValuePair <string, GitHubActions.Job> job in gitHubActions.jobs)
                    {
                        if (job.Value.steps != null)
                        {
                            if (job.Value.job_message != null)
                            {
                                stepComments.Add(ConversionUtility.ConvertMessageToYamlComment(job.Value.job_message));
                            }
                            foreach (GitHubActions.Step step in job.Value.steps)
                            {
                                if (step != null && string.IsNullOrEmpty(step.step_message) == false)
                                {
                                    stepComments.Add(ConversionUtility.ConvertMessageToYamlComment(step.step_message));
                                }
                            }
                        }
                    }
                }
            }

            //Append all of the comments to the top of the file
            foreach (string item in stepComments)
            {
                gitHubYaml = item + System.Environment.NewLine + gitHubYaml;
            }

            //Return the final conversion result, with the original (pipeline) yaml, processed (actions) yaml, and any comments
            return(new ConversionResponse
            {
                pipelinesYaml = yaml,
                actionsYaml = gitHubYaml,
                comments = stepComments,
                v2ConversionSuccessful = false
            });
        }