Skip to content

Commit bdeee48

Browse files
committed
(GH-17) Add support for loading generic reporter dynamically
1 parent c2d76ea commit bdeee48

File tree

6 files changed

+151
-71
lines changed

6 files changed

+151
-71
lines changed

Cake.Issues.Recipe/Content/addins.cake

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
#addin nuget:?package=Cake.Issues.InspectCode&version=0.8.0
99
#addin nuget:?package=Cake.Issues.Markdownlint&version=0.8.2
1010
#addin nuget:?package=Cake.Issues.Reporting&version=0.8.0
11-
#addin nuget:?package=Cake.Issues.Reporting.Generic&version=0.8.2
1211
#addin nuget:?package=Cake.Issues.PullRequests&version=0.8.1
1312
#addin nuget:?package=Cake.Issues.PullRequests.AppVeyor&version=0.8.0
1413
#addin nuget:?package=Cake.Issues.PullRequests.AzureDevOps&version=0.8.0
15-
#addin nuget:?package=Cake.AzureDevOps&version=0.4.4
14+
#addin nuget:?package=Cake.AzureDevOps&version=0.4.4
15+
16+
public const string CakeIssuesReportingGenericVersion = "0.8.2";

Cake.Issues.Recipe/Content/build.cake

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
#load IssuesBuildTasksDefinitions.cake
33
#load version.cake
44
#load data/data.cake
5+
#load loader/loader.cake
56
#load parameters/parameters.cake
7+
#load reporters/reporters.cake
68

79
///////////////////////////////////////////////////////////////////////////////
810
// GLOBAL VARIABLES
@@ -113,16 +115,23 @@ IssuesBuildTasks.CreateFullIssuesReportTask = Task("Create-FullIssuesReport")
113115
IssuesParameters.OutputDirectory.CombineWithFilePath(reportFileName);
114116
EnsureDirectoryExists(IssuesParameters.OutputDirectory);
115117

116-
// Create HTML report using DevExpress template.
117-
var settings =
118-
GenericIssueReportFormatSettings
119-
.FromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDxDataGrid)
120-
.WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueLight);
121-
CreateIssueReport(
122-
data.Issues,
123-
GenericIssueReportFormat(settings),
124-
data.RepositoryRootDirectory,
125-
data.FullIssuesReport);
118+
var issueFormats = new List<IIssueReportFormat>();
119+
120+
if (!Context.Environment.Runtime.IsCoreClr)
121+
{
122+
Information("Creating report format using Generic Reporter");
123+
issueFormats.Add(GenericReporterData.CreateIssueFormatFromEmbeddedTemplate(Context, IssuesParameters.Reporting));
124+
}
125+
126+
foreach (var issueFormat in issueFormats)
127+
{
128+
CreateIssueReport(
129+
data.Issues,
130+
issueFormat,
131+
data.RepositoryRootDirectory,
132+
data.FullIssuesReport
133+
);
134+
}
126135
});
127136

128137
IssuesBuildTasks.PublishIssuesArtifactsTask = Task("Publish-IssuesArtifacts")

Cake.Issues.Recipe/Content/loader/AddinData.cake

