Esempio n. 1
0
        /// <summary>
        /// Deserialize an Azure DevOps Pipeline with a complex trigger and complex variable list
        /// </summary>
        /// <param name="yaml">yaml to convert</param>
        /// <returns>Azure DevOps Pipeline with complex trigger and complex variables</returns>
        public static AzurePipelinesRoot <AzurePipelines.Trigger, AzurePipelines.Variable[]> DeserializeComplexTriggerAndComplexVariables(string yaml)
        {
            yaml = CleanYamlBeforeDeserialization(yaml);
            AzurePipelinesRoot <AzurePipelines.Trigger, AzurePipelines.Variable[]> azurePipeline = GenericObjectSerialization.DeserializeYaml <AzurePipelinesRoot <AzurePipelines.Trigger, AzurePipelines.Variable[]> >(yaml);

            return(azurePipeline);
        }
Esempio n. 2
0
        /// <summary>
        /// Deserialize an Azure DevOps Pipeline with a simple trigger/ string[] and simple variable list/ Dictionary<string, string>
        /// </summary>
        /// <param name="yaml">yaml to convert</param>
        /// <returns>Azure DevOps Pipeline with simple trigger and simple variables</returns>
        public static AzurePipelinesRoot <string[], Dictionary <string, string> > DeserializeSimpleTriggerAndSimpleVariables(string yaml)
        {
            yaml = CleanYamlBeforeDeserialization(yaml);
            AzurePipelinesRoot <string[], Dictionary <string, string> > azurePipeline = GenericObjectSerialization.DeserializeYaml <AzurePipelinesRoot <string[], Dictionary <string, string> > >(yaml);

            return(azurePipeline);
        }
Esempio n. 3
0
        /// <summary>
        /// Deserialize an Azure DevOps Pipeline with a simple trigger/ string[] and simple variable list/ Dictionary<string, string>
        /// </summary>
        /// <param name="yaml">yaml to convert</param>
        /// <returns>Azure DevOps Pipeline with simple trigger and complex variables</returns>
        public static AzurePipelinesRoot <string[], AzurePipelines.Variable[]> DeserializeSimpleTriggerAndComplexVariables(string yaml)
        {
            AzurePipelinesRoot <string[], AzurePipelines.Variable[]> azurePipeline = null;

            try
            {
                yaml          = CleanYamlBeforeDeserialization(yaml);
                azurePipeline = GenericObjectSerialization.DeserializeYaml <AzurePipelinesRoot <string[], AzurePipelines.Variable[]> >(yaml);
            }
            catch (Exception)
            {
                Debug.WriteLine($"{nameof(DeserializeSimpleTriggerAndComplexVariables)} swallowed an exception, to be reviewed...");
                //Do nothing
            }
            return(azurePipeline);
        }
Esempio n. 4
0
        /// <summary>
        /// Deserialize an Azure DevOps Pipeline with a simple trigger/ string[] and simple variable list/ Dictionary<string, string>
        /// </summary>
        /// <param name="yaml">yaml to convert</param>
        /// <returns>Azure DevOps Pipeline with simple trigger and complex variables</returns>
        public static AzurePipelinesRoot <string[], AzurePipelines.Variable[]> DeserializeSimpleTriggerAndComplexVariables(string yaml)
        {
            AzurePipelinesRoot <string[], AzurePipelines.Variable[]> azurePipeline = null;

            try
            {
                yaml          = CleanYamlBeforeDeserialization(yaml);
                azurePipeline = GenericObjectSerialization.DeserializeYaml <AzurePipelinesRoot <string[], AzurePipelines.Variable[]> >(yaml);
            }
            catch (Exception ex)
            {
                ConversionUtility.WriteLine($"{nameof(DeserializeSimpleTriggerAndComplexVariables)} swallowed an exception: " + ex.Message, true);
                //Do nothing
            }
            return(azurePipeline);
        }
