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

samsmithnz / GitHubActionsDotNet / 21306684855

24 Jan 2026 01:22AM UTC coverage: 91.215% (-0.07%) from 91.281%
21306684855

Pull #226

github

web-flow
Merge 96d07c109 into 993167f4a
Pull Request #226: Add exclude support to Strategy matrix configuration

190 of 222 branches covered (85.59%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

9 existing lines in 1 file now uncovered.

651 of 700 relevant lines covered (93.0%)

15.67 hits per line

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

78.52
/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);
1✔
15
        }
16

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

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

23
            return yaml;
36✔
24
        }
25

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

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

33
            return yaml;
2✔
34
        }
35

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

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

43
            return yaml;
12✔
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);
50✔
50

51
            //update variables from the $(variableName) format to ${{variableName}} format, by piping them into a list for replacement later.
52
            if (variableList != null)
50✔
53
            {
54
                yaml = PrepareYamlVariablesForGitHubSerialization(yaml, variableList, matrixVariableName);
3✔
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)
50✔
61
            {
62
                StringBuilder processedYaml = new StringBuilder();
6✔
63
                using (StringReader reader = new StringReader(yaml))
6✔
64
                {
65
                    string line;
66
                    while ((line = reader.ReadLine()) != null)
32✔
67
                    {
68
                        if (line.IndexOf("cron") >= 0)
26✔
69
                        {
70
                            line = line.Replace(@"""", "");
7✔
71
                        }
72
                        processedYaml.AppendLine(line);
26✔
73
                    }
74
                }
6✔
75
                yaml = processedYaml.ToString();
6✔
76
            }
77
            //The serialization adds extra new line characters to Multi-line scripts
78
            yaml = yaml.Replace("\r\n\r\n", "\r\n");
50✔
79
            yaml = yaml.Replace("\n\n", "\n");
50✔
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");
50✔
83
            yaml = yaml.Replace("\\n", "\n");
50✔
84

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

90
            return yaml;
50✔
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");
1✔
97
            yaml = yaml.Replace("if", "_if");
1✔
98
            yaml = yaml.Replace("timeout-minutes", "timeout_minutes");
1✔
99
            yaml = yaml.Replace("pull-request", "pull_request");
1✔
100
            yaml = yaml.Replace("branches-ignore", "branches_ignore");
1✔
101
            yaml = yaml.Replace("paths-ignore", "paths_ignore");
1✔
102
            yaml = yaml.Replace("tags-ignore", "tags_ignore");
1✔
103
            yaml = yaml.Replace("max-parallel", "max_parallel");
1✔
104
            yaml = yaml.Replace("ref", "_ref");
1✔
105
            yaml = yaml.Replace("continue-on-error", "continue_on_error");
1✔
106
            yaml = yaml.Replace("timeout-minutes", "timeout_minutes");
1✔
107

108
            return YamlSerialization.DeserializeYaml<GitHubActionsRoot>(yaml);
1✔
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");
50✔
115
            yaml = yaml.Replace("_if", "if");
50✔
116
            yaml = yaml.Replace("timeout_minutes", "timeout-minutes");
50✔
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");
50✔
120
            yaml = yaml.Replace("paths_ignore", "paths-ignore");
50✔
121
            yaml = yaml.Replace("tags_ignore", "tags-ignore");
50✔
122
            yaml = yaml.Replace("max_parallel", "max-parallel");
50✔
123
            yaml = yaml.Replace("_ref", "ref");
50✔
124
            yaml = yaml.Replace("continue_on_error", "continue-on-error");
50✔
125
            yaml = yaml.Replace("timeout_minutes", "timeout-minutes");
50✔
126
            yaml = yaml.Replace("step_message:", "#");
50✔
127
            yaml = yaml.Replace("job_message:", "#");
50✔
128
            yaml = yaml.Replace("step_message", "#");
50✔
129
            yaml = yaml.Replace("job_message", "#");
50✔
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: |");
50✔
134
            yaml = yaml.Replace("run: >2-\r\n     |", "run: |");
50✔
135
            yaml = yaml.Replace("run: >2-\r\n         |", "run: |");
50✔
136
            yaml = yaml.Replace("run: 2-\r\n         |", "run: |");
50✔
137
            yaml = yaml.Replace("run: 2-\r\n         |", "run: |");
50✔
138
            yaml = yaml.Replace("run: >\r\n", "run: |\r\n");
50✔
139
            yaml = yaml.Replace("run: >+", "run: ");
50✔
140
            yaml = yaml.Replace("run: >", "run: |");
50✔
141
            yaml = yaml.Replace(": >+\r\n      ", ": ");
50✔
142
            yaml = yaml.Replace(": >", ": ");
50✔
143
            yaml = yaml.Replace("#: \n      ", ": ");
50✔
144

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

148
            return yaml;
50✔
149
        }
150

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

158
            foreach (string item in variableList)
14✔
159
            {
160
                if (item == matrixVariableName)
4✔
161
                {
162
                    yaml = yaml.Replace("$(" + item + ")", "${{ matrix." + item + " }}");
2✔
163
                    yaml = yaml.Replace("$( " + item + " )", "${{ matrix." + item + " }}");
2✔
164
                }
165
                else
166
                {
167
                    //Replace variables with the format "$(MyVar)" with the format "$MyVar"
168
                    yaml = yaml.Replace("$(" + item + ")", "${{ env." + item + " }}");
2✔
169
                    yaml = yaml.Replace("$( " + item + " )", "${{ env." + item + " }}");
2✔
170
                    yaml = yaml.Replace("$(" + item + " )", "${{ env." + item + " }}");
2✔
171
                    yaml = yaml.Replace("$( " + item + ")", "${{ env." + item + " }}");
2✔
172
                    yaml = yaml.Replace("$" + item + "", "${{ env." + item + " }}");
2✔
173
                    yaml = yaml.Replace("${{" + item + "}}", "${{ env." + item + " }}");
2✔
174
                    yaml = yaml.Replace("${{ " + item + " }}", "${{ env." + item + " }}");
2✔
175
                    yaml = yaml.Replace("${{" + item + " }}", "${{ env." + item + " }}");
2✔
176
                    yaml = yaml.Replace("${{ " + item + "}}", "${{ env." + item + " }}");
2✔
177
                    yaml = yaml.Replace("env.parameters.", "env.");
2✔
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
2✔
179
                }
180
            }
181

182
            return yaml;
3✔
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:"))
14!
189
            {
190
                //we need to remove steps, before we do, we need to see if the task needs to remove indent
UNCOV
191
                string[] stepLines = input.Split(Environment.NewLine);
×
UNCOV
192
                if (stepLines.Length > 0)
×
193
                {
194
                    int i = 0;
×
195
                    //Search for the first non empty line
UNCOV
196
                    while (string.IsNullOrEmpty(stepLines[i].Trim()) || stepLines[i].Trim().StartsWith("steps:"))
×
197
                    {
UNCOV
198
                        i++;
×
199
                    }
UNCOV
200
                    if (stepLines[i].StartsWith("-"))
×
201
                    {
UNCOV
202
                        int indentLevel = stepLines[i].IndexOf("-");
×
203
                        string buffer = ConversionUtility.GenerateSpaces(indentLevel);
×
UNCOV
204
                        StringBuilder newInput = new StringBuilder();
×
205
                        foreach (string line in stepLines)
×
206
                        {
207
                            if (!line.Trim().StartsWith("steps:"))
×
208
                            {
UNCOV
209
                                newInput.Append(buffer);
×
210
                                newInput.Append(line);
×
UNCOV
211
                                newInput.Append(Environment.NewLine);
×
212
                            }
213
                        }
214
                        input = newInput.ToString();
×
215
                    }
216
                }
217
                input = input.TrimEnd('\r', '\n');
×
218
            }
219

220
            return input;
14✔
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

© 2026 Coveralls, Inc