Lines changed: 75 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,7 @@ public class AddinData
3737
foreach (var ctx in constructors)
3838
{
3939
var ctxParams = ctx.GetParameters();
40-
bool useCtx = true;
41-
for (int i = 0; i < ctxParams.Length && useCtx; i++)
42-
{
43-
useCtx = ctxParams[i].ParameterType == parameters[i].GetType();
44-
}
40+
bool useCtx = ParametersMatch(ctxParams, parameters);
4541

4642
if (useCtx)
4743
{
@@ -60,76 +56,104 @@ public class AddinData
6056

6157
public object CallStaticMethod(string methodName, params object[] parameters)
6258
{
63-
parameters = parameters ?? new object[0];
59+
parameters = TransformParameters(parameters);
6460

65-
for (int i = 0; i < parameters.Length; i++)
61+
var methods = this._definedMethods.Where(m => m.IsPublic && m.IsStatic && string.Compare(m.Name, methodName, StringComparison.OrdinalIgnoreCase) == 0);
62+
MethodInfo method = null;
63+
64+
foreach (var m in methods.Where(m => m.GetParameters().Length == parameters.Length))
6665
{
67-
var parameterType = parameters[i].GetType();
68-
int index = parameterType == typeof(string) ? parameters[i].ToString().IndexOf('.') : -1;
69-
if (index >= 0)
66+
var methodParams = m.GetParameters();
67+
bool useMethod = ParametersMatch(methodParams, parameters);
68+
69+
if (useMethod)
7070
{
71-
var enumOrClass = parameters[i].ToString().Substring(0, index);
72-
var enumType = _declaredEnums.FirstOrDefault(e => string.Compare(e.Name, enumOrClass, StringComparison.OrdinalIgnoreCase) == 0);
73-
if (enumType is object)
74-
{
75-
var value = parameters[i].ToString().Substring(index+1);
76-
parameters[i] = Enum.Parse(enumType, value);
77-
}
71+
method = m;
72+
break;
7873
}
7974
}
8075

81-
var methods = this._definedMethods.Where(m => m.IsPublic && m.IsStatic && string.Compare(m.Name, methodName, StringComparison.OrdinalIgnoreCase) == 0);
82-
MethodInfo method = null;
76+
if (method is null)
77+
{
78+
throw new NullReferenceException($"No method with the name '{methodName}' was found!");
79+
}
8380

84-
foreach (var m in methods.Where(m => m.GetParameters().Length == parameters.Length))
81+
return method.Invoke(null, parameters);
82+
}
83+
84+
public object[] TransformParameters(params object[] parameters)
85+
{
86+
var newParameters = new List<object>();
87+
if (parameters is null)
8588
{
86-
var methodParams = m.GetParameters();
87-
bool useMethod = true;
89+
return newParameters.ToArray();
90+
}
8891

89-
for (int i = 0; i < methodParams.Length && useMethod; i++)
92+
foreach (var parameter in parameters)
93+
{
94+
object value = parameter;
95+
if (parameter is string sParam)
9096
{
91-
var methodParamType = methodParams[i].ParameterType;
92-
var optionParamType = parameters[i].GetType();
93-
if (methodParamType.IsEnum && optionParamType == typeof(string))
97+
int index = sParam.IndexOf('.');
98+
if (index >= 0)
9499
{
95-
try
100+
var enumOrClass = sParam.Substring(0, index);
101+
var subValue = sParam.Substring(index+1);
102+
var enumType = _declaredEnums.FirstOrDefault(e => string.Compare(e.Name, enumOrClass, StringComparison.OrdinalIgnoreCase) == 0);
103+
var classType = _definedClasses.FirstOrDefault(c => string.Compare(c.Name, enumOrClass, StringComparison.OrdinalIgnoreCase) == 0);
104+
if (enumType is object)
96105
{
97-
var parsedValue = Enum.Parse(methodParamType, parameters[i].ToString());
98-
if (parsedValue is object)
99-
{
100-
parameters[i] = parsedValue;
101-
}
102-
else
103-
useMethod = false;
106+
value = Enum.Parse(enumType, subValue);
104107
}
105-
catch
108+
else if (classType is object)
106109
{
107-
useMethod = false;
110+
var property = classType.GetProperty(subValue, BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static);
111+
value = property.GetValue(null);
108112
}
109113
}
110-
else if (methodParamType == typeof(Enum) && optionParamType.IsEnum)
114+
}
115+
116+
newParameters.Add(value);
117+
}
118+
119+
return newParameters.ToArray();
120+
}
121+
122+
public static bool ParametersMatch(ParameterInfo[] methodParameters, object[] parameters)
123+
{
124+
bool useMethod = true;
125+
for (int i = 0; i < methodParameters.Length && useMethod; i++)
126+
{
127+
var methodParamType = methodParameters[i].ParameterType;
128+
var optionParamType = parameters[i].GetType();
129+
if (methodParamType.IsEnum && optionParamType == typeof(string))
130+
{
131+
try
111132
{
112-
useMethod = true;
113-
}
114-
else
133+
var parsedValue = Enum.Parse(methodParamType, parameters[i].ToString());
134+
if (parsedValue is object)
135+
{
136+
parameters[i] = parsedValue;
137+
}
138+
else
139+
useMethod = false;
140+
}
141+
catch
115142
{
116-
useMethod = methodParamType == optionParamType || methodParamType.IsAssignableFrom(optionParamType);
143+
useMethod = false;
117144
}
118145
}
119-
120-
if (useMethod)
146+
else if (methodParamType == typeof(Enum) && optionParamType.IsEnum)
121147
{
122-
method = m;
123-
break;
148+
useMethod = true;
149+
}
150+
else
151+
{
152+
useMethod = methodParamType == optionParamType || methodParamType.IsAssignableFrom(optionParamType);
124153
}
125154
}
126155

127-
if (method is null)
128-
{
129-
throw new NullReferenceException("No method with the specified name was found!");
130-
}
131-
132-
return method.Invoke(null, parameters);
156+
return useMethod;
133157
}
134158

135159
protected void Initialize(ICakeContext context, string packageName, string packageVersion, string assemblyName = null)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
public class GenericReporterData : AddinData
2+
{
3+
private static GenericReporterData _reporter = null;
4+
5+
private GenericReporterData(ICakeContext context)
6+
: base(context, "Cake.Issues.Reporting.Generic", CakeIssuesReportingGenericVersion)
7+
{
8+
_reporter = this;
9+
}
10+
11+
public static GenericReporterData GetReporter(ICakeContext context)
12+
{
13+
return _reporter ?? new GenericReporterData(context);
14+
}
15+
16+
public static IIssueReportFormat CreateIssueFormatFromEmbeddedTemplate(ICakeContext context, IssuesParametersReporting parameters)
17+
{
18+
var reporter = GetReporter(context);
19+
20+
var settings = reporter.CallStaticMethod("FromEmbeddedTemplate", "HtmlDxDataGrid");
21+
22+
var theme = "DevExtremeTheme.MaterialBlueLight"; // Should be changed to be set on IssuesParametersReporting settings class.
23+
reporter.CallStaticMethod("WithOption", settings, "HtmlDxDataGridOption.Theme", theme);
24+
25+
var issueFormat = (IIssueReportFormat)reporter.CallStaticMethod("GenericIssueReportFormat", context, settings);
26+
27+
return issueFormat;
28+
}
29+
30+
public static IIssueReportFormat CreateIssueFormatFromFilePath(ICakeContext context, IssuesParametersReporting parameters, FilePath reportPath)
31+
{
32+
var reporter = GetReporter(context);
33+
34+
var issueFormat = (IIssueReportFormat)reporter.CallStaticMethod("GenericIssueReportFormatFromFilePath", context, reportPath);
35+
36+
return issueFormat;
37+
}
38+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#load ./GenericReporterData.cake

Cake.Issues.Recipe/Content/tasks/buildservers/AzureDevOpsBuildServer.cake

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,22 @@ public class AzureDevOpsBuildServer : BaseBuildServer
9797
summaryFileName += ".md";
9898
var summaryFilePath = IssuesParameters.OutputDirectory.CombineWithFilePath(summaryFileName);
9999

100-
// Create summary for Azure Pipelines using custom template.
101-
context.CreateIssueReport(
102-
data.Issues,
103-
context.GenericIssueReportFormatFromFilePath(
104-
new FilePath(sourceFilePath).GetDirectory().Combine("tasks").Combine("buildservers").CombineWithFilePath("AzurePipelineSummary.cshtml")),
105-
data.RepositoryRootDirectory,
106-
summaryFilePath);
100+
var issueFormats = new List<IIssueReportFormat>();
101+
if (!context.Environment.Runtime.IsCoreClr)
102+
{
103+
var reportPath = new FilePath(sourceFilePath).GetDirectory().Combine("tasks").Combine("buildservers").CombineWithFilePath("AzurePipelineSummary.cshtml");
104+
issueFormats.Add(GenericReporterData.CreateIssueFormatFromFilePath(context, IssuesParameters.Reporting, reportPath));
105+
}
107106

108-
context.TFBuild().Commands.UploadTaskSummary(summaryFilePath);
107+
foreach (var issueFormat in issueFormats)
108+
{
109+
context.CreateIssueReport(
110+
data.Issues,
111+
issueFormat,
112+
data.RepositoryRootDirectory,
113+
summaryFilePath
114+
);
115+
}
109116
}
110117

111118
/// <inheritdoc />

0 commit comments

Comments
 (0)