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

loresoft / DotNet.Property / 6719270641

01 Nov 2023 11:49AM UTC coverage: 55.357%. Remained the same
6719270641

Pull #93

github

web-flow
Merge 57dc32590 into b83870101
Pull Request #93: Bump xunit from 2.5.0 to 2.6.0

28 of 50 branches covered (0.0%)

Branch coverage included in aggregate %.

65 of 118 relevant lines covered (55.08%)

3.69 hits per line

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

62.31
/src/DotNet.Property/ProjectUpdater.cs
1
using System;
2
using System.Collections.Generic;
3
using System.IO;
4
using System.Linq;
5
using System.Xml;
6
using System.Xml.Linq;
7
using Microsoft.Extensions.FileSystemGlobbing;
8
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
9

10
namespace DotNet.Property
11
{
12
    /// <summary>
13
    /// Update .net core project properties
14
    /// </summary>
15
    public class ProjectUpdater
16
    {
17

18
        /// <summary>
19
        /// Gets or sets the log writer delegate.
20
        /// </summary>
21
        /// <value>
22
        /// The log writer delegate.
23
        /// </value>
24
        public Action<string> Logger { get; set; } = Console.WriteLine;
5✔
25

26
        /// <summary>
27
        /// Gets or sets the properties to update.
28
        /// </summary>
29
        /// <value>
30
        /// The properties to update.
31
        /// </value>
32
        public Dictionary<string, string> Properties { get; set; } = new Dictionary<string, string>();
33

34
        /// <summary>
35
        /// Gets or sets the projects to update as a file glob expression.
36
        /// </summary>
37
        /// <value>
38
        /// The projects to update as a file glob expression.
39
        /// </value>
40
        public string Projects { get; set; } = "**/*.props";
41

42

43
        /// <summary>
44
        /// Updates .net core projects using the specified command line arguments. The first argument is the project list glob expression.
45
        /// </summary>
46
        /// <param name="args">The arguments used to update project with.</param>
47
        /// <param name="rootDirectory">The root directory to search for projects.</param>
48
        public void Update(string[] args, string rootDirectory = null)
49
        {
50
            Projects = args[0];
×
51
            Properties = ParseArguments(args, 1);
×
52

53
            WriteLog($"Matching projects: {Projects}");
×
54
            var matcher = new Matcher(StringComparison.OrdinalIgnoreCase);
×
55
            matcher.AddInclude(Projects);
×
56

57
            if (string.IsNullOrEmpty(rootDirectory))
×
58
                rootDirectory = Environment.CurrentDirectory;
×
59

60
            var currentDirectory = new DirectoryInfo(rootDirectory);
×
61
            var startingDirectory = new DirectoryInfoWrapper(currentDirectory);
×
62
            var matchingResult = matcher.Execute(startingDirectory);
×
63

64
            if (!matchingResult.HasMatches)
×
65
            {
66
                WriteLog($"Error: No Projects found: {Projects}");
×
67
                return;
×
68
            }
69

70
            foreach (var fileMatch in matchingResult.Files)
×
71
            {
72
                var filePath = Path.GetFullPath(fileMatch.Path);
×
73
                try
74
                {
75
                    UpdateProject(filePath);
×
76
                }
×
77
                catch (Exception ex)
×
78
                {
79
                    Console.Error.WriteLine($"Error occured processing {filePath} : {ex.Message}");
×
80
                }
×
81
            }
82
        }
×
83

84

85
        /// <summary>
86
        /// Updates the project at the specified <paramref name="filePath"/>.
87
        /// </summary>
88
        /// <param name="filePath">The file path of the project to update.</param>
89
        /// <exception cref="ArgumentNullException"><paramref name="filePath"/> is <see langword="null"/></exception>
90
        /// <exception cref="ArgumentException"><paramref name="filePath"/> is not found.</exception>
91
        public void UpdateProject(string filePath)
92
        {
93
            if (filePath == null)
2!
94
                throw new ArgumentNullException(nameof(filePath));
×
95

96
            if (!File.Exists(filePath))
2!
97
                throw new ArgumentException($"File not found: {filePath}", nameof(filePath));
×
98

99
            WriteLog($"Updating Project: {filePath}");
2✔
100

101
            XDocument document;
102
            using (var readStream = File.OpenRead(filePath))
2✔
103
            {
104
                document = XDocument.Load(readStream);
2✔
105
            }
2✔
106

107
            UpdateProject(document);
2✔
108

109
            // save document
110
            var settings = new XmlWriterSettings
2✔
111
            {
2✔
112
                OmitXmlDeclaration = true,
2✔
113
                Indent = true
2✔
114
            };
2✔
115

116
            using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
2✔
117
            using (var writer = XmlWriter.Create(stream, settings))
2✔
118
            {
119
                document.Save(writer);
2✔
120
            }
2✔
121
        }
2✔
122

123
        /// <summary>
124
        /// Updates the project as an <see cref="XDocument"/>.
125
        /// </summary>
126
        /// <param name="document">The project document.</param>
127
        /// <exception cref="ArgumentNullException"><paramref name="document"/> is <see langword="null"/></exception>
128
        /// <exception cref="InvalidOperationException">Missing root Project node.</exception>
129
        public void UpdateProject(XDocument document)
130
        {
131
            if (document == null)
5!
132
                throw new ArgumentNullException(nameof(document));
×
133

134
            if (Properties == null || Properties.Count == 0)
5!
135
                return;
×
136

137
            var projectElement = document.Element("Project");
5✔
138
            if (projectElement == null)
5!
139
                throw new InvalidOperationException("Could not find root Project node. Make sure file has a root Project node without a namespace.");
×
140

141
            foreach (var p in Properties)
30✔
142
            {
143
                WriteLog($"  Set Property '{p.Key}':'{p.Value}'");
10✔
144

145
                // find last group with element and no condition
146
                var projectGroup = projectElement
10✔
147
                    .Elements("PropertyGroup")
10✔
148
                    .LastOrDefault(e =>
10✔
149
                        e.Elements(p.Key).Any() &&
10✔
150
                        (e.HasAttributes == false || e.Attributes().All(a => a.Name != "Condition"))
10✔
151
                    );
10✔
152

153
                // use last group without condition
154
                if (projectGroup == null)
10✔
155
                    projectGroup = projectElement
7✔
156
                        .Elements("PropertyGroup")
7✔
157
                        .LastOrDefault(e => e.HasAttributes == false || e.Attributes().All(a => a.Name != "Condition"));
7✔
158

159
                // create new if not found
160
                if (projectGroup == null)
10✔
161
                    projectGroup = projectElement
1✔
162
                        .GetOrCreateElement("PropertyGroup");
1✔
163

164
                projectGroup
10✔
165
                    .GetOrCreateElement(p.Key)
10✔
166
                    .SetValue(p.Value);
10✔
167
            }
168
        }
5✔
169

170

171
        /// <summary>
172
        /// Parses the arguments into a dictionary.
173
        /// </summary>
174
        /// <param name="args">The arguments.</param>
175
        /// <param name="startIndex">The start index.</param>
176
        /// <returns></returns>
177
        /// <exception cref="ArgumentNullException"><paramref name="args"/> is <see langword="null"/></exception>
178
        public static Dictionary<string, string> ParseArguments(string[] args, int startIndex = 0)
179
        {
180
            if (args == null)
3!
181
                throw new ArgumentNullException(nameof(args));
×
182

183
            var arguments = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
3✔
184

185
            // skip first
186
            for (int i = startIndex; i < args.Length; i++)
20✔
187
            {
188
                int keyStartIndex = 0;
7✔
189

190
                if (args[i].StartsWith("--"))
7!
191
                {
192
                    keyStartIndex = 2;
×
193
                }
194
                else if (args[i].StartsWith("-"))
7!
195
                {
196
                    keyStartIndex = 1;
×
197
                }
198
                else if (args[i].StartsWith("/"))
7!
199
                {
200
                    keyStartIndex = 1;
×
201
                }
202

203
                int separator = args[i].IndexOfAny(new char[] { ':', '=' });
7✔
204

205
                if (separator < 0)
7✔
206
                {
207
                    continue; // an invalid format
208

209
                }
210

211
                var key = args[i].Substring(keyStartIndex, separator - keyStartIndex);
7✔
212
                var value = args[i].Substring(separator + 1);
7✔
213

214
                arguments[key] = value;
7✔
215
            }
216

217
            return arguments;
3✔
218
        }
219

220

221
        private void WriteLog(string s)
222
        {
223
            if (Logger == null || string.IsNullOrEmpty(s))
12!
224
                return;
×
225

226
            Logger.Invoke(s);
12✔
227
        }
12✔
228
    }
229
}
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