private static UpversionType AnalyzeMethods(IList <MethodSpec> oldMethods, IList <MethodSpec> newMethods) { UpversionType maxUpversionType = UpversionType.Patch; foreach (MethodSpec oldMethod in oldMethods) { MethodSpec newMethod = newMethods .FirstOrDefault(field => field.Name.Name.Equals(oldMethod.Name.Name, StringComparison.InvariantCulture)); if (newMethod == null) { return(UpversionType.Major); } if (!newMethod.ReturnType.Equals(oldMethod.ReturnType, StringComparison.InvariantCulture)) { return(UpversionType.Major); } // Check parameters bool isMajorChange = NapackAnalyst.AnayzeParameters(oldMethod.Parameters, newMethod.Parameters); if (isMajorChange) { return(UpversionType.Major); } } if (maxUpversionType == UpversionType.Patch && newMethods.Count != oldMethods.Count) { return(UpversionType.Minor); } return(maxUpversionType); }
private static UpversionType AnalyzeConstructors(IList <ConstructorSpec> oldConstructors, IList <ConstructorSpec> newConstructors) { UpversionType maxUpversionType = UpversionType.Patch; foreach (ConstructorSpec oldConstructor in oldConstructors) { // Constructor matching is complicated as all constructors have the same name, but different parameters. // For now, perform an inefficient n^2 matching by comparing each old constructor against each new one. bool anyWithoutMajorChanges = false; foreach (ConstructorSpec newConstructor in newConstructors) { if (!NapackAnalyst.AnayzeParameters(oldConstructor.Parameters, newConstructor.Parameters)) { anyWithoutMajorChanges = true; break; } } if (!anyWithoutMajorChanges) { return(UpversionType.Major); } } if (maxUpversionType == UpversionType.Patch && newConstructors.Count != oldConstructors.Count) { return(UpversionType.Minor); } return(maxUpversionType); }
private static UpversionType AnalyzeInterface(InterfaceSpec oldInterfaceSpec, InterfaceSpec newInterfaceSpec) { UpversionType maxUpversionType = UpversionType.Patch; if (newInterfaceSpec == null) { // The new spec removed a publically facing class. return(UpversionType.Major); } UpversionType upversionType = NapackAnalyst.AnalyzeProperties(oldInterfaceSpec.Properties, newInterfaceSpec.Properties); if (upversionType == UpversionType.Major) { return(upversionType); } else if (upversionType == UpversionType.Minor) { maxUpversionType = UpversionType.Minor; } upversionType = NapackAnalyst.AnalyzeMethods(oldInterfaceSpec.Methods, newInterfaceSpec.Methods); if (upversionType == UpversionType.Major) { return(upversionType); } else if (upversionType == UpversionType.Minor) { maxUpversionType = UpversionType.Minor; } return(maxUpversionType); }
/// <summary> /// Determines the requried upversioning when code transitions from the old Napack to the new Napack. /// </summary> /// <remarks> /// Major == breaking changes. /// Minor == publically-facing API was added (but not changed or removed) from the new Napack. /// Patch == The publically-facing API is identical between both Napacks, excluding documentation. /// </remarks> public static UpversionType DeterminedRequiredUpversioning(NapackSpec oldNapack, NapackSpec newNapack) { UpversionType maxUpversionType = UpversionType.Patch; foreach (ClassSpec oldClassSpec in oldNapack.Classes) { ClassSpec newClassSpec = newNapack.Classes .FirstOrDefault(cls => cls.Name.Name.Equals(oldClassSpec.Name.Name, StringComparison.InvariantCulture)); UpversionType upversionType = NapackAnalyst.AnalyzeClass(oldClassSpec, newClassSpec); if (upversionType == UpversionType.Major) { // Exit early, as we found a breaking change. return(UpversionType.Major); } else if (upversionType == UpversionType.Minor) { maxUpversionType = UpversionType.Minor; } } foreach (InterfaceSpec oldInterfaceSpec in oldNapack.Interfaces) { InterfaceSpec newInterfaceSpec = newNapack.Interfaces .FirstOrDefault(cls => cls.Name.Name.Equals(oldInterfaceSpec.Name.Name, StringComparison.InvariantCulture)); UpversionType upversionType = NapackAnalyst.AnalyzeInterface(oldInterfaceSpec, newInterfaceSpec); if (upversionType == UpversionType.Major) { // Exit early, as we found a breaking change. return(UpversionType.Major); } else if (upversionType == UpversionType.Minor) { maxUpversionType = UpversionType.Minor; } } // No APIs added in the prior classes. Did the new package add classes? if (maxUpversionType == UpversionType.Patch && (newNapack.Classes.Count != oldNapack.Classes.Count || newNapack.Interfaces.Count != oldNapack.Interfaces.Count)) { maxUpversionType = UpversionType.Minor; } return(maxUpversionType); }
private static UpversionType AnalyzeClass(ClassSpec oldClassSpec, ClassSpec newClassSpec) { UpversionType maxUpversionType = UpversionType.Patch; if (newClassSpec == null) { // The new spec removed a publically facing class. return(UpversionType.Major); } // Check if any modifier changes force a major (breaking) change. if ((!oldClassSpec.IsAbstract && newClassSpec.IsAbstract) || (oldClassSpec.IsStatic != newClassSpec.IsStatic) || (!oldClassSpec.IsSealed && newClassSpec.IsSealed)) { return(UpversionType.Major); } // Verify all old fields exist UpversionType upversionType = NapackAnalyst.AnalyzeFields(oldClassSpec.PublicFields, newClassSpec.PublicFields); if (upversionType == UpversionType.Major) { return(upversionType); } else if (upversionType == UpversionType.Minor) { maxUpversionType = UpversionType.Minor; } upversionType = NapackAnalyst.AnalyzeProperties(oldClassSpec.PublicProperties, newClassSpec.PublicProperties); if (upversionType == UpversionType.Major) { return(upversionType); } else if (upversionType == UpversionType.Minor) { maxUpversionType = UpversionType.Minor; } upversionType = NapackAnalyst.AnalyzeConstructors(oldClassSpec.PublicConstructors, newClassSpec.PublicConstructors); if (upversionType == UpversionType.Major) { return(upversionType); } else if (upversionType == UpversionType.Minor) { maxUpversionType = UpversionType.Minor; } upversionType = NapackAnalyst.AnalyzeMethods(oldClassSpec.PublicMethods, newClassSpec.PublicMethods); if (upversionType == UpversionType.Major) { return(upversionType); } else if (upversionType == UpversionType.Minor) { maxUpversionType = UpversionType.Minor; } // Analyze classes recursively. foreach (ClassSpec oldClass in oldClassSpec.PublicClasses) { ClassSpec newClass = newClassSpec.PublicClasses .FirstOrDefault(cls => cls.Name.Name.Equals(oldClass.Name.Name, StringComparison.InvariantCulture)); upversionType = NapackAnalyst.AnalyzeClass(oldClass, newClass); if (upversionType == UpversionType.Major) { return(upversionType); } else if (upversionType == UpversionType.Minor) { maxUpversionType = UpversionType.Minor; } } if (maxUpversionType == UpversionType.Patch && oldClassSpec.PublicClasses.Count != newClassSpec.PublicClasses.Count) { maxUpversionType = UpversionType.Minor; } return(maxUpversionType); }