Skip to content

Commit

Permalink
(GH-17) Add support for loading generic reporter dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
AdmiringWorm committed Jul 21, 2020
1 parent c2d76ea commit bdeee48
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 71 deletions.
5 changes: 3 additions & 2 deletions Cake.Issues.Recipe/Content/addins.cake
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
#addin nuget:?package=Cake.Issues.InspectCode&version=0.8.0
#addin nuget:?package=Cake.Issues.Markdownlint&version=0.8.2
#addin nuget:?package=Cake.Issues.Reporting&version=0.8.0
#addin nuget:?package=Cake.Issues.Reporting.Generic&version=0.8.2
#addin nuget:?package=Cake.Issues.PullRequests&version=0.8.1
#addin nuget:?package=Cake.Issues.PullRequests.AppVeyor&version=0.8.0
#addin nuget:?package=Cake.Issues.PullRequests.AzureDevOps&version=0.8.0
#addin nuget:?package=Cake.AzureDevOps&version=0.4.4
#addin nuget:?package=Cake.AzureDevOps&version=0.4.4

public const string CakeIssuesReportingGenericVersion = "0.8.2";
29 changes: 19 additions & 10 deletions Cake.Issues.Recipe/Content/build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
#load IssuesBuildTasksDefinitions.cake
#load version.cake
#load data/data.cake
#load loader/loader.cake
#load parameters/parameters.cake
#load reporters/reporters.cake

///////////////////////////////////////////////////////////////////////////////
// GLOBAL VARIABLES
Expand Down Expand Up @@ -113,16 +115,23 @@ IssuesBuildTasks.CreateFullIssuesReportTask = Task("Create-FullIssuesReport")
IssuesParameters.OutputDirectory.CombineWithFilePath(reportFileName);
EnsureDirectoryExists(IssuesParameters.OutputDirectory);
// Create HTML report using DevExpress template.
var settings =
GenericIssueReportFormatSettings
.FromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDxDataGrid)
.WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueLight);
CreateIssueReport(
data.Issues,
GenericIssueReportFormat(settings),
data.RepositoryRootDirectory,
data.FullIssuesReport);
var issueFormats = new List<IIssueReportFormat>();
if (!Context.Environment.Runtime.IsCoreClr)
{
Information("Creating report format using Generic Reporter");
issueFormats.Add(GenericReporterData.CreateIssueFormatFromEmbeddedTemplate(Context, IssuesParameters.Reporting));
}
foreach (var issueFormat in issueFormats)
{
CreateIssueReport(
data.Issues,
issueFormat,
data.RepositoryRootDirectory,
data.FullIssuesReport
);
}
});

