Skip to content

Commit 57ec8d3

Browse files
daveMuellerMarcoRossignoli
authored andcommitted
Fix cobertura Jenkins reporter + source link support (#614)
Fix cobertura Jenkins reporter + source link support
1 parent ca10ca9 commit 57ec8d3

File tree

4 files changed

+127
-6
lines changed

4 files changed

+127
-6
lines changed

src/coverlet.core/Coverage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ public CoverageResult GetCoverageResult()
276276
}
277277
}
278278

279-
var coverageResult = new CoverageResult { Identifier = _identifier, Modules = modules, InstrumentedResults = _results };
279+
var coverageResult = new CoverageResult { Identifier = _identifier, Modules = modules, InstrumentedResults = _results, UseSourceLink = _useSourceLink };
280280

281281
if (!string.IsNullOrEmpty(_mergeWith) && !string.IsNullOrWhiteSpace(_mergeWith) && _fileSystem.Exists(_mergeWith))
282282
{

src/coverlet.core/CoverageResult.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ internal class CoverageResult
4141
{
4242
public string Identifier;
4343
public Modules Modules;
44+
public bool UseSourceLink;
4445
internal List<InstrumenterResult> InstrumentedResults;
4546

4647
internal CoverageResult() { }

src/coverlet.core/Reporters/CoberturaReporter.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
24
using System.Globalization;
35
using System.IO;
46
using System.Linq;
@@ -30,7 +32,8 @@ public string Report(CoverageResult result)
3032
coverage.Add(new XAttribute("timestamp", (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds));
3133

3234
XElement sources = new XElement("sources");
33-
sources.Add(new XElement("source", string.Empty));
35+
var rootDirs = GetRootDirs(result.Modules, result.UseSourceLink).ToList();
36+
rootDirs.ForEach(x => sources.Add(new XElement("source", x)));
3437

3538
XElement packages = new XElement("packages");
3639
foreach (var module in result.Modules)
@@ -48,7 +51,7 @@ public string Report(CoverageResult result)
4851
{
4952
XElement @class = new XElement("class");
5053
@class.Add(new XAttribute("name", cls.Key));
51-
@class.Add(new XAttribute("filename", document.Key));
54+
@class.Add(new XAttribute("filename", GetRelativePathFromBase(rootDirs, document.Key, result.UseSourceLink)));
5255
@class.Add(new XAttribute("line-rate", (summary.CalculateLineCoverage(cls.Value).Percent / 100).ToString(CultureInfo.InvariantCulture)));
5356
@class.Add(new XAttribute("branch-rate", (summary.CalculateBranchCoverage(cls.Value).Percent / 100).ToString(CultureInfo.InvariantCulture)));
5457
@class.Add(new XAttribute("complexity", summary.CalculateCyclomaticComplexity(cls.Value)));
@@ -129,5 +132,35 @@ public string Report(CoverageResult result)
129132

130133
return Encoding.UTF8.GetString(stream.ToArray());
131134
}
135+
136+
private static IEnumerable<string> GetRootDirs(Modules modules, bool useSourceLink)
137+
{
138+
if (useSourceLink)
139+
{
140+
return new[] { string.Empty };
141+
}
142+
143+
return modules.Values.SelectMany(k => k.Keys).Select(Directory.GetDirectoryRoot).Distinct();
144+
}
145+
146+
private static string GetRelativePathFromBase(IEnumerable<string> rootPaths, string path, bool useSourceLink)
147+
{
148+
if (useSourceLink)
149+
{
150+
return path;
151+
}
152+
153+
foreach (var root in rootPaths)
154+
{
155+
if (path.StartsWith(root))
156+
{
157+
return path.Substring(root.Length);
158+
}
159+
}
160+
161+
Debug.Assert(false, "Unexpected, we should find at least one path starts with one pre-build roots list");
162+
163+
return path;
164+
}
132165
}
133166
}

test/coverlet.core.tests/Reporters/CoberturaReporterTests.cs

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
using System.Globalization;
44
using System.IO;
55
using System.Linq;
6+
using System.Runtime.InteropServices;
67
using System.Text;
78
using System.Threading;
8-
using System.Xml;
99
using System.Xml.Linq;
1010
using Xunit;
1111

@@ -37,7 +37,15 @@ public void TestReport()
3737
classes.Add("Coverlet.Core.Reporters.Tests.CoberturaReporterTests", methods);
3838

3939
Documents documents = new Documents();
40-
documents.Add("doc.cs", classes);
40+
41+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
42+
{
43+
documents.Add(@"C:\doc.cs", classes);
44+
}
45+
else
46+
{
47+
documents.Add(@"/doc.cs", classes);
48+
}
4149

4250
result.Modules = new Modules();
4351
result.Modules.Add("module", documents);
@@ -102,7 +110,14 @@ public void TestEnsureParseMethodStringCorrectly(
102110
classes.Add("Google.Protobuf.Reflection.MessageDescriptor", methods);
103111

104112
Documents documents = new Documents();
105-
documents.Add("doc.cs", classes);
113+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
114+
{
115+
documents.Add(@"C:\doc.cs", classes);
116+
}
117+
else
118+
{
119+
documents.Add(@"/doc.cs", classes);
120+
}
106121

107122
result.Modules = new Modules();
108123
result.Modules.Add("module", documents);
@@ -120,5 +135,77 @@ public void TestEnsureParseMethodStringCorrectly(
120135
Assert.Equal(expectedMethodName, methodAttrs["name"]);
121136
Assert.Equal(expectedSignature, methodAttrs["signature"]);
122137
}
138+
139+
[Fact]
140+
public void TestReportWithTwoDifferentDirectories()
141+
{
142+
CoverageResult result = new CoverageResult();
143+
result.Identifier = Guid.NewGuid().ToString();
144+
145+
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
146+
147+
string absolutePath1;
148+
string absolutePath2;
149+
150+
if (isWindows)
151+
{
152+
absolutePath1 = @"C:\projA\file.cs";
153+
absolutePath2 = @"E:\projB\file.cs";
154+
}
155+
else
156+
{
157+
absolutePath1 = @"/projA/file.cs";
158+
absolutePath2 = @"/projB/file.cs";
159+
}
160+
161+
var classes = new Classes {{"Class", new Methods()}};
162+
var documents = new Documents {{absolutePath1, classes}, {absolutePath2, classes}};
163+
164+
result.Modules = new Modules {{"Module", documents}};
165+
166+
CoberturaReporter reporter = new CoberturaReporter();
167+
string report = reporter.Report(result);
168+
169+
var doc = XDocument.Load(new MemoryStream(Encoding.UTF8.GetBytes(report)));
170+
171+
List<string> rootPaths = doc.Element("coverage").Element("sources").Elements().Select(e => e.Value).ToList();
172+
List<string> relativePaths = doc.Element("coverage").Element("packages").Element("package")
173+
.Element("classes").Elements().Select(e => e.Attribute("filename").Value).ToList();
174+
175+
List<string> possiblePaths = new List<string>();
176+
foreach (string root in rootPaths)
177+
{
178+
foreach (string relativePath in relativePaths)
179+
{
180+
possiblePaths.Add(Path.Combine(root, relativePath));
181+
}
182+
}
183+
184+
Assert.Contains(absolutePath1, possiblePaths);
185+
Assert.Contains(absolutePath2, possiblePaths);
186+
}
187+
188+
[Fact]
189+
public void TestReportWithSourcelinkPaths()
190+
{
191+
CoverageResult result = new CoverageResult {UseSourceLink = true, Identifier = Guid.NewGuid().ToString()};
192+
193+
var absolutePath =
194+
@"https://raw.githubusercontent.com/johndoe/Coverlet/02c09baa8bfdee3b6cdf4be89bd98c8157b0bc08/Demo.cs";
195+
196+
var classes = new Classes {{"Class", new Methods()}};
197+
var documents = new Documents {{absolutePath, classes}};
198+
199+
result.Modules = new Modules {{"Module", documents}};
200+
201+
CoberturaReporter reporter = new CoberturaReporter();
202+
string report = reporter.Report(result);
203+
204+
var doc = XDocument.Load(new MemoryStream(Encoding.UTF8.GetBytes(report)));
205+
var fileName = doc.Element("coverage").Element("packages").Element("package").Element("classes").Elements()
206+
.Select(e => e.Attribute("filename").Value).Single();
207+
208+
Assert.Equal(absolutePath, fileName);
209+
}
123210
}
124211
}

0 commit comments

Comments
 (0)