diff --git a/CHANGELOG.md b/CHANGELOG.md index 836398fa..e8c112be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Support file scoped namespace declarations when generating code (#140) * Improved handling of scope tag expressions, hook and scope errors (#150) * Improved logging for binding discovery (#154) +* Report generic binding errors and log type load errors of binding discovery (#157) ## Bug fixes: diff --git a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/DiscoveryExecutor.cs b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/DiscoveryExecutor.cs index dfe65b91..fd59d3f0 100644 --- a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/DiscoveryExecutor.cs +++ b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/DiscoveryExecutor.cs @@ -73,6 +73,8 @@ public static DiscoveryResult Execute(DiscoveryOptions options, Hooks = discoveryResult.Hooks, SourceFiles = new Dictionary(discoveryResult.SourceFiles), TypeNames = new Dictionary(discoveryResult.TypeNames), + GenericBindingErrors = discoveryResult.GenericBindingErrors, + LogMessages = discoveryResult.TypeLoadErrors.Select(e => $"Type or method has been skipped: {e}").ToArray(), AnalyticsProperties = analytics.ToDictionary() }; } diff --git a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/DiscoveryResultTransformer.cs b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/DiscoveryResultTransformer.cs index 6da1b24e..42be28f3 100644 --- a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/DiscoveryResultTransformer.cs +++ b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/DiscoveryResultTransformer.cs @@ -36,6 +36,14 @@ public InternalDiscoveryResult Transform(BindingData bindingData, ISourceLocatio .OrderBy(sd => sd.SourceLocation) .ToArray(); + string[] GetErrorsWithPrefix(string prefix) => + bindingData.Errors? + .Where(e => e.StartsWith(prefix)) + .Select(e => e.Substring(prefix.Length).Trim()) + .ToArray() ?? Array.Empty(); + + var typeLoadErrors = GetErrorsWithPrefix("TypeLoadError:"); + var genericBindingErrors = GetErrorsWithPrefix("BindingError:"); analytics.AddAnalyticsProperty("TypeNames", typeNamesToKey.Count.ToString()); analytics.AddAnalyticsProperty("SourcePaths", sourceFilesToKey.Count.ToString()); @@ -46,7 +54,9 @@ public InternalDiscoveryResult Transform(BindingData bindingData, ISourceLocatio stepDefinitions, hooks, ReverseDictionary(sourceFilesToKey), - ReverseDictionary(typeNamesToKey) + ReverseDictionary(typeNamesToKey), + genericBindingErrors, + typeLoadErrors ); } diff --git a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/InternalDiscoveryResult.cs b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/InternalDiscoveryResult.cs index c694a9b1..76b5dbd7 100644 --- a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/InternalDiscoveryResult.cs +++ b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/Discovery/InternalDiscoveryResult.cs @@ -4,5 +4,7 @@ public record InternalDiscoveryResult( Reqnroll.VisualStudio.ReqnrollConnector.Models.StepDefinition[] StepDefinitions, Reqnroll.VisualStudio.ReqnrollConnector.Models.Hook[] Hooks, IDictionary SourceFiles, - IDictionary TypeNames + IDictionary TypeNames, + string[] GenericBindingErrors, + string[] TypeLoadErrors ); diff --git a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Models/ConnectorResult.cs b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Models/ConnectorResult.cs index a1c953b7..baad6fde 100644 --- a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Models/ConnectorResult.cs +++ b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Models/ConnectorResult.cs @@ -7,6 +7,7 @@ public abstract class ConnectorResult public string ReqnrollVersion { get; set; } public string ErrorMessage { get; set; } public bool IsFailed => !string.IsNullOrWhiteSpace(ErrorMessage); + public string[] LogMessages { get; set; } public string[] Warnings { get; set; } public Dictionary AnalyticsProperties { get; set; } } diff --git a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Models/DiscoveryResult.cs b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Models/DiscoveryResult.cs index 59134185..01958890 100644 --- a/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Models/DiscoveryResult.cs +++ b/Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Models/DiscoveryResult.cs @@ -7,4 +7,5 @@ public class DiscoveryResult : ConnectorResult public Hook[] Hooks { get; set; } = Array.Empty(); public Dictionary SourceFiles { get; set; } public Dictionary TypeNames { get; set; } + public string[] GenericBindingErrors { get; set; } } diff --git a/Reqnroll.VisualStudio/Discovery/DiscoveryInvoker.cs b/Reqnroll.VisualStudio/Discovery/DiscoveryInvoker.cs index b4e16ded..db3bdfaa 100644 --- a/Reqnroll.VisualStudio/Discovery/DiscoveryInvoker.cs +++ b/Reqnroll.VisualStudio/Discovery/DiscoveryInvoker.cs @@ -102,6 +102,36 @@ public IDiscovery AndDiscoveryProviderSucceed(IDiscoveryResultProvider discovery _discoveryResult = discoveryResultProvider.RunDiscovery(_testAssemblySource.FilePath, _projectSettings.ReqnrollConfigFilePath, _projectSettings); + if (_discoveryResult.LogMessages is { Length: > 0 }) + { + foreach (var logMessage in _discoveryResult.LogMessages) + { + var lines = logMessage.Trim().Split(new[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries); + _logger.LogInfo(lines[0]); + if (lines.Length > 1) + { + _logger.LogVerbose($"Additional details:{Environment.NewLine}{string.Join(Environment.NewLine, lines.Skip(1))}"); + } + } + } + + if (_discoveryResult.Warnings is { Length: > 0 }) + { + foreach (string warning in _discoveryResult.Warnings) + { + _logger.LogWarning(warning); + _errorListServices.AddErrors(new[] + { + new DeveroomUserError + { + Category = DeveroomUserErrorCategory.Discovery, + Message = warning, + Type = TaskErrorCategory.Warning + } + }); + } + } + if (!_discoveryResult.IsFailed) return this; @@ -142,12 +172,32 @@ public IDiscovery ThenImportBindings(string projectName) _logger.LogInfo( $"{_stepDefinitions.Length} step definitions and {_hooks.Length} hooks discovered for project {projectName}"); + ReportGenericBindingErrors(); ReportInvalidStepDefinitions(); ReportInvalidHooks(); return this; } + private void ReportGenericBindingErrors() + { + if (_discoveryResult.GenericBindingErrors == null || !_discoveryResult.GenericBindingErrors.Any()) + return; + + _logger.LogWarning($"Generic binding errors found: {Environment.NewLine}" + + string.Join(Environment.NewLine, _discoveryResult.GenericBindingErrors)); + + _errorListServices.AddErrors( + _discoveryResult.GenericBindingErrors + .Select(errorMessage => new DeveroomUserError + { + Category = DeveroomUserErrorCategory.Discovery, + Message = errorMessage, + Type = TaskErrorCategory.Error + }) + ); + } + public ProjectBindingRegistry AndCreateBindingRegistry(IMonitoringService monitoringService) { monitoringService.MonitorReqnrollDiscovery(_discoveryResult.IsFailed, _discoveryResult.ErrorMessage,