diff --git a/schema/cloud.exclusions.schema.json b/schema/cloud.exclusions.schema.json index 7563fff..33999ac 100644 --- a/schema/cloud.exclusions.schema.json +++ b/schema/cloud.exclusions.schema.json @@ -24,6 +24,8 @@ "enum": [ "Global", "UsGov", + "UsGovL4", + "UsGovL5", "China" ] }, diff --git a/src/CheckCloudSupport.csproj b/src/CheckCloudSupport.csproj index df4ce8e..0b78737 100644 --- a/src/CheckCloudSupport.csproj +++ b/src/CheckCloudSupport.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/Docs/ApiDocument.cs b/src/Docs/ApiDocument.cs index 7d4300c..dbe1f3b 100644 --- a/src/Docs/ApiDocument.cs +++ b/src/Docs/ApiDocument.cs @@ -215,9 +215,13 @@ private static string GetIncludeLine(CloudSupportStatus status, string includeDi return status switch { CloudSupportStatus.AllClouds => $"[!INCLUDE [national-cloud-support]({includeDirectory}/all-clouds.md)]", - CloudSupportStatus.GlobalAndUSGov => $"[!INCLUDE [national-cloud-support]({includeDirectory}/global-us.md)]", CloudSupportStatus.GlobalAndChina => $"[!INCLUDE [national-cloud-support]({includeDirectory}/global-china.md)]", - CloudSupportStatus.GlobalOnly => $"[!INCLUDE [national-cloud-support]({includeDirectory}/global-only.md)]", + CloudSupportStatus.GlobalAndChinaAndUsGovL4 => $"[!INCLUDE [national-cloud-support]({includeDirectory}/global-china-us-l4.md)]", + CloudSupportStatus.GlobalAndChinaAndUsGovL5 => $"[!INCLUDE [national-cloud-support]({includeDirectory}/global-china-us-l5.md)]", + CloudSupportStatus.GlobalAndUSGov => $"[!INCLUDE [national-cloud-support]({includeDirectory}/global-us.md)]", + CloudSupportStatus.GlobalAndUsGovL4 => $"[!INCLUDE [national-cloud-support]({includeDirectory}/global-us-l4.md)]", + CloudSupportStatus.GlobalAndUsGovL5 => $"[!INCLUDE [national-cloud-support]({includeDirectory}/global-us-l5.md)]", + CloudSupportStatus.Global => $"[!INCLUDE [national-cloud-support]({includeDirectory}/global-only.md)]", _ => throw new ArgumentException("Invalid cloud support status"), }; } diff --git a/src/Docs/CloudSupportStatus.cs b/src/Docs/CloudSupportStatus.cs index 8748f36..ee172f3 100644 --- a/src/Docs/CloudSupportStatus.cs +++ b/src/Docs/CloudSupportStatus.cs @@ -6,30 +6,71 @@ namespace CheckCloudSupport.Docs; /// /// Represents the cloud support status of an API. /// +[Flags] public enum CloudSupportStatus { /// /// Cloud support status is undetermined. /// - Unknown, + Unknown = 0, /// - /// API is supported in all public national clouds. + /// API is supported in Chinese cloud. /// - AllClouds, + China = 1 << 0, /// - /// API is supported in the global and US Government clouds only. + /// API is supported in the global cloud. /// - GlobalAndUSGov, + Global = 1 << 1, /// - /// API is supported in the global and Chinese clouds only. + /// API is supported in the US Government L4 cloud. /// - GlobalAndChina, + USGovL4 = 1 << 2, /// - /// API is supported in the global cloud only. + /// API is supported in the US Government L5 cloud. /// - GlobalOnly, + USGovL5 = 1 << 3, + + /// + /// API is supported in the US Government cloud (L4 and L5). + /// + USGov = USGovL4 | USGovL5, + + /// + /// API is supported in all clouds (China, Global, and US Government). + /// + AllClouds = China | Global | USGov, + + /// + /// API is supported in both Global and US Government clouds. + /// + GlobalAndUSGov = Global | USGov, + + /// + /// API is supported in both Global and Chinese clouds. + /// + GlobalAndChina = Global | China, + + /// + /// API is supported in both Global and US Government L4 clouds. + /// + GlobalAndUsGovL4 = Global | USGovL4, + + /// + /// API is supported in both Global and US Government L5 clouds. + /// + GlobalAndUsGovL5 = Global | USGovL5, + + /// + /// API is supported in Global, Chinese, and US Government L4 clouds. + /// + GlobalAndChinaAndUsGovL4 = Global | China | USGovL4, + + /// + /// API is supported in Global, Chinese, and US Government L5 clouds. + /// + GlobalAndChinaAndUsGovL5 = Global | China | USGovL5, } diff --git a/src/Docs/DocSet.cs b/src/Docs/DocSet.cs index f3d90c2..d0ef491 100644 --- a/src/Docs/DocSet.cs +++ b/src/Docs/DocSet.cs @@ -38,32 +38,6 @@ public static async Task CreateFromDirectory(string docsRoot) return docSet; } - /// - /// Combines two into the most inclusive value. - /// - /// The first status. - /// The second status. - /// The combined status. - public static CloudSupportStatus CombineStatuses(CloudSupportStatus a, CloudSupportStatus b) - { - if (a == b) - { - return a; - } - - if (a == CloudSupportStatus.Unknown || a == CloudSupportStatus.GlobalOnly) - { - return b == CloudSupportStatus.Unknown ? CloudSupportStatus.GlobalOnly : b; - } - - if (b == CloudSupportStatus.Unknown || b == CloudSupportStatus.GlobalOnly) - { - return a; - } - - return CloudSupportStatus.AllClouds; - } - /// /// Loads the Markdown files in the root directory into the . /// diff --git a/src/Extensions/OpenApiUrlTreeNodeExtensions.cs b/src/Extensions/OpenApiUrlTreeNodeExtensions.cs index b7b4065..af17804 100644 --- a/src/Extensions/OpenApiUrlTreeNodeExtensions.cs +++ b/src/Extensions/OpenApiUrlTreeNodeExtensions.cs @@ -118,33 +118,57 @@ public static CloudSupportStatus GetCloudSupportStatus( method = HttpMethod.Get; } - var supportsGlobal = node.PathItems.ContainsKey("Global") && - (node.PathItems["Global"].Operations?.ContainsKey(method) ?? false); - var supportsUsGov = node.PathItems.ContainsKey("UsGov") && - (node.PathItems["UsGov"].Operations?.ContainsKey(method) ?? false) && - !OpenAPIOverrides.CheckIfCloudExcluded(node.Path, method, "UsGov") && - !OpenAPIOverrides.CheckIfCloudExcludedForFile(fileName, "UsGov"); - var supportsChina = node.PathItems.ContainsKey("China") && - (node.PathItems["China"].Operations?.ContainsKey(method) ?? false) && + var supportStatus = node.PathItems.TryGetValue("Global", out IOpenApiPathItem? globalValue) && + (globalValue.Operations?.ContainsKey(method) ?? false) + ? CloudSupportStatus.Global + : CloudSupportStatus.Unknown; + if (supportStatus == CloudSupportStatus.Unknown) + { + return supportStatus; + } + + if (node.PathItems.TryGetValue("UsGov", out IOpenApiPathItem? usGovValue) && + (usGovValue.Operations?.ContainsKey(method) ?? false)) + { + supportStatus |= GetUsGovCloudSupportStatus(node.Path, method, fileName); + } + + if (node.PathItems.TryGetValue("China", out IOpenApiPathItem? chinaValue) && + (chinaValue.Operations?.ContainsKey(method) ?? false) && !OpenAPIOverrides.CheckIfCloudExcluded(node.Path, method, "China") && - !OpenAPIOverrides.CheckIfCloudExcludedForFile(fileName, "China"); + !OpenAPIOverrides.CheckIfCloudExcludedForFile(fileName, "China")) + { + supportStatus |= CloudSupportStatus.China; + } + + return supportStatus; + } + + private static CloudSupportStatus GetUsGovCloudSupportStatus( + string apiPath, + HttpMethod? method, + string fileName) + { + var supportStatus = CloudSupportStatus.USGov; - if (!supportsGlobal) + if (OpenAPIOverrides.CheckIfCloudExcluded(apiPath, method, "UsGov") || + OpenAPIOverrides.CheckIfCloudExcludedForFile(fileName, "UsGov")) { - // Only process APIs that exist in Global cloud return CloudSupportStatus.Unknown; } - if (supportsUsGov && supportsChina) + if (OpenAPIOverrides.CheckIfCloudExcluded(apiPath, method, "UsGovL4") || + OpenAPIOverrides.CheckIfCloudExcludedForFile(fileName, "UsGovL4")) { - return CloudSupportStatus.AllClouds; + supportStatus &= ~CloudSupportStatus.USGovL4; } - if (!supportsUsGov && !supportsChina) + if (OpenAPIOverrides.CheckIfCloudExcluded(apiPath, method, "UsGovL5") || + OpenAPIOverrides.CheckIfCloudExcludedForFile(fileName, "UsGovL5")) { - return CloudSupportStatus.GlobalOnly; + supportStatus &= ~CloudSupportStatus.USGovL5; } - return supportsUsGov ? CloudSupportStatus.GlobalAndUSGov : CloudSupportStatus.GlobalAndChina; + return supportStatus; } } diff --git a/src/Extensions/StringExtensions.cs b/src/Extensions/StringExtensions.cs index 7e8ab7d..acd3db1 100644 --- a/src/Extensions/StringExtensions.cs +++ b/src/Extensions/StringExtensions.cs @@ -37,7 +37,7 @@ public static string NormalizeIdSegments(this string path) normalizedPath = normalizedPath.Replace("/{name}", "/{id}"); // Replace any segments wrapped in braces that contain "id" - normalizedPath = IdSegmentRegex().Replace(normalizedPath, "{id}"); + normalizedPath = IdSegmentRegex().Replace(normalizedPath, "/{id}"); return normalizedPath; } @@ -211,13 +211,13 @@ public static bool IsEqualIgnoringCase(this string value, string compareTo) return compareValue == 0; } - [GeneratedRegex("{[^{}]*id[^{}]*}", RegexOptions.IgnoreCase)] + [GeneratedRegex("\\/{[^{}]*id[^{}]*}", RegexOptions.IgnoreCase)] private static partial Regex IdSegmentRegex(); - [GeneratedRegex("\\(((?>\\w*='?\\{?[\\w-]*\\}?'?,?)+)\\)")] + [GeneratedRegex("\\(((?>\\w*='?\\{?[\\w@-]*\\}?'?,?)+)\\)")] private static partial Regex ParameterListRegex(); - [GeneratedRegex("(?\\w*)='?(?\\{?[\\w-]*\\}?)'?")] + [GeneratedRegex("(?\\w*)='?(?\\{?[\\w@-]*\\}?)'?")] private static partial Regex ParameterValuePairRegex(); [GeneratedRegex("^\\/users\\/{id}\\/drive\\/")] diff --git a/src/Program.cs b/src/Program.cs index 5c7501d..b4c8419 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -160,7 +160,7 @@ supportStatus, apiDoc.CloudSupportStatus); - apiDoc.CloudSupportStatus = DocSet.CombineStatuses(apiDoc.CloudSupportStatus, supportStatus); + apiDoc.CloudSupportStatus |= supportStatus; } else { @@ -340,7 +340,7 @@ supportStatus, v1CloudSupportStatus); - v1CloudSupportStatus = DocSet.CombineStatuses(v1CloudSupportStatus, supportStatus); + v1CloudSupportStatus |= supportStatus; } else { @@ -377,7 +377,7 @@ supportStatus, betaCloudSupportStatus); - betaCloudSupportStatus = DocSet.CombineStatuses(betaCloudSupportStatus, supportStatus); + betaCloudSupportStatus |= supportStatus; } else { diff --git a/test/DocSetTests.cs b/test/DocSetTests.cs deleted file mode 100644 index c43c953..0000000 --- a/test/DocSetTests.cs +++ /dev/null @@ -1,47 +0,0 @@ -using CheckCloudSupport.Docs; - -namespace CheckCloudSupportTests; - -public class DocSetTests -{ - public static TheoryData CombineTestData => new() - { - {CloudSupportStatus.Unknown, CloudSupportStatus.Unknown, CloudSupportStatus.Unknown}, - {CloudSupportStatus.Unknown, CloudSupportStatus.GlobalOnly, CloudSupportStatus.GlobalOnly}, - {CloudSupportStatus.Unknown, CloudSupportStatus.AllClouds, CloudSupportStatus.AllClouds}, - {CloudSupportStatus.Unknown, CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.GlobalAndUSGov}, - {CloudSupportStatus.Unknown, CloudSupportStatus.GlobalAndChina, CloudSupportStatus.GlobalAndChina}, - - {CloudSupportStatus.GlobalOnly, CloudSupportStatus.Unknown, CloudSupportStatus.GlobalOnly}, - {CloudSupportStatus.GlobalOnly, CloudSupportStatus.GlobalOnly, CloudSupportStatus.GlobalOnly}, - {CloudSupportStatus.GlobalOnly, CloudSupportStatus.AllClouds, CloudSupportStatus.AllClouds}, - {CloudSupportStatus.GlobalOnly, CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.GlobalAndUSGov}, - {CloudSupportStatus.GlobalOnly, CloudSupportStatus.GlobalAndChina, CloudSupportStatus.GlobalAndChina}, - - {CloudSupportStatus.AllClouds, CloudSupportStatus.Unknown, CloudSupportStatus.AllClouds}, - {CloudSupportStatus.AllClouds, CloudSupportStatus.GlobalOnly, CloudSupportStatus.AllClouds}, - {CloudSupportStatus.AllClouds, CloudSupportStatus.AllClouds, CloudSupportStatus.AllClouds}, - {CloudSupportStatus.AllClouds, CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.AllClouds}, - {CloudSupportStatus.AllClouds, CloudSupportStatus.GlobalAndChina, CloudSupportStatus.AllClouds}, - - {CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.Unknown, CloudSupportStatus.GlobalAndUSGov}, - {CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.GlobalOnly, CloudSupportStatus.GlobalAndUSGov}, - {CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.AllClouds, CloudSupportStatus.AllClouds}, - {CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.GlobalAndUSGov}, - {CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.GlobalAndChina, CloudSupportStatus.AllClouds}, - - {CloudSupportStatus.GlobalAndChina, CloudSupportStatus.Unknown, CloudSupportStatus.GlobalAndChina}, - {CloudSupportStatus.GlobalAndChina, CloudSupportStatus.GlobalOnly, CloudSupportStatus.GlobalAndChina}, - {CloudSupportStatus.GlobalAndChina, CloudSupportStatus.AllClouds, CloudSupportStatus.AllClouds}, - {CloudSupportStatus.GlobalAndChina, CloudSupportStatus.GlobalAndUSGov, CloudSupportStatus.AllClouds}, - {CloudSupportStatus.GlobalAndChina, CloudSupportStatus.GlobalAndChina, CloudSupportStatus.GlobalAndChina}, - - }; - - [Theory] - [MemberData(nameof(CombineTestData))] - public void CloudStatusesCombineCorrectly(CloudSupportStatus a, CloudSupportStatus b, CloudSupportStatus combined) - { - Assert.Equal(combined, DocSet.CombineStatuses(a, b)); - } -}