public Pool ProcessPoolV2(string poolYaml)
        {
            Pool pool = null;

            if (poolYaml != null)
            {
                try
                {
                    //Most often, the pool will be in this structure
                    pool = GenericObjectSerialization.DeserializeYaml <Pool>(poolYaml);
                }
                catch (Exception ex)
                {
                    ConversionUtility.WriteLine($"DeserializeYaml<Pool>(poolYaml) swallowed an exception: " + ex.Message, _verbose);
                    //If it's a simple pool string, and has no json in it, assign it to the name
                    if (poolYaml.IndexOf("{") < 0)
                    {
                        pool = new Pool
                        {
                            name = poolYaml
                        };
                    }
                    else
                    {
                        //otherwise, demands is probably a string, instead of string[], let's fix it
                        JObject json = JSONSerialization.DeserializeStringToObject(poolYaml);
                        if (json["demands"].Type.ToString() == "String")
                        {
                            string name = null;
                            if (json["name"] != null)
                            {
                                name = json["name"].ToString();
                            }
                            string vmImage = null;
                            if (json["vmImage"] != null)
                            {
                                vmImage = json["vmImage"].ToString();
                            }
                            string demands = null;
                            if (json["demands"] != null)
                            {
                                demands = json["demands"].ToString();
                            }
                            pool = new Pool
                            {
                                name    = name,
                                vmImage = vmImage
                            };
                            //Move the single string demands to an array
                            pool.demands    = new string[1];
                            pool.demands[0] = demands;
                        }
                        else
                        {
                            ConversionUtility.WriteLine($"Manual deserialization with demands string swallowed an exception: " + ex.Message, _verbose);
                        }
                    }
                }
            }
            return(pool);
        }
        public AzurePipelines.Environment ProcessEnvironmentV2(string environmentYaml)
        {
            AzurePipelines.Environment environment = null;
            if (environmentYaml != null)
            {
                try
                {
                    environment = GenericObjectSerialization.DeserializeYaml <AzurePipelines.Environment>(environmentYaml);
                }
                catch (Exception ex1)
                {
                    ConversionUtility.WriteLine($"DeserializeYaml<AzurePipelines.Environment>(environmentYaml) swallowed an exception: " + ex1.Message, _verbose);

                    try
                    {
                        //when the environment is just a simple string, e.g.  //environment: environmentName.resourceName
                        string simpleEnvironment = GenericObjectSerialization.DeserializeYaml <string>(environmentYaml);
                        environment = new AzurePipelines.Environment
                        {
                            name = simpleEnvironment
                        };
                    }
                    catch (Exception ex2)
                    {
                        JObject json = JSONSerialization.DeserializeStringToObject(environmentYaml);
                        if (json["tags"].Type.ToString() == "String")
                        {
                            string name = null;
                            if (json["name"] != null)
                            {
                                name = json["name"].ToString();
                            }
                            string resourceName = null;
                            if (json["resourceName"] != null)
                            {
                                name = json["resourceName"].ToString();
                            }
                            string resourceId = null;
                            if (json["resourceId"] != null)
                            {
                                name = json["resourceId"].ToString();
                            }
                            string resourceType = null;
                            if (json["resourceType"] != null)
                            {
                                name = json["resourceType"].ToString();
                            }
                            environment = new AzurePipelines.Environment
                            {
                                name         = name,
                                resourceName = resourceName,
                                resourceId   = resourceId,
                                resourceType = resourceType
                            };
                            //Move the single string demands to an array
                            environment.tags    = new string[1];
                            environment.tags[0] = json["tags"].ToString();
                        }
                        else
                        {
                            ConversionUtility.WriteLine($"Manual deserialization with demands string swallowed an exception: " + ex2.Message, _verbose);
                        }
                    }
                }
            }

            return(environment);
        }
