public static TypeDescriptor GenerateTypeDescriptor(TypeInfo type, IEnumerable <Func <MemberInfo, bool> > filters = null) { filters = filters ?? Enumerable.Empty <Func <MemberInfo, bool> >(); var generator = new ApiListingGenerator(type.Assembly, filters); return(generator.GenerateTypeDescriptor(type)); }
public static JObject GenerateApiListingReport(Assembly assembly, IEnumerable <Func <MemberInfo, bool> > filters = null) { var generator = new ApiListingGenerator(assembly, filters ?? Enumerable.Empty <Func <MemberInfo, bool> >()); var apiListingDocument = generator.GenerateApiListing(); return(JObject.FromObject(apiListingDocument)); }
private static int OnGenerate( CommandLineApplication command, CommandOption assemblyPath, CommandOption assetsJson, CommandOption framework, CommandOption excludeInternalNamespace, CommandOption output) { if (!assemblyPath.HasValue() || !output.HasValue() || !assetsJson.HasValue() || !framework.HasValue()) { Console.Error.WriteLine("Missing required option."); command.ShowHelp(); return(Error); } var assembly = AssemblyLoader.LoadAssembly( assemblyPath.Value(), assetsJson.Value(), framework.Value()); var filters = new List <Func <MemberInfo, bool> >(); if (excludeInternalNamespace.HasValue()) { filters.Add(ApiListingFilters.IsInInternalNamespace); } var report = ApiListingGenerator.GenerateApiListingReport(assembly, filters); using (var writer = new JsonTextWriter(File.CreateText(output.Value()))) { writer.Formatting = Formatting.Indented; writer.Indentation = 2; writer.IndentChar = ' '; report.WriteTo(writer); } return(Ok); }
private static int OnCompare( CommandLineApplication command, CommandOption apiListingPathOption, CommandOption breakingChangesPathOption, CommandOption assemblyPath, CommandOption assetsJson, CommandOption framework, CommandOption excludeInternalNamespace) { if (!apiListingPathOption.HasValue() || !assemblyPath.HasValue() || !assetsJson.HasValue() || !framework.HasValue()) { command.ShowHelp(); return(Error); } var assembly = AssemblyLoader.LoadAssembly( assemblyPath.Value(), assetsJson.Value(), framework.Value()); var newApiListingFilters = new List <Func <MemberInfo, bool> >(); var oldApiListingFilters = new List <Func <ApiElement, bool> >(); if (excludeInternalNamespace.HasValue()) { newApiListingFilters.Add(ApiListingFilters.IsInInternalNamespace); oldApiListingFilters.Add(ApiListingFilters.IsInInternalNamespace); } var oldApiListing = ApiListingGenerator.LoadFrom(File.ReadAllText(apiListingPathOption.Value()), oldApiListingFilters); var generator = new ApiListingGenerator(assembly, newApiListingFilters); var newApiListing = generator.GenerateApiListing(); var knownBreakingChanges = (breakingChangesPathOption.HasValue() ? JsonConvert.DeserializeObject <IList <BreakingChange> >( File.ReadAllText(breakingChangesPathOption.Value())) : null) ?? new List <BreakingChange>(); var comparer = new ApiListingComparer(oldApiListing, newApiListing); var breakingChanges = comparer.GetDifferences(); var newBreakingChanges = breakingChanges.Except(knownBreakingChanges).ToList(); var incorrectBreakingChanges = knownBreakingChanges.Except(breakingChanges).ToList(); const string indent = " "; var breakingChangesToPrint = new List <BreakingChange>(); if (newBreakingChanges.Count > 0) { Console.WriteLine( $"ERROR: Verifying breaking changes for framework {framework.Value()} failed."); } var removedTypes = newBreakingChanges.Where(b => b.MemberId == null).OrderBy(b => b.TypeId).ToList(); if (removedTypes.Count > 0) { Console.WriteLine(); Console.WriteLine("The following types have been removed."); Console.WriteLine(); Console.WriteLine(string.Join(Environment.NewLine, removedTypes.Select(b => indent + b.TypeId))); Console.WriteLine(); } breakingChangesToPrint.AddRange(removedTypes); var removedMembers = newBreakingChanges .Where(b => b.MemberId != null && b.Kind == ChangeKind.Removal) .OrderBy(b => b.MemberId) .GroupBy(b => b.TypeId) .ToList(); if (removedMembers.Count > 0) { Console.WriteLine(); Console.WriteLine(); Console.WriteLine("The following types have one or more members removed from them."); Console.WriteLine(); foreach (var memberGrouping in removedMembers) { Console.WriteLine(indent + memberGrouping.Key); Console.WriteLine(string.Join(Environment.NewLine, memberGrouping.Select(b => indent + indent + b.MemberId).ToList())); Console.WriteLine(); } } breakingChangesToPrint.AddRange(removedMembers.SelectMany(t => t.ToList())); var newMembersOnInterfaces = newBreakingChanges .Where(b => b.MemberId != null && b.Kind == ChangeKind.Addition) .OrderBy(b => b.MemberId) .GroupBy(b => b.TypeId) .ToList(); if (newMembersOnInterfaces.Count > 0) { Console.WriteLine(); Console.WriteLine(); Console.WriteLine("The following interfaces have one or more members added to them."); foreach (var memberGrouping in newMembersOnInterfaces) { Console.WriteLine(indent + memberGrouping.Key); Console.WriteLine(string.Join(Environment.NewLine, memberGrouping.Select(b => indent + indent + b.MemberId).ToList())); Console.WriteLine(); } } breakingChangesToPrint.AddRange(newMembersOnInterfaces.SelectMany(t => t.ToList())); foreach (var exclusion in incorrectBreakingChanges) { if (breakingChangesPathOption.HasValue()) { Console.Error.WriteLine( $"ERROR: The following exclusion is in the exclusion file '{breakingChangesPathOption.Value()}', but is no longer necessary:"); } else { Console.Error.WriteLine( "ERROR: The following exclusion is in the exclusion file, but is no longer necessary:"); } Console.WriteLine(JsonConvert.SerializeObject(exclusion, Formatting.Indented)); Console.WriteLine(); } if (breakingChangesToPrint.Any()) { Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Following is the list of exclusions that either need to be added to the list of breaking changes, or the breaking changes themselves need to be reverted:"); Console.WriteLine( JsonConvert.SerializeObject( breakingChangesToPrint, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })); Console.WriteLine(); } if (newBreakingChanges.Count > 0 || incorrectBreakingChanges.Count > 0) { Console.WriteLine( "The process for breaking changes is described in: https://github.com/aspnet/Home/wiki/Engineering-guidelines#breaking-changes"); Console.WriteLine( "The process to add an exclusion to this tool is described in: https://github.com/aspnet/BuildTools/wiki/Api-Check#apicheck-exceptions"); Console.WriteLine(); return(Error); } return(Ok); }
private TypeDescriptor FindOrGenerateDescriptorForBaseType(TypeDescriptor candidate) { return(_newApiListing.FindType(candidate.BaseType) ?? ApiListingGenerator.GenerateTypeDescriptor(candidate.Source.BaseType.GetTypeInfo(), _newApiListing.SourceFilters)); }