Esempio n. 5
0
        /// <summary>
        /// Deserialize an Azure DevOps Pipeline with a complex trigger and complex variable list
        /// </summary>
        /// <param name="yaml">yaml to convert</param>
        /// <returns>Azure DevOps Pipeline with complex trigger and complex variables</returns>
        public static AzurePipelinesRoot <AzurePipelines.Trigger, AzurePipelines.Variable[]> DeserializeComplexTriggerAndComplexVariables(string yaml)
        {
            //DANGER WILL ROBINSON - DANGER
            //Unlike the other deserializers, we need to leave this last error handler off - so that errors can be returned to the client, where as the others can fail so that they can try the next deserializer method.
            AzurePipelinesRoot <AzurePipelines.Trigger, AzurePipelines.Variable[]> azurePipeline = null;

            //try
            //{
            yaml          = CleanYamlBeforeDeserialization(yaml);
            azurePipeline = GenericObjectSerialization.DeserializeYaml <AzurePipelinesRoot <AzurePipelines.Trigger, AzurePipelines.Variable[]> >(yaml);
            //}
            //catch (Exception)
            //{
            //    //Do nothing
            //}
            return(azurePipeline);
        }
        /// <summary>
        /// Process an Azure DevOps Pipeline, converting it to a GitHub Action
        /// </summary>
        /// <param name="azurePipeline">Azure DevOps Pipeline object</param>
        /// <param name="simpleTrigger">When the YAML has a simple trigger, (String[]). Can be null</param>
        /// <param name="complexTrigger">When the YAML has a complex trigger. Can be null</param>
        /// <returns>GitHub Actions object</returns>
        public GitHubActionsRoot ProcessPipeline(AzurePipelinesRoot <TTriggers, TVariables> azurePipeline,
                                                 string[] simpleTrigger, AzurePipelines.Trigger complexTrigger,
                                                 Dictionary <string, string> simpleVariables, AzurePipelines.Variable[] complexVariables)
        {
            VariableList = new List <string>();
            GeneralProcessing generalProcessing = new GeneralProcessing(_verbose);
            GitHubActionsRoot gitHubActions     = new GitHubActionsRoot();

            //Name
            if (azurePipeline.name != null)
            {
                gitHubActions.name = azurePipeline.name;
            }

            //Container
            if (azurePipeline.container != null)
            {
                gitHubActions.messages.Add("TODO: Container conversion not yet done, we need help!: https://github.com/samsmithnz/AzurePipelinesToGitHubActionsConverter/issues/39");
            }

            //Triggers for pushs
            TriggerProcessing tp = new TriggerProcessing(_verbose);

            if (azurePipeline.trigger != null)
            {
                if (complexTrigger != null)
                {
                    gitHubActions.on = tp.ProcessComplexTrigger(complexTrigger);
                }
                else if (simpleTrigger != null)
                {
                    gitHubActions.on = tp.ProcessSimpleTrigger(simpleTrigger);
                }
            }

            //Triggers for pull requests
            if (azurePipeline.pr != null)
            {
                GitHubActions.Trigger pr = tp.ProcessPullRequest(azurePipeline.pr);
                if (gitHubActions.on == null)
                {
                    gitHubActions.on = pr;
                }
                else
                {
                    gitHubActions.on.pull_request = pr.pull_request;
                }
            }

            //pool/demands
            if (azurePipeline.pool != null && azurePipeline.pool.demands != null)
            {
                gitHubActions.messages.Add("Note: GitHub Actions does not have a 'demands' command on 'runs-on' yet");
            }

            //schedules
            if (azurePipeline.schedules != null)
            {
                string[] schedules = tp.ProcessSchedules(azurePipeline.schedules);
                if (gitHubActions.on == null)
                {
                    gitHubActions.on = new GitHubActions.Trigger();
                }
                gitHubActions.on.schedule = schedules;
            }

            //Resources
            if (azurePipeline.resources != null)
            {
                //Note: Containers is in the jobs - this note should be removed once pipeliens and repositories is moved too

                //TODO: There is currently no conversion path for pipelines
                if (azurePipeline.resources.pipelines != null)
                {
                    gitHubActions.messages.Add("TODO: Resource pipelines conversion not yet done: https://github.com/samsmithnz/AzurePipelinesToGitHubActionsConverter/issues/8");
                    if (azurePipeline.resources.pipelines.Length > 0)
                    {
                        if (azurePipeline.resources.pipelines[0].pipeline != null)
                        {
                            ConversionUtility.WriteLine("pipeline: " + azurePipeline.resources.pipelines[0].pipeline, _verbose);
                        }
                        if (azurePipeline.resources.pipelines[0].project != null)
                        {
                            ConversionUtility.WriteLine("project: " + azurePipeline.resources.pipelines[0].project, _verbose);
                        }
                        if (azurePipeline.resources.pipelines[0].source != null)
                        {
                            ConversionUtility.WriteLine("source: " + azurePipeline.resources.pipelines[0].source, _verbose);
                        }
                        if (azurePipeline.resources.pipelines[0].branch != null)
                        {
                            ConversionUtility.WriteLine("branch: " + azurePipeline.resources.pipelines[0].branch, _verbose);
                        }
                        if (azurePipeline.resources.pipelines[0].version != null)
                        {
                            ConversionUtility.WriteLine("version: " + azurePipeline.resources.pipelines[0].version, _verbose);
                        }
                        if (azurePipeline.resources.pipelines[0].trigger != null)
                        {
                            if (azurePipeline.resources.pipelines[0].trigger.autoCancel)
                            {
                                ConversionUtility.WriteLine("autoCancel: " + azurePipeline.resources.pipelines[0].trigger.autoCancel, _verbose);
                            }
                            if (azurePipeline.resources.pipelines[0].trigger.batch)
                            {
                                ConversionUtility.WriteLine("batch: " + azurePipeline.resources.pipelines[0].trigger.batch, _verbose);
                            }
                        }
                    }
                }

                //TODO: There is currently no conversion path for repositories
                if (azurePipeline.resources.repositories != null)
                {
                    gitHubActions.messages.Add("TODO: Resource repositories conversion not yet done: https://github.com/samsmithnz/AzurePipelinesToGitHubActionsConverter/issues/8");

                    if (azurePipeline.resources.repositories.Length > 0)
                    {
                        if (azurePipeline.resources.repositories[0].repository != null)
                        {
                            ConversionUtility.WriteLine("repository: " + azurePipeline.resources.repositories[0].repository, _verbose);
                        }
                        if (azurePipeline.resources.repositories[0].type != null)
                        {
                            ConversionUtility.WriteLine("type: " + azurePipeline.resources.repositories[0].type, _verbose);
                        }
                        if (azurePipeline.resources.repositories[0].name != null)
                        {
                            ConversionUtility.WriteLine("name: " + azurePipeline.resources.repositories[0].name, _verbose);
                        }
                        if (azurePipeline.resources.repositories[0]._ref != null)
                        {
                            ConversionUtility.WriteLine("ref: " + azurePipeline.resources.repositories[0]._ref, _verbose);
                        }
                        if (azurePipeline.resources.repositories[0].endpoint != null)
                        {
                            ConversionUtility.WriteLine("endpoint: " + azurePipeline.resources.repositories[0].endpoint, _verbose);
                        }
                        if (azurePipeline.resources.repositories[0].connection != null)
                        {
                            ConversionUtility.WriteLine("connection: " + azurePipeline.resources.repositories[0].connection, _verbose);
                        }
                        if (azurePipeline.resources.repositories[0].source != null)
                        {
                            ConversionUtility.WriteLine("source: " + azurePipeline.resources.repositories[0].source, _verbose);
                        }
                    }
                }
            }

            //Stages (Note: stages are not yet present in actions, we are merging them into one giant list of jobs, appending the stage name to jobs to keep names unique)
            if (azurePipeline.stages != null)
            {
                //Count the number of jobs and initialize the jobs array with that number
                int jobCounter = 0;
                foreach (Stage stage in azurePipeline.stages)
                {
                    if (stage.jobs != null)
                    {
                        jobCounter += stage.jobs.Length;
                    }
                }
                azurePipeline.jobs = new AzurePipelines.Job[jobCounter];
                //We are going to take each stage and assign it a set of jobs
                int currentIndex = 0;
                foreach (Stage stage in azurePipeline.stages)
                {
                    if (stage.jobs != null)
                    {
                        int j = 0;
                        for (int i = 0; i < stage.jobs.Length; i++)
                        {
                            //Get the job name
                            string jobName = ConversionUtility.GenerateJobName(stage.jobs[i], currentIndex);
                            //Rename the job, using the stage name as prefix, so that we keep the job names unique
                            stage.jobs[j].job = stage.stage + "_Stage_" + jobName;
                            ConversionUtility.WriteLine("This variable is not needed in actions: " + stage.displayName, _verbose);
                            azurePipeline.jobs[currentIndex]           = stage.jobs[j];
                            azurePipeline.jobs[currentIndex].condition = stage.condition;
                            //Move over the variables, the stage variables will need to be applied to each job
                            if (stage.variables != null && stage.variables.Count > 0)
                            {
                                azurePipeline.jobs[currentIndex].variables = new Dictionary <string, string>();
                                foreach (KeyValuePair <string, string> stageVariable in stage.variables)
                                {
                                    azurePipeline.jobs[currentIndex].variables.Add(stageVariable.Key, stageVariable.Value);
                                }
                            }
                            j++;
                            currentIndex++;
                        }
                    }
                }
            }

            //Jobs (when no stages are defined)
            if (azurePipeline.jobs != null)
            {
                //If there is a parent strategy, and no child strategy, load in the parent
                //This is not perfect...
                if (azurePipeline.strategy != null)
                {
                    foreach (AzurePipelines.Job item in azurePipeline.jobs)
                    {
                        if (item.strategy == null)
                        {
                            item.strategy = azurePipeline.strategy;
                        }
                    }
                }
                gitHubActions.jobs = ProcessJobs(azurePipeline.jobs, azurePipeline.resources);

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

            //Pool + Steps (When there are no jobs defined)
            if ((azurePipeline.pool != null && azurePipeline.jobs == null) || (azurePipeline.steps != null && azurePipeline.steps.Length > 0))
            {
                //Steps only have one job, so we just create it here
                StepsProcessing sp = new StepsProcessing();
                gitHubActions.jobs = new Dictionary <string, GitHubActions.Job>
                {
                    {
                        "build",
                        new GitHubActions.Job
                        {
                            runs_on   = generalProcessing.ProcessPool(azurePipeline.pool),
                            strategy  = generalProcessing.ProcessStrategy(azurePipeline.strategy),
                            container = generalProcessing.ProcessContainer(azurePipeline.resources),
                            //resources = ProcessResources(azurePipeline.resources),
                            steps = sp.AddSupportingSteps(azurePipeline.steps)
                        }
                    }
                };
                MatrixVariableName = generalProcessing.MatrixVariableName;
            }

            //Variables
            VariablesProcessing vp = new VariablesProcessing(_verbose);

            if (azurePipeline.variables != null)
            {
                if (complexVariables != null)
                {
                    gitHubActions.env = vp.ProcessComplexVariables(complexVariables);
                    VariableList.AddRange(vp.VariableList);
                }
                else if (simpleVariables != null)
                {
                    gitHubActions.env = vp.ProcessSimpleVariables(simpleVariables);
                    VariableList.AddRange(vp.VariableList);
                }
            }
            else if (azurePipeline.parameters != null)
            {
                //For now, convert the parameters to variables
                gitHubActions.env = vp.ProcessSimpleVariables(azurePipeline.parameters);
            }

            return(gitHubActions);
        }
Esempio n. 7
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. 8
0
        /// <summary>
        /// Process an Azure DevOps Pipeline, converting it to a GitHub Action
        /// </summary>
        /// <param name="azurePipeline">Azure DevOps Pipeline object</param>
        /// <param name="simpleTrigger">When the YAML has a simple trigger, (String[]). Can be null</param>
        /// <param name="complexTrigger">When the YAML has a complex trigger. Can be null</param>
        /// <returns>GitHub Actions object</returns>
        public GitHubActionsRoot ProcessPipeline(AzurePipelinesRoot <T, T2> azurePipeline, string[] simpleTrigger, AzurePipelines.Trigger complexTrigger, Dictionary <string, string> simpleVariables, AzurePipelines.Variable[] complexVariables)
        {
            VariableList = new List <string>();
            GitHubActionsRoot gitHubActions = new GitHubActionsRoot();

            //Name
            if (azurePipeline.name != null)
            {
                gitHubActions.name = azurePipeline.name;
            }

            //Container
            if (azurePipeline.container != null)
            {
                gitHubActions.messages.Add("TODO: Container conversion not yet done: https://github.com/samsmithnz/AzurePipelinesToGitHubActionsConverter/issues/39");
            }

            //Triggers for pushs
            if (azurePipeline.trigger != null)
            {
                if (complexTrigger != null)
                {
                    gitHubActions.on = ProcessComplexTrigger(complexTrigger);
                }
                else if (simpleTrigger != null)
                {
                    gitHubActions.on = ProcessSimpleTrigger(simpleTrigger);
                }
            }

            //Triggers for pull requests
            if (azurePipeline.pr != null)
            {
                GitHubActions.Trigger pr = ProcessPullRequest(azurePipeline.pr);
                if (gitHubActions.on == null)
                {
                    gitHubActions.on = pr;
                }
                else
                {
                    gitHubActions.on.pull_request = pr.pull_request;
                }
            }

            //Container
            if (azurePipeline.pool != null && azurePipeline.pool.demands != null)
            {
                gitHubActions.messages.Add("Note: GitHub Actions does not have a 'demands' command on 'runs-on' yet");
            }

            //schedules
            if (azurePipeline.schedules != null)
            {
                string[] schedules = ProcessSchedules(azurePipeline.schedules);
                if (gitHubActions.on == null)
                {
                    gitHubActions.on = new GitHubActions.Trigger();
                }
                gitHubActions.on.schedule = schedules;
            }

            //Resources
            if (azurePipeline.resources != null)
            {
                //Note: Containers is in the jobs - this note should be removed once pipeliens and repositories is moved too

                //TODO: Add code for pipelines
                if (azurePipeline.resources.pipelines != null)
                {
                    gitHubActions.messages.Add("TODO: Resource pipelines conversion not yet done: https://github.com/samsmithnz/AzurePipelinesToGitHubActionsConverter/issues/8");
                    if (azurePipeline.resources.pipelines.Length > 0)
                    {
                        if (azurePipeline.resources.pipelines[0].pipeline != null)
                        {
                            Console.WriteLine("pipeline: " + azurePipeline.resources.pipelines[0].pipeline);
                        }
                        if (azurePipeline.resources.pipelines[0].project != null)
                        {
                            Console.WriteLine("project: " + azurePipeline.resources.pipelines[0].project);
                        }
                        if (azurePipeline.resources.pipelines[0].source != null)
                        {
                            Console.WriteLine("source: " + azurePipeline.resources.pipelines[0].source);
                        }
                        if (azurePipeline.resources.pipelines[0].branch != null)
                        {
                            Console.WriteLine("branch: " + azurePipeline.resources.pipelines[0].branch);
                        }
                        if (azurePipeline.resources.pipelines[0].version != null)
                        {
                            Console.WriteLine("version: " + azurePipeline.resources.pipelines[0].version);
                        }
                        if (azurePipeline.resources.pipelines[0].trigger != null)
                        {
                            if (azurePipeline.resources.pipelines[0].trigger.autoCancel)
                            {
                                Console.WriteLine("autoCancel: " + azurePipeline.resources.pipelines[0].trigger.autoCancel);
                            }
                            if (azurePipeline.resources.pipelines[0].trigger.batch)
                            {
                                Console.WriteLine("batch: " + azurePipeline.resources.pipelines[0].trigger.batch);
                            }
                        }
                    }
                }

                //TODO: Add code for repositories
                if (azurePipeline.resources.repositories != null)
                {
                    gitHubActions.messages.Add("TODO: Resource repositories conversion not yet done: https://github.com/samsmithnz/AzurePipelinesToGitHubActionsConverter/issues/8");

                    if (azurePipeline.resources.repositories.Length > 0)
                    {
                        if (azurePipeline.resources.repositories[0].repository != null)
                        {
                            Console.WriteLine("repository: " + azurePipeline.resources.repositories[0].repository);
                        }
                        if (azurePipeline.resources.repositories[0].type != null)
                        {
                            Console.WriteLine("type: " + azurePipeline.resources.repositories[0].type);
                        }
                        if (azurePipeline.resources.repositories[0].name != null)
                        {
                            Console.WriteLine("name: " + azurePipeline.resources.repositories[0].name);
                        }
                        if (azurePipeline.resources.repositories[0]._ref != null)
                        {
                            Console.WriteLine("ref: " + azurePipeline.resources.repositories[0]._ref);
                        }
                        if (azurePipeline.resources.repositories[0].endpoint != null)
                        {
                            Console.WriteLine("endpoint: " + azurePipeline.resources.repositories[0].endpoint);
                        }
                        if (azurePipeline.resources.repositories[0].connection != null)
                        {
                            Console.WriteLine("connection: " + azurePipeline.resources.repositories[0].connection);
                        }
                        if (azurePipeline.resources.repositories[0].source != null)
                        {
                            Console.WriteLine("source: " + azurePipeline.resources.repositories[0].source);
                        }
                    }
                }
            }

            //Stages (Note: stages are not yet present in actions, we are merging them into one giant list of jobs, appending the stage name to jobs to keep names unique)
            if (azurePipeline.stages != null)
            {
                //Count the number of jobs and initialize the jobs array with that number
                int jobCounter = 0;
                foreach (Stage stage in azurePipeline.stages)
                {
                    jobCounter += stage.jobs.Length;
                }
                azurePipeline.jobs = new AzurePipelines.Job[jobCounter];

                //We are going to take each stage and assign it a set of jobs
                int currentIndex = 0;
                foreach (Stage stage in azurePipeline.stages)
                {
                    int j = 0;
                    for (int i = currentIndex; i < currentIndex + stage.jobs.Length; i++)
                    {
                        //Get the job name
                        string jobName = stage.jobs[j].job;
                        if (jobName == null && stage.jobs[j].template != null)
                        {
                            jobName = "Template";
                        }
                        //Rename the job, using the stage name as prefix, so that we keep the job names unique
                        stage.jobs[j].job = stage.stage + "_Stage_" + jobName;
                        Console.WriteLine("This variable is not needed in actions: " + stage.displayName);
                        azurePipeline.jobs[i]           = stage.jobs[j];
                        azurePipeline.jobs[i].condition = stage.condition;
                        j++;
                    }
                    currentIndex += stage.jobs.Length;
                }
            }

            //Jobs (when no stages are defined)
            if (azurePipeline.jobs != null)
            {
                //If there is a parent strategy, and no child strategy, load in the parent
                //This is not perfect...
                if (azurePipeline.strategy != null)
                {
                    foreach (AzurePipelines.Job item in azurePipeline.jobs)
                    {
                        if (item.strategy == null)
                        {
                            item.strategy = azurePipeline.strategy;
                        }
                    }
                }
                gitHubActions.jobs = ProcessJobs(azurePipeline.jobs, azurePipeline.resources);
            }

            //Pool + Steps (When there are no jobs defined)
            if (azurePipeline.pool != null || (azurePipeline.steps != null && azurePipeline.steps.Length > 0))
            {
                //Steps only have one job, so we just create it here
                gitHubActions.jobs = new Dictionary <string, GitHubActions.Job>
                {
                    {
                        "build",
                        new GitHubActions.Job
                        {
                            runs_on   = ProcessPool(azurePipeline.pool),
                            strategy  = ProcessStrategy(azurePipeline.strategy),
                            container = ProcessContainer(azurePipeline.resources),
                            //resources = ProcessResources(azurePipeline.resources),
                            steps = ProcessSteps(azurePipeline.steps)
                        }
                    }
                };
            }

            //Variables
            if (azurePipeline.variables != null)
            {
                if (complexVariables != null)
                {
                    gitHubActions.env = ProcessComplexVariables(complexVariables);
                }
                else if (simpleVariables != null)
                {
                    gitHubActions.env = ProcessSimpleVariables(simpleVariables);
                }
            }
            else if (azurePipeline.parameters != null)
            {
                //For now, convert the parameters to variables
                gitHubActions.env = ProcessSimpleVariables(azurePipeline.parameters);
            }

            return(gitHubActions);
        }