• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

samsmithnz / GitHubActionsDotNet / 7900757945

14 Feb 2024 11:53AM CUT coverage: 76.33%. Remained the same
7900757945

Pull #133

github

web-flow
Merge 652e32ffc into 5ca82b379
Pull Request #133: Bump the core group in /src/GitHubActionsDotNet with 1 update

144 of 222 branches covered (64.86%)

Branch coverage included in aggregate %.

559 of 699 relevant lines covered (79.97%)

13.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

46.67
/src/GitHubActionsDotNet/Serialization/GitHubActionsSerialization.cs
1
using GitHubActionsDotNet.Common;
2
using GitHubActionsDotNet.Models;
3
using System.Collections.Generic;
4
using System.IO;
5
using System.Text;
6
using Environment = System.Environment;
7

8
namespace GitHubActionsDotNet.Serialization
9
{
10
    public static class GitHubActionsSerialization
11
    {
12
        public static GitHubActionsRoot Deserialize(string yaml)
13
        {
14
            return DeserializeGitHubActionsYaml(yaml);
×
15
        }
16

17
        public static string Serialize(GitHubActionsRoot gitHubActions, List<string> variableList = null, string matrixVariableName = null)
18
        {
19
            string yaml = YamlSerialization.SerializeYaml<GitHubActionsRoot>(gitHubActions);
30✔
20

21
            yaml = ProcessGitHubActionYAML(yaml, variableList, matrixVariableName);
30✔
22

23
            return yaml;
30✔
24
        }
25

26
        public static string SerializeJob(Job gitHubActionJob, List<string> variableList = null)
27
        {
28
            string yaml = YamlSerialization.SerializeYaml<Job>(gitHubActionJob);
×
29

30
            yaml = ProcessGitHubActionYAML(yaml, variableList);
×
31
            yaml = StepsPostProcessing(yaml);
×
32

33
            return yaml;
×
34
        }
35

36
        public static string SerializeStep(Step gitHubActionStep, List<string> variableList = null)
37
        {
38
            string yaml = YamlSerialization.SerializeYaml<Step[]>(new Step[1] { gitHubActionStep });
10✔
39

40
            yaml = ProcessGitHubActionYAML(yaml, variableList);
10✔
41
            yaml = StepsPostProcessing(yaml);
10✔
42

43
            return yaml;
10✔
44
        }
45

46
        private static string ProcessGitHubActionYAML(string yaml, List<string> variableList = null, string matrixVariableName = null)
47
        {
48
            //Fix some variables for serialization, the '-' character is not valid in C# property names, and some of the YAML standard uses reserved words (e.g. if)
49
            yaml = PrepareYamlPropertiesForGitHubSerialization(yaml);
40✔
50

51
            //update variables from the $(variableName) format to ${{variableName}} format, by piping them into a list for replacement later.
52
            if (variableList != null)
40!
53
            {
54
                yaml = PrepareYamlVariablesForGitHubSerialization(yaml, variableList, matrixVariableName);
×
55
            }
56

57
            //If there is a cron in the conversion, we need to do a special processing to remove the quotes. 
58
            //This is hella custom and ugly, but otherwise the yaml comes out funky
59
            //Here we look at every line, removing the double quotes
60
            if (yaml.IndexOf("cron") >= 0)
40✔
61
            {
62
                StringBuilder processedYaml = new StringBuilder();
5✔
63
                using (StringReader reader = new StringReader(yaml))
5✔
64
                {
65
                    string line;
66
                    while ((line = reader.ReadLine()) != null)
24✔
67
                    {
68
                        if (line.IndexOf("cron") >= 0)
19✔
69
                        {
70
                            line = line.Replace(@"""", "");
6✔
71
                        }
72
                        processedYaml.AppendLine(line);
19✔
73
                    }
74
                }
5✔
75
                yaml = processedYaml.ToString();
5✔
76
            }
77
            //The serialization adds extra new line characters to Multi-line scripts
78
            yaml = yaml.Replace("\r\n\r\n", "\r\n");
40✔
79
            yaml = yaml.Replace("\n\n", "\n");
40✔
80

81
            //If we have a string with new lines and strings, it double encodes them, so we undo this
82
            yaml = yaml.Replace("\\r", "\r");
40✔
83
            yaml = yaml.Replace("\\n", "\n");
40✔
84

85
            //Trim off any leading of trailing new lines 
86
            yaml = yaml.TrimStart('\r', '\n');
40✔
87
            yaml = yaml.TrimEnd('\r', '\n');
40✔
88
            yaml = yaml.Trim();
40✔
89

90
            return yaml;
40✔
91
        }
92

93
        private static GitHubActionsRoot DeserializeGitHubActionsYaml(string yaml)
94
        {
95
            //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)
96
            yaml = yaml.Replace("runs-on", "runs_on");
×
97
            yaml = yaml.Replace("if", "_if");
×
98
            yaml = yaml.Replace("timeout-minutes", "timeout_minutes");
×
99
            yaml = yaml.Replace("pull-request", "pull_request");
×
100
            yaml = yaml.Replace("branches-ignore", "branches_ignore");
×
101
            yaml = yaml.Replace("paths-ignore", "paths_ignore");
×
102
            yaml = yaml.Replace("tags-ignore", "tags_ignore");
×
103
            yaml = yaml.Replace("max-parallel", "max_parallel");
×
104
            yaml = yaml.Replace("ref", "_ref");
×
105
            yaml = yaml.Replace("continue-on-error", "continue_on_error");
×
106
            yaml = yaml.Replace("timeout-minutes", "timeout_minutes");
×
107

108
            return YamlSerialization.DeserializeYaml<GitHubActionsRoot>(yaml);
×
109
        }
110

111
        private static string PrepareYamlPropertiesForGitHubSerialization(string yaml)
112
        {
113
            //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)
114
            yaml = yaml.Replace("runs_on", "runs-on");
40✔
115
            yaml = yaml.Replace("_if", "if");
40✔
116
            yaml = yaml.Replace("timeout_minutes", "timeout-minutes");
40✔
117
            //Commented out 20-Dec-2021, as it's affecting the pull_request workflow trigger
118
            //yaml = yaml.Replace("pull_request", "pull-request");
119
            yaml = yaml.Replace("branches_ignore", "branches-ignore");
40✔
120
            yaml = yaml.Replace("paths_ignore", "paths-ignore");
40✔
121
            yaml = yaml.Replace("tags_ignore", "tags-ignore");
40✔
122
            yaml = yaml.Replace("max_parallel", "max-parallel");
40✔
123
            yaml = yaml.Replace("_ref", "ref");
40✔
124
            yaml = yaml.Replace("continue_on_error", "continue-on-error");
40✔
125
            yaml = yaml.Replace("timeout_minutes", "timeout-minutes");
40✔
126
            yaml = yaml.Replace("step_message:", "#");
40✔
127
            yaml = yaml.Replace("job_message:", "#");
40✔
128
            yaml = yaml.Replace("step_message", "#");
40✔
129
            yaml = yaml.Replace("job_message", "#");
40✔
130

131
            //HACK: Sometimes when generating  yaml, a weird ">+" string appears, which we replace out. This is a known bug, but there is no known fix yet. https://github.com/aaubry/YamlDotNet/issues/449
132
            //This replaces a weird artifact in scripts when converting pipes, the order matters, and this is not a long term solution...
133
            yaml = yaml.Replace("run: >-", "run: |");
40✔
134
            yaml = yaml.Replace("run: >2-\r\n     |", "run: |");
40✔
135
            yaml = yaml.Replace("run: >2-\r\n         |", "run: |");
40✔
136
            yaml = yaml.Replace("run: 2-\r\n         |", "run: |");
40✔
137
            yaml = yaml.Replace("run: 2-\r\n         |", "run: |");
40✔
138
            yaml = yaml.Replace("run: >\r\n", "run: |\r\n");
40✔
139
            yaml = yaml.Replace("run: >+", "run: ");
40✔
140
            yaml = yaml.Replace("run: >", "run: |");
40✔
141
            yaml = yaml.Replace(": >+\r\n      ", ": ");
40✔
142
            yaml = yaml.Replace(": >", ": ");
40✔
143
            yaml = yaml.Replace("#: \n      ", ": ");
40✔
144

145
            //Fix the workflow dispatch empty string to be [nothing]
146
            yaml = yaml.Replace("workflow_dispatch: ''", "workflow_dispatch:");
40✔
147

148
            return yaml;
40✔
149
        }
150

151
        private static string PrepareYamlVariablesForGitHubSerialization(string yaml, List<string> variableList, string matrixVariableName = null)
152
        {
153
            if (matrixVariableName != null)
×
154
            {
155
                variableList.Add(matrixVariableName);
×
156
            }
157

158
            foreach (string item in variableList)
×
159
            {
160
                if (item == matrixVariableName)
×
161
                {
162
                    yaml = yaml.Replace("$(" + item + ")", "${{ matrix." + item + " }}");
×
163
                    yaml = yaml.Replace("$( " + item + " )", "${{ matrix." + item + " }}");
×
164
                }
165
                else
166
                {
167
                    //Replace variables with the format "$(MyVar)" with the format "$MyVar"
168
                    yaml = yaml.Replace("$(" + item + ")", "${{ env." + item + " }}");
×
169
                    yaml = yaml.Replace("$( " + item + " )", "${{ env." + item + " }}");
×
170
                    yaml = yaml.Replace("$(" + item + " )", "${{ env." + item + " }}");
×
171
                    yaml = yaml.Replace("$( " + item + ")", "${{ env." + item + " }}");
×
172
                    yaml = yaml.Replace("$" + item + "", "${{ env." + item + " }}");
×
173
                    yaml = yaml.Replace("${{" + item + "}}", "${{ env." + item + " }}");
×
174
                    yaml = yaml.Replace("${{ " + item + " }}", "${{ env." + item + " }}");
×
175
                    yaml = yaml.Replace("${{" + item + " }}", "${{ env." + item + " }}");
×
176
                    yaml = yaml.Replace("${{ " + item + "}}", "${{ env." + item + " }}");
×
177
                    yaml = yaml.Replace("env.parameters.", "env.");
×
178
                    yaml = yaml.Replace("${{ env.rev:r }}", "${GITHUB_RUN_NUMBER}"); //Replace the unique version number in Azure DevOps with a unique system variable in GitHub Actions
×
179
                }
180
            }
181

182
            return yaml;
×
183
        }
184

185
        //Strip the steps off to focus on just the individual step
186
        private static string StepsPostProcessing(string input)
187
        {
188
            if (input.Trim().StartsWith("steps:"))
10!
189
            {
190
                //we need to remove steps, before we do, we need to see if the task needs to remove indent
191
                string[] stepLines = input.Split(Environment.NewLine);
×
192
                if (stepLines.Length > 0)
×
193
                {
194
                    int i = 0;
×
195
                    //Search for the first non empty line
196
                    while (string.IsNullOrEmpty(stepLines[i].Trim()) || stepLines[i].Trim().StartsWith("steps:"))
×
197
                    {
198
                        i++;
×
199
                    }
200
                    if (stepLines[i].StartsWith("-"))
×
201
                    {
202
                        int indentLevel = stepLines[i].IndexOf("-");
×
203
                        string buffer = ConversionUtility.GenerateSpaces(indentLevel);
×
204
                        StringBuilder newInput = new StringBuilder();
×
205
                        foreach (string line in stepLines)
×
206
                        {
207
                            if (!line.Trim().StartsWith("steps:"))
×
208
                            {
209
                                newInput.Append(buffer);
×
210
                                newInput.Append(line);
×
211
                                newInput.Append(Environment.NewLine);
×
212
                            }
213
                        }
214
                        input = newInput.ToString();
×
215
                    }
216
                }
217
                input = input.TrimEnd('\r', '\n');
×
218
            }
219

220
            return input;
10✔
221
        }
222

223
    }
224
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc