// 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);
        }