IssuesBuildTasks.PublishIssuesArtifactsTask = Task("Publish-IssuesArtifacts")
Expand Down
126 changes: 75 additions & 51 deletions Cake.Issues.Recipe/Content/loader/AddinData.cake
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@ public class AddinData
foreach (var ctx in constructors)
{
var ctxParams = ctx.GetParameters();
bool useCtx = true;
for (int i = 0; i < ctxParams.Length && useCtx; i++)
{
useCtx = ctxParams[i].ParameterType == parameters[i].GetType();
}
bool useCtx = ParametersMatch(ctxParams, parameters);

if (useCtx)
{
Expand All @@ -60,76 +56,104 @@ public class AddinData

public object CallStaticMethod(string methodName, params object[] parameters)
{
parameters = parameters ?? new object[0];
parameters = TransformParameters(parameters);

for (int i = 0; i < parameters.Length; i++)
var methods = this._definedMethods.Where(m => m.IsPublic && m.IsStatic && string.Compare(m.Name, methodName, StringComparison.OrdinalIgnoreCase) == 0);
MethodInfo method = null;

foreach (var m in methods.Where(m => m.GetParameters().Length == parameters.Length))
{
var parameterType = parameters[i].GetType();
int index = parameterType == typeof(string) ? parameters[i].ToString().IndexOf('.') : -1;
if (index >= 0)
var methodParams = m.GetParameters();
bool useMethod = ParametersMatch(methodParams, parameters);

if (useMethod)
{
var enumOrClass = parameters[i].ToString().Substring(0, index);
var enumType = _declaredEnums.FirstOrDefault(e => string.Compare(e.Name, enumOrClass, StringComparison.OrdinalIgnoreCase) == 0);
if (enumType is object)
{
var value = parameters[i].ToString().Substring(index+1);
parameters[i] = Enum.Parse(enumType, value);
}
method = m;
break;
}
}

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

foreach (var m in methods.Where(m => m.GetParameters().Length == parameters.Length))
return method.Invoke(null, parameters);
}

public object[] TransformParameters(params object[] parameters)
{
var newParameters = new List<object>();
if (parameters is null)
{
var methodParams = m.GetParameters();
bool useMethod = true;
return newParameters.ToArray();
}

for (int i = 0; i < methodParams.Length && useMethod; i++)
foreach (var parameter in parameters)
{
object value = parameter;
if (parameter is string sParam)
{
var methodParamType = methodParams[i].ParameterType;
var optionParamType = parameters[i].GetType();
if (methodParamType.IsEnum && optionParamType == typeof(string))
int index = sParam.IndexOf('.');
if (index >= 0)
{
try
var enumOrClass = sParam.Substring(0, index);
var subValue = sParam.Substring(index+1);
var enumType = _declaredEnums.FirstOrDefault(e => string.Compare(e.Name, enumOrClass, StringComparison.OrdinalIgnoreCase) == 0);
var classType = _definedClasses.FirstOrDefault(c => string.Compare(c.Name, enumOrClass, StringComparison.OrdinalIgnoreCase) == 0);
if (enumType is object)
{
var parsedValue = Enum.Parse(methodParamType, parameters[i].ToString());
if (parsedValue is object)
{
parameters[i] = parsedValue;
}
else
useMethod = false;
value = Enum.Parse(enumType, subValue);
}
catch
else if (classType is object)
{
useMethod = false;
var property = classType.GetProperty(subValue, BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static);
value = property.GetValue(null);
}
}
else if (methodParamType == typeof(Enum) && optionParamType.IsEnum)
}

newParameters.Add(value);
}

return newParameters.ToArray();
}

public static bool ParametersMatch(ParameterInfo[] methodParameters, object[] parameters)
{
bool useMethod = true;
for (int i = 0; i < methodParameters.Length && useMethod; i++)
{
var methodParamType = methodParameters[i].ParameterType;
var optionParamType = parameters[i].GetType();
if (methodParamType.IsEnum && optionParamType == typeof(string))
{
try
{
useMethod = true;
}
else
var parsedValue = Enum.Parse(methodParamType, parameters[i].ToString());
if (parsedValue is object)
{
parameters[i] = parsedValue;
}
else
useMethod = false;
}
catch
{
useMethod = methodParamType == optionParamType || methodParamType.IsAssignableFrom(optionParamType);
useMethod = false;
}
}

if (useMethod)
else if (methodParamType == typeof(Enum) && optionParamType.IsEnum)
{
method = m;
break;
useMethod = true;
}
else
{
useMethod = methodParamType == optionParamType || methodParamType.IsAssignableFrom(optionParamType);
}
}

if (method is null)
{
throw new NullReferenceException("No method with the specified name was found!");
}

return method.Invoke(null, parameters);
return useMethod;
}

protected void Initialize(ICakeContext context, string packageName, string packageVersion, string assemblyName = null)
Expand Down
38 changes: 38 additions & 0 deletions Cake.Issues.Recipe/Content/reporters/GenericReporterData.cake
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
public class GenericReporterData : AddinData
{
private static GenericReporterData _reporter = null;

private GenericReporterData(ICakeContext context)
: base(context, "Cake.Issues.Reporting.Generic", CakeIssuesReportingGenericVersion)
{
_reporter = this;
}

public static GenericReporterData GetReporter(ICakeContext context)
{
return _reporter ?? new GenericReporterData(context);
}

public static IIssueReportFormat CreateIssueFormatFromEmbeddedTemplate(ICakeContext context, IssuesParametersReporting parameters)
{
var reporter = GetReporter(context);

var settings = reporter.CallStaticMethod("FromEmbeddedTemplate", "HtmlDxDataGrid");

var theme = "DevExtremeTheme.MaterialBlueLight"; // Should be changed to be set on IssuesParametersReporting settings class.
reporter.CallStaticMethod("WithOption", settings, "HtmlDxDataGridOption.Theme", theme);

var issueFormat = (IIssueReportFormat)reporter.CallStaticMethod("GenericIssueReportFormat", context, settings);

return issueFormat;
}

public static IIssueReportFormat CreateIssueFormatFromFilePath(ICakeContext context, IssuesParametersReporting parameters, FilePath reportPath)
{
var reporter = GetReporter(context);

var issueFormat = (IIssueReportFormat)reporter.CallStaticMethod("GenericIssueReportFormatFromFilePath", context, reportPath);

return issueFormat;
}
}
1 change: 1 addition & 0 deletions Cake.Issues.Recipe/Content/reporters/reporters.cake
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#load ./GenericReporterData.cake
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,22 @@ public class AzureDevOpsBuildServer : BaseBuildServer
summaryFileName += ".md";
var summaryFilePath = IssuesParameters.OutputDirectory.CombineWithFilePath(summaryFileName);

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

context.TFBuild().Commands.UploadTaskSummary(summaryFilePath);
foreach (var issueFormat in issueFormats)
{
context.CreateIssueReport(
data.Issues,
issueFormat,
data.RepositoryRootDirectory,
summaryFilePath
);
}
}

/// <inheritdoc />
Expand Down

0 comments on commit bdeee48

Please sign in to comment.