// This Build tasks validates that changes are not breaking Api public override bool Execute() { Log.LogMessage(MessageImportance.High, $"CheckApiCompatibility for ApiLevel: {ApiLevel}"); // Check to see if Api has a previous Api defined. if (!api_versions.TryGetValue(ApiLevel, out string previousApiLevel)) { LogError($"Please add ApiLevel:{ApiLevel} to the list of supported apis."); return(!Log.HasLoggedErrors); } // Get the previous api implementation path by replacing the current api string with the previous one. var previousTargetImplementationPath = TargetImplementationPath.Replace(ApiLevel, previousApiLevel); // In case previous api is not defined or directory does not exist we can skip the check. var validateAgainstPreviousApi = !(string.IsNullOrWhiteSpace(previousApiLevel) || !Directory.Exists(previousTargetImplementationPath)); if (validateAgainstPreviousApi) { // First we check the Api level assembly against the previous api level assembly // i.e.: check api breakages using "the just built V2.dll" against "the just built V1.dll" ValidateApiCompat(previousTargetImplementationPath, false); if (Log.HasLoggedErrors) { return(!Log.HasLoggedErrors); } } // If Api level is the latest we should also compare it against the reference assembly // located on the external folder. (xamarin-android-api-compatibility) // i.e.: check apicompat using "the just built V2.dll" against V2.dll located on xamarin-android-api-compatibility repo if (ApiLevel == LastStableApiLevel) { // Check xamarin-android-api-compatibility reference directory exists var referenceContractPath = Path.Combine(ApiCompatibilityPath, "reference"); if (!Directory.Exists(referenceContractPath)) { Log.LogWarning($"CheckApiCompatibility Warning: Skipping reference contract check.\n{referenceContractPath} does not exist."); return(!Log.HasLoggedErrors); } // Before validate, check that zip files were decompressed. var zipFiles = Directory.GetFiles(referenceContractPath, "*.zip"); foreach (var zipFile in zipFiles) { using (var zip = ZipArchive.Open(zipFile, FileMode.Open)) { zip.ExtractAll(referenceContractPath); } } ValidateApiCompat(referenceContractPath, true); } return(!Log.HasLoggedErrors); }
// This Build tasks validates that changes are not breaking Api public override bool Execute() { Log.LogMessage(MessageImportance.High, $"CheckApiCompatibility for ApiLevel: {ApiLevel}"); // Check to see if Api has a previous Api defined. if (!api_versions.TryGetValue(ApiLevel, out string previousApiLevel)) { LogError($"Please add ApiLevel:{ApiLevel} to the list of supported apis."); return(!Log.HasLoggedErrors); } var implementationPath = new DirectoryInfo(TargetImplementationPath); if (!implementationPath.Exists) { LogError($"Implementation path does not exists:'{TargetImplementationPath}'"); return(!Log.HasLoggedErrors); } TargetImplementationPath = implementationPath.FullName; if (TargetImplementationPath.EndsWith("\\") || TargetImplementationPath.EndsWith("/")) { TargetImplementationPath = TargetImplementationPath.Substring(0, TargetImplementationPath.Length - 1); } // For non netcoreapp assemblies we should compare against previous version. if (TargetImplementationPath.IndexOf(netCoreAppVersion, StringComparison.OrdinalIgnoreCase) == -1) { // Get the previous api implementation path by replacing the current api string with the previous one. var previousTargetImplementationPath = new DirectoryInfo(TargetImplementationPath.Replace(ApiLevel, previousApiLevel)); // In case previous api is not defined or directory does not exist we can skip the check. var validateAgainstPreviousApi = !(string.IsNullOrWhiteSpace(previousApiLevel) || !previousTargetImplementationPath.Exists); if (validateAgainstPreviousApi) { // First we check the Api level assembly against the previous api level assembly // i.e.: check api breakages using "the just built V2.dll" against "the just built V1.dll" ValidateApiCompat(previousTargetImplementationPath.FullName, false); if (Log.HasLoggedErrors) { return(!Log.HasLoggedErrors); } } } // If Api level is the latest we should also compare it against the reference assembly // located on the external folder. (xamarin-android-api-compatibility) // i.e.: check apicompat using "the just built V2.dll" against V2.dll located on xamarin-android-api-compatibility repo // This condition is also valid for netcoreapp if (ApiLevel == LastStableApiLevel) { // Check xamarin-android-api-compatibility reference directory exists var referenceContractPath = new DirectoryInfo(Path.Combine(ApiCompatibilityPath, "reference")); if (!referenceContractPath.Exists) { Log.LogWarning($"CheckApiCompatibility Warning: Skipping reference contract check.\n{referenceContractPath.FullName} does not exist."); return(!Log.HasLoggedErrors); } // Before validate, check that zip files were decompressed. var zipFiles = Directory.GetFiles(referenceContractPath.FullName, "*.zip"); foreach (var zipFile in zipFiles) { var zipDateTime = File.GetLastWriteTimeUtc(zipFile); using (var zip = ZipArchive.Open(zipFile, FileMode.Open)) { foreach (var entry in zip) { var path = Path.Combine(referenceContractPath.FullName, entry.NativeFullName); if (!File.Exists(path) || File.GetLastWriteTimeUtc(path) < zipDateTime) { Log.LogMessage($"Extracting: {path}"); using (var fileStream = File.Create(path)) { entry.Extract(fileStream); } } else { Log.LogMessage($"Skipping, up to date: {path}"); } } } } ValidateApiCompat(referenceContractPath.FullName, true); } return(!Log.HasLoggedErrors); }