private AnalyzeRequest GenerateRequest(IApiPortOptions options, IDependencyInfo dependencyInfo) { return(new AnalyzeRequest { Targets = options.Targets.SelectMany(_targetMapper.GetNames).ToList(), Dependencies = dependencyInfo.Dependencies, AssembliesToIgnore = _assembliesToIgnore, // We pass along assemblies to ignore instead of filtering them from Dependencies at this point // because breaking change analysis and portability analysis will likely want to filter dependencies // in different ways for ignored assemblies. // For breaking changes, we should show breaking changes for // an assembly if it is un-ignored on any of the user-specified targets and we should hide breaking changes // for an assembly if it ignored on all user-specified targets. // For portability analysis, on the other hand, we will want to show portability for precisely those targets // that a user specifies that are not on the ignore list. In this case, some of the assembly's dependency // information will be needed. UnresolvedAssemblies = dependencyInfo.UnresolvedAssemblies.Keys.ToList(), UnresolvedAssembliesDictionary = dependencyInfo.UnresolvedAssemblies, UserAssemblies = dependencyInfo.UserAssemblies.ToList(), AssembliesWithErrors = dependencyInfo.AssembliesWithErrors.ToList(), ApplicationName = options.Description, Version = AnalyzeRequest.CurrentVersion, RequestFlags = options.RequestFlags, BreakingChangesToSuppress = options.BreakingChangeSuppressions }); }
public ConsoleApiPort(ApiPortClient apiPortClient, ITargetMapper targetMapper, IApiPortOptions options, DocIdSearchRepl repl) { _apiPortClient = apiPortClient; _targetMapper = targetMapper; _options = options; _repl = repl; }
/// <summary> /// Gets an analysis report based on the options supplied /// </summary> /// <param name="options">Options to generate report</param> /// <returns>A collection of reports</returns> private async Task <IEnumerable <byte[]> > GetAnalysisResultAsync(IApiPortOptions options) { var dependencyInfo = _dependencyFinder.FindDependencies(options.InputAssemblies, _progressReport); if (dependencyInfo.UserAssemblies.Any()) { AnalyzeRequest request = GenerateRequest(options, dependencyInfo); // Create the progress reporter here (instead of within GetResultFromServiceAsync) since the reporter does not work well when run in parallel using (var progressTask = _progressReport.StartTask(LocalizedStrings.SendingDataToService)) { try { var tasks = options.OutputFormats .Select(f => GetResultFromServiceAsync(request, f)) .ToList(); await Task.WhenAll(tasks); return(tasks.Select(t => t.Result).ToList()); } catch (Exception) { progressTask.Abort(); throw; } } } else { _progressReport.ReportIssue(LocalizedStrings.NoFilesAvailableToUpload); return(Enumerable.Empty <byte[]>()); } }
/// <summary> /// Ensures that the analysis options are valid. If they are not, /// throws a <see cref="InvalidApiPortOptionsException"/> /// </summary> private static void ValidateOptions(IApiPortOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (options.Targets.Count() > MaxNumberOfTargets && options.OutputFormats.Contains(Excel, StringComparer.OrdinalIgnoreCase)) { throw new InvalidApiPortOptionsException(string.Format(CultureInfo.CurrentCulture, LocalizedStrings.TooManyTargetsMessage, MaxNumberOfTargets)); } }
public ReadWriteApiPortOptions(IApiPortOptions other) { BreakingChangeSuppressions = other.BreakingChangeSuppressions; Description = other.Description; IgnoredAssemblyFiles = other.IgnoredAssemblyFiles; InputAssemblies = other.InputAssemblies; OutputFormats = other.OutputFormats; RequestFlags = other.RequestFlags; Targets = other.Targets; ServiceEndpoint = other.ServiceEndpoint; InvalidInputFiles = other.InvalidInputFiles; OutputFileName = other.OutputFileName; }
/// <summary> /// Gets an analysis report based on the options supplied /// </summary> /// <param name="options">Options to generate report</param> /// <returns>A collection of reports</returns> private async Task <MultipleFormatAnalysis> GetAnalysisResultAsync(IApiPortOptions options) { var dependencyInfo = _dependencyFinder.FindDependencies(options.InputAssemblies, _progressReport); if (dependencyInfo.UserAssemblies.Any()) { AnalyzeRequest request = GenerateRequest(options, dependencyInfo); // Create the progress reporter here (instead of within GetResultFromServiceAsync) since the reporter does not work well when run in parallel using (var progressTask = _progressReport.StartTask(LocalizedStrings.AnalyzingCompatibility)) { try { var tasks = options.OutputFormats .Select(f => new { Format = f, Task = GetResultFromServiceAsync(request, f) }) .ToList(); await Task.WhenAll(tasks.Select(t => t.Task)); var results = tasks.Select(t => new ReportingResultWithFormat { Data = t.Task.Result, Format = t.Format, }).ToList(); return(new MultipleFormatAnalysis { Info = dependencyInfo, Request = request, Results = results }); } catch (Exception) { progressTask.Abort(); throw; } } } else { _progressReport.ReportIssue(LocalizedStrings.NoFilesAvailableToUpload); return(new MultipleFormatAnalysis { Results = Enumerable.Empty <ReportingResultWithFormat>() }); } }
/// <summary> /// Analyzes assemblies provided by options /// </summary> /// <param name="options"></param> /// <returns>A reporting result for the supplied assemblies</returns> public async Task<ReportingResult> AnalyzeAssembliesAsync(IApiPortOptions options) { var dependencyInfo = _dependencyFinder.FindDependencies(options.InputAssemblies, _progressReport); if (dependencyInfo.UserAssemblies.Any()) { AnalyzeRequest request = GenerateRequest(options, dependencyInfo); return await GetResultFromServiceAsync(request, dependencyInfo); } else { _progressReport.ReportIssue(LocalizedStrings.NoFilesAvailableToUpload); return null; } }
/// <summary> /// Analyzes assemblies provided by options /// </summary> /// <param name="options"></param> /// <returns>A reporting result for the supplied assemblies</returns> public async Task <ReportingResult> AnalyzeAssembliesAsync(IApiPortOptions options) { var dependencyInfo = _dependencyFinder.FindDependencies(options.InputAssemblies, _progressReport); if (dependencyInfo.UserAssemblies.Any()) { AnalyzeRequest request = GenerateRequest(options, dependencyInfo); return(await GetResultFromServiceAsync(request, dependencyInfo)); } else { _progressReport.ReportIssue(LocalizedStrings.NoFilesAvailableToUpload); return(null); } }
private AnalyzeRequest GenerateRequest(IApiPortOptions options, IDependencyInfo dependencyInfo) { // Match the dependencyInfo for each user assembly to the given // input assemblies to see whether or not the assembly was explicitly // specified. foreach (var assembly in dependencyInfo.UserAssemblies) { // Windows's file paths are case-insensitive var matchingAssembly = options.InputAssemblies.FirstOrDefault(x => x.Key.Name.Equals(assembly.Location, StringComparison.OrdinalIgnoreCase)); // AssemblyInfo is explicitly specified if we found a matching // assembly location in the input dictionary AND the value is // true. assembly.IsExplicitlySpecified = matchingAssembly.Key != default(IAssemblyFile) && matchingAssembly.Value; } return(new AnalyzeRequest { Entrypoints = new[] { options.Entrypoint }, Targets = options.Targets.SelectMany(_targetMapper.GetNames).ToList(), Dependencies = dependencyInfo.Dependencies, // We pass along assemblies to ignore instead of filtering them from Dependencies at this point // because breaking change analysis and portability analysis will likely want to filter dependencies // in different ways for ignored assemblies. // For breaking changes, we should show breaking changes for // an assembly if it is un-ignored on any of the user-specified targets and we should hide breaking changes // for an assembly if it ignored on all user-specified targets. // For portability analysis, on the other hand, we will want to show portability for precisely those targets // that a user specifies that are not on the ignore list. In this case, some of the assembly's dependency // information will be needed. AssembliesToIgnore = _assembliesToIgnore, UnresolvedAssemblies = dependencyInfo.UnresolvedAssemblies.Keys.ToList(), UnresolvedAssembliesDictionary = dependencyInfo.UnresolvedAssemblies, UserAssemblies = dependencyInfo.UserAssemblies.ToList(), NonUserAssemblies = dependencyInfo.NonUserAssemblies.ToList(), AssembliesWithErrors = dependencyInfo.AssembliesWithErrors.ToList(), ApplicationName = options.Description, Version = AnalyzeRequest.CurrentVersion, RequestFlags = options.RequestFlags, BreakingChangesToSuppress = options.BreakingChangeSuppressions, ReferencedNuGetPackages = options.ReferencedNuGetPackages }); }
/// <summary> /// Writes analysis reports to path supplied by options /// </summary> /// <param name="options"></param> /// <param name="includeResponse"></param> /// <returns>Output paths to the reports that were successfully written.</returns> public async Task <ReportingResultPaths> WriteAnalysisReportsAsync(IApiPortOptions options, bool includeResponse) { ValidateOptions(options); var jsonAdded = includeResponse ? TryAddJsonToOptions(options, out options) : false; foreach (var errorInput in options.InvalidInputFiles) { _progressReport.ReportIssue(string.Format(CultureInfo.CurrentCulture, LocalizedStrings.InvalidFileName, errorInput)); } var results = await GetAnalysisResultAsync(options); var outputPaths = new List <string>(); AnalyzeResponse response = null; foreach (var result in results.Results) { if (string.Equals(Json, result.Format, StringComparison.OrdinalIgnoreCase)) { response = result.Data?.Deserialize <AnalyzeResponse>(); if (jsonAdded) { continue; } } var outputPath = await CreateReport(result.Data, options.OutputFileName, result.Format, options.OverwriteOutputFile); if (!string.IsNullOrEmpty(outputPath)) { outputPaths.Add(outputPath); } } return(new ReportingResultPaths { Paths = outputPaths, Result = GetReportingResult(results.Request, response, results.Info) }); }
/// <summary> /// Gets an analysis report based on the options supplied /// </summary> /// <param name="options">Options to generate report</param> /// <returns>A collection of reports</returns> private async Task <MultipleFormatAnalysis> GetAnalysisResultAsync(IApiPortOptions options) { var assemblies = options.InputAssemblies?.Keys ?? Array.Empty <IAssemblyFile>(); var dependencyInfo = _dependencyFinder.FindDependencies(assemblies, _progressReport); if (dependencyInfo.UserAssemblies.Any()) { AnalyzeRequest request = GenerateRequest(options, dependencyInfo); // Create the progress reporter here (instead of within GetResultFromServiceAsync) since the reporter does not work well when run in parallel using (var progressTask = _progressReport.StartTask(LocalizedStrings.AnalyzingCompatibility)) { try { var results = await _apiPortService.SendAnalysisAsync(request, options.OutputFormats); CheckEndpointStatus(results.Headers.Status); return(new MultipleFormatAnalysis { Info = dependencyInfo, Request = request, Results = results.Response }); } catch (Exception) { progressTask.Abort(); throw; } } } else { _progressReport.ReportIssue(LocalizedStrings.NoFilesAvailableToUpload); return(new MultipleFormatAnalysis { Results = Enumerable.Empty <ReportingResultWithFormat>() }); } }
/// <summary> /// Writes analysis reports to path supplied by options /// </summary> /// <param name="options"></param> /// <returns>Output paths</returns> public async Task <IEnumerable <string> > WriteAnalysisReportsAsync(IApiPortOptions options) { foreach (var errorInput in options.InvalidInputFiles) { _progressReport.ReportIssue(string.Format(LocalizedStrings.InvalidFileName, errorInput)); } var results = await GetAnalysisResultAsync(options); var outputPaths = new List <string>(); foreach (var resultAndFormat in results.Zip(options.OutputFormats, (r, f) => new { Result = r, Format = f })) { var outputPath = await CreateReport(resultAndFormat.Result, options.OutputFileName, resultAndFormat.Format); outputPaths.Add(outputPath); } return(outputPaths); }
public FileIgnoreAssemblyInfoList(IApiPortOptions options) { #if FEATURE_ASSEMBLY_LOCATION var noDefaultIgnoreFile = options.RequestFlags.HasFlag(AnalyzeRequestFlags.NoDefaultIgnoreFile); if (!noDefaultIgnoreFile) { LoadJsonFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), DEFAULT_IGNORE_ASSEMBLIES_FILE)); } #endif var ignoredAssemblyFiles = options.IgnoredAssemblyFiles; if (ignoredAssemblyFiles != null) { foreach (string ignoreFile in ignoredAssemblyFiles) { LoadJsonFile(ignoreFile); } } }
/// <summary> /// Add JSON to the options object if it is not there. This is used in cases where an analysis /// doesn't request the JSON result, but the result is needed for analysis (ie source line mapping) /// </summary> /// <param name="options"></param> /// <param name="other"></param> /// <returns></returns> private bool TryAddJsonToOptions(IApiPortOptions options, out IApiPortOptions other) { var outputs = new HashSet <string>(options.OutputFormats, StringComparer.OrdinalIgnoreCase); if (outputs.Contains(Json)) { other = options; return(false); } else { outputs.Add(Json); other = new ReadWriteApiPortOptions(options) { OutputFormats = outputs }; return(true); } }
/// <summary> /// Gets an analysis report based on the options supplied /// </summary> /// <param name="options">Options to generate report</param> /// <returns>A collection of reports</returns> private async Task <IEnumerable <byte[]> > GetAnalysisResultAsync(IApiPortOptions options) { var dependencyInfo = _dependencyFinder.FindDependencies(options.InputAssemblies, _progressReport); if (dependencyInfo.UserAssemblies.Any()) { AnalyzeRequest request = GenerateRequest(options, dependencyInfo); var tasks = options.OutputFormats .Select(f => GetResultFromServiceAsync(request, f)) .ToList(); await Task.WhenAll(tasks); return(tasks.Select(t => t.Result).ToList()); } else { _progressReport.ReportIssue(LocalizedStrings.NoFilesAvailableToUpload); return(Enumerable.Empty <byte[]>()); } }
public async Task<IEnumerable<byte[]>> GetAnalysisReportAsync(IApiPortOptions options, IEnumerable<string> outputFormats) { var dependencyInfo = _dependencyFinder.FindDependencies(options.InputAssemblies, _progressReport); if (dependencyInfo.UserAssemblies.Any()) { AnalyzeRequest request = GenerateRequest(options, dependencyInfo); var tasks = outputFormats .Select(f => GetResultFromServiceAsync(request, f)) .ToList(); await Task.WhenAll(tasks); return tasks.Select(t => t.Result).ToList(); } else { _progressReport.ReportIssue(LocalizedStrings.NoFilesAvailableToUpload); return Enumerable.Empty<byte[]>(); } }
/// <summary> /// Writes analysis reports to path supplied by options /// </summary> /// <param name="options"></param> /// <returns>Output paths to the reports that were successfully written.</returns> public async Task <IEnumerable <string> > WriteAnalysisReportsAsync(IApiPortOptions options) { var result = await WriteAnalysisReportsAsync(options, false); return(result.Paths); }
/// <summary> /// Writes analysis reports to path supplied by options /// </summary> /// <param name="options"></param> /// <returns>Output paths</returns> public async Task<IEnumerable<string>> WriteAnalysisReportsAsync(IApiPortOptions options) { foreach (var errorInput in options.InvalidInputFiles) { _progressReport.ReportIssue(string.Format(LocalizedStrings.InvalidFileName, errorInput)); } var results = await GetAnalysisResultAsync(options); var outputPaths = new List<string>(); foreach (var resultAndFormat in results.Zip(options.OutputFormats, (r, f) => new { Result = r, Format = f })) { var outputPath = await CreateReport(resultAndFormat.Result, options.OutputFileName, resultAndFormat.Format); outputPaths.Add(outputPath); } return outputPaths; }
public ConsoleApiPort(ApiPortClient apiPortClient, ITargetMapper targetMapper, IApiPortOptions options) { _apiPortClient = apiPortClient; _targetMapper = targetMapper; _options = options; }
/// <summary> /// Add JSON to the options object if it is not there. This is used in cases where an analysis /// doesn't request the JSON result, but the result is needed for analysis (ie source line mapping) /// </summary> /// <param name="options"></param> /// <param name="other"></param> /// <returns></returns> private bool TryAddJsonToOptions(IApiPortOptions options, out IApiPortOptions other) { var outputs = new HashSet<string>(options.OutputFormats, StringComparer.OrdinalIgnoreCase); if (outputs.Contains(Json)) { other = options; return false; } else { outputs.Add(Json); other = new ReadWriteApiPortOptions(options) { OutputFormats = outputs }; return true; } }
/// <summary> /// Gets an analysis report based on the options supplied /// </summary> /// <param name="options">Options to generate report</param> /// <returns>A collection of reports</returns> private async Task<IEnumerable<byte[]>> GetAnalysisResultAsync(IApiPortOptions options) { var dependencyInfo = _dependencyFinder.FindDependencies(options.InputAssemblies, _progressReport); if (dependencyInfo.UserAssemblies.Any()) { AnalyzeRequest request = GenerateRequest(options, dependencyInfo); // Create the progress reporter here (instead of within GetResultFromServiceAsync) since the reporter does not work well when run in parallel using (var progressTask = _progressReport.StartTask(LocalizedStrings.SendingDataToService)) { try { var tasks = options.OutputFormats .Select(f => GetResultFromServiceAsync(request, f)) .ToList(); await Task.WhenAll(tasks); return tasks.Select(t => t.Result).ToList(); } catch (Exception) { progressTask.Abort(); throw; } } } else { _progressReport.ReportIssue(LocalizedStrings.NoFilesAvailableToUpload); return Enumerable.Empty<byte[]>(); } }
/// <summary> /// Writes analysis reports to path supplied by options /// </summary> /// <param name="options"></param> /// <param name="includeResponse"></param> /// <returns>Output paths to the reports that were successfully written.</returns> public async Task<ReportingResultPaths> WriteAnalysisReportsAsync(IApiPortOptions options, bool includeResponse) { var jsonAdded = includeResponse ? TryAddJsonToOptions(options, out options) : false; foreach (var errorInput in options.InvalidInputFiles) { _progressReport.ReportIssue(string.Format(LocalizedStrings.InvalidFileName, errorInput)); } var results = await GetAnalysisResultAsync(options); var outputPaths = new List<string>(); AnalyzeResponse response = null; foreach (var result in results.Results) { if (string.Equals(Json, result.Format, StringComparison.OrdinalIgnoreCase)) { response = result.Data?.Deserialize<AnalyzeResponse>(); if (jsonAdded) { continue; } } var outputPath = await CreateReport(result.Data, options.OutputFileName, result.Format); if (!string.IsNullOrEmpty(outputPath)) { outputPaths.Add(outputPath); } } return new ReportingResultPaths { Paths = outputPaths, Result = GetReportingResult(results.Request, response, results.Info) }; }
/// <summary> /// Gets an analysis report based on the options supplied /// </summary> /// <param name="options">Options to generate report</param> /// <returns>A collection of reports</returns> private async Task<MultipleFormatAnalysis> GetAnalysisResultAsync(IApiPortOptions options) { var dependencyInfo = _dependencyFinder.FindDependencies(options.InputAssemblies, _progressReport); if (dependencyInfo.UserAssemblies.Any()) { AnalyzeRequest request = GenerateRequest(options, dependencyInfo); // Create the progress reporter here (instead of within GetResultFromServiceAsync) since the reporter does not work well when run in parallel using (var progressTask = _progressReport.StartTask(LocalizedStrings.AnalyzingCompatibility)) { try { var results = await _apiPortService.SendAnalysisAsync(request, options.OutputFormats); CheckEndpointStatus(results.Headers.Status); return new MultipleFormatAnalysis { Info = dependencyInfo, Request = request, Results = results.Response }; } catch (Exception) { progressTask.Abort(); throw; } } } else { _progressReport.ReportIssue(LocalizedStrings.NoFilesAvailableToUpload); return new MultipleFormatAnalysis { Results = Enumerable.Empty<ReportingResultWithFormat>() }; } }
private AnalyzeRequest GenerateRequest(IApiPortOptions options, IDependencyInfo dependencyInfo) { return new AnalyzeRequest { Targets = options.Targets.SelectMany(_targetMapper.GetNames).ToList(), Dependencies = dependencyInfo.Dependencies, AssembliesToIgnore = _assembliesToIgnore, // We pass along assemblies to ignore instead of filtering them from Dependencies at this point // because breaking change analysis and portability analysis will likely want to filter dependencies // in different ways for ignored assemblies. // For breaking changes, we should show breaking changes for // an assembly if it is un-ignored on any of the user-specified targets and we should hide breaking changes // for an assembly if it ignored on all user-specified targets. // For portability analysis, on the other hand, we will want to show portability for precisely those targets // that a user specifies that are not on the ignore list. In this case, some of the assembly's dependency // information will be needed. UnresolvedAssemblies = dependencyInfo.UnresolvedAssemblies.Keys.ToList(), UnresolvedAssembliesDictionary = dependencyInfo.UnresolvedAssemblies, UserAssemblies = dependencyInfo.UserAssemblies.ToList(), AssembliesWithErrors = dependencyInfo.AssembliesWithErrors.ToList(), ApplicationName = options.Description, Version = AnalyzeRequest.CurrentVersion, RequestFlags = options.RequestFlags, BreakingChangesToSuppress = options.BreakingChangeSuppressions }; }
/// <summary> /// Writes analysis reports to path supplied by options /// </summary> /// <param name="options"></param> /// <returns>Output paths to the reports that were successfully written.</returns> public async Task<IEnumerable<string>> WriteAnalysisReportsAsync(IApiPortOptions options) { var result = await WriteAnalysisReportsAsync(options, false); return result.Paths; }