Пример #3
0
        /// <summary>
        /// V2 plan:
        /// 1. get the yaml
        /// 2. converting the yaml into a json document
        /// 3. parse the json document into azure pipelines sub-objects
        /// 4. put it together into one azure pipelines object
        /// 5. convert the azure pipelines object to github action
        /// </summary>
        /// <param name="yaml"></param>
        /// <returns></returns>

        private ConversionResponse ConvertAzurePipelineToGitHubActionV2(string yaml)
        {
            string        gitHubYaml   = "";
            List <string> variableList = new List <string>();
            List <string> stepComments = new List <string>();

            //convert the yaml into json, it's easier to parse
            JObject json = null;

            if (yaml != null)
            {
                //Clean up the YAML to remove conditional insert statements
                string processedYaml = ConversionUtility.CleanYamlBeforeDeserializationV2(yaml);
                json = JSONSerialization.DeserializeStringToObject(processedYaml);
            }

            //Build up the GitHub object piece by piece
            GitHubActionsRoot gitHubActions = new GitHubActionsRoot();
            GeneralProcessing gp            = new GeneralProcessing(_verbose);

            if (json != null)
            {
                //Name
                if (json["name"] != null)
                {
                    string nameYaml = json["name"].ToString();
                    gitHubActions.name = gp.ProcessNameV2(nameYaml);
                }

                //Trigger/PR/Schedules
                TriggerProcessing tp = new TriggerProcessing(_verbose);
                if (json["trigger"] != null)
                {
                    string triggerYaml = json["trigger"].ToString();
                    triggerYaml      = ConversionUtility.ProcessNoneJsonElement(triggerYaml);
                    gitHubActions.on = tp.ProcessTriggerV2(triggerYaml);
                }
                if (json["pr"] != null)
                {
                    string prYaml = json["pr"].ToString();
                    prYaml = ConversionUtility.ProcessNoneJsonElement(prYaml);
                    GitHubActions.Trigger prTrigger = tp.ProcessPullRequestV2(prYaml);
                    if (gitHubActions.on == null)
                    {
                        gitHubActions.on = prTrigger;
                    }
                    else
                    {
                        gitHubActions.on.pull_request = prTrigger.pull_request;
                    }
                }
                if (json["schedules"] != null)
                {
                    string schedulesYaml            = json["schedules"].ToString();
                    GitHubActions.Trigger schedules = tp.ProcessSchedulesV2(schedulesYaml);
                    if (gitHubActions.on == null)
                    {
                        gitHubActions.on = schedules;
                    }
                    else
                    {
                        gitHubActions.on.schedule = schedules.schedule;
                    }
                }

                //Parameters & Variables
                string parametersYaml  = json["parameters"]?.ToString();
                string variablesYaml   = json["variables"]?.ToString();
                VariablesProcessing vp = new VariablesProcessing(_verbose);
                gitHubActions.env = vp.ProcessParametersAndVariablesV2(parametersYaml, variablesYaml);

                //Resources
                string resourcesYaml = json["resources"]?.ToString();
                //Resource Pipelines
                if (resourcesYaml?.IndexOf("\"pipelines\"") >= 0)
                {
                    gitHubActions.messages.Add("TODO: Resource pipelines conversion not yet done: https://github.com/samsmithnz/AzurePipelinesToGitHubActionsConverter/issues/8");
                }
                //Resource Repositories
                if (resourcesYaml?.IndexOf("\"repositories\"") >= 0)
                {
                    gitHubActions.messages.Add("TODO: Resource repositories conversion not yet done: https://github.com/samsmithnz/AzurePipelinesToGitHubActionsConverter/issues/8");
                }
                //Resource Container
                if (resourcesYaml?.IndexOf("\"containers\"") >= 0)
                {
                    gitHubActions.messages.Add("TODO: Container conversion not yet done, we need help!: https://github.com/samsmithnz/AzurePipelinesToGitHubActionsConverter/issues/39");
                }
                //Strategy
                string strategyYaml = json["strategy"]?.ToString();


                //If we have stages, convert them into jobs first:
                if (json["stages"] != null)
                {
                    StagesProcessing sp = new StagesProcessing(_verbose);
                    gitHubActions.jobs = sp.ProcessStagesV2(json["stages"], strategyYaml);
                }
                //If we don't have stages, but have jobs:
                else if (json["stages"] == null && json["jobs"] != null)
                {
                    JobProcessing jp = new JobProcessing(_verbose);
                    gitHubActions.jobs  = jp.ProcessJobsV2(jp.ExtractAzurePipelinesJobsV2(json["jobs"], strategyYaml), gp.ExtractResourcesV2(resourcesYaml));
                    _matrixVariableName = jp.MatrixVariableName;
                }
                //Otherwise, if we don't have stages or jobs, we just have steps, and need to load them into a new job
                else if (json["stages"] == null && json["jobs"] == null)
                {
                    //Pool
                    string poolYaml = json["pool"]?.ToString();
                    //pool/demands
                    if (poolYaml?.IndexOf("\"demands\":") >= 0)
                    {
                        gitHubActions.messages.Add("Note: GitHub Actions does not have a 'demands' command on 'runs-on' yet");
                    }

                    //Steps
                    string               stepsYaml    = json["steps"]?.ToString();
                    JobProcessing        jp           = new JobProcessing(_verbose);
                    AzurePipelines.Job[] pipelineJobs = jp.ProcessJobFromPipelineRootV2(poolYaml, strategyYaml, stepsYaml);
                    Resources            resources    = gp.ExtractResourcesV2(resourcesYaml);
                    gitHubActions.jobs  = jp.ProcessJobsV2(pipelineJobs, resources);
                    _matrixVariableName = jp.MatrixVariableName;
                }

                if (gitHubActions.jobs != null && gitHubActions.jobs.Count == 0)
                {
                    gitHubActions.messages.Add("Note that although having no jobs is valid YAML, it is not a valid GitHub Action.");
                }

                //Load in all variables. Duplicates are ok, they are processed the same
                variableList.AddRange(vp.SearchForVariables(yaml));
                variableList.AddRange(vp.SearchForVariablesV2(gitHubActions));

                //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
                //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 = true
            });
        }