diff --git a/tools/code/publisher/Api.cs b/tools/code/publisher/Api.cs index ae94500..8fba0df 100644 --- a/tools/code/publisher/Api.cs +++ b/tools/code/publisher/Api.cs @@ -17,7 +17,7 @@ namespace publisher; internal static class Api { - public static async ValueTask ProcessDeletedArtifacts(IReadOnlyCollection files, JsonObject configurationJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, PutRestResource putRestResource, DeleteRestResource deleteRestResource, ILogger logger, CancellationToken cancellationToken) + public static async ValueTask ProcessDeletedArtifacts(IReadOnlyCollection files, JsonObject configurationJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, GetRestResource getRestResource, PutRestResource putRestResource, DeleteRestResource deleteRestResource, ILogger logger, CancellationToken cancellationToken) { var configurationApis = GetConfigurationApis(configurationJson); @@ -27,7 +27,7 @@ internal static class Api secondKeySelector: configurationArtifact => configurationArtifact.ApiName, firstSelector: api => (api.ApiName, api.InformationFile, api.SpecificationFile, ConfigurationApiJson: (JsonObject?)null), bothSelector: (file, configurationArtifact) => (file.ApiName, file.InformationFile, file.SpecificationFile, ConfigurationApiJson: configurationArtifact.Json)) - .ForEachParallel(async artifact => await ProcessDeletedApi(artifact.ApiName, artifact.InformationFile, artifact.SpecificationFile, artifact.ConfigurationApiJson, serviceDirectory, serviceUri, putRestResource, deleteRestResource, logger, cancellationToken), + .ForEachParallel(async artifact => await ProcessDeletedApi(artifact.ApiName, artifact.InformationFile, artifact.SpecificationFile, artifact.ConfigurationApiJson, serviceDirectory, serviceUri, getRestResource, putRestResource, deleteRestResource, logger, cancellationToken), cancellationToken); } @@ -192,7 +192,7 @@ internal static class Api return new(specificationFile.ApiDirectory.GetName()); } - private static async ValueTask ProcessDeletedApi(ApiName apiName, ApiInformationFile? deletedApiInformationFile, ApiSpecificationFile? deletedSpecificationFile, JsonObject? configurationApiJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, PutRestResource putRestResource, DeleteRestResource deleteRestResource, ILogger logger, CancellationToken cancellationToken) + private static async ValueTask ProcessDeletedApi(ApiName apiName, ApiInformationFile? deletedApiInformationFile, ApiSpecificationFile? deletedSpecificationFile, JsonObject? configurationApiJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, GetRestResource getRestResource, PutRestResource putRestResource, DeleteRestResource deleteRestResource, ILogger logger, CancellationToken cancellationToken) { switch (deletedApiInformationFile, deletedSpecificationFile) { @@ -208,7 +208,7 @@ internal static class Api } else { - await PutApi(apiName, existingInformationFile, specificationFile: null, configurationApiJson, serviceUri, putRestResource, logger, cancellationToken); + await PutApi(apiName, existingInformationFile, specificationFile: null, configurationApiJson, serviceUri, getRestResource, putRestResource, logger, cancellationToken); } return; @@ -221,7 +221,7 @@ internal static class Api } else { - await PutApi(apiName, apiInformationFile: null, existingSpecificationFile, configurationApiJson, serviceUri, putRestResource, logger, cancellationToken); + await PutApi(apiName, apiInformationFile: null, existingSpecificationFile, configurationApiJson, serviceUri, getRestResource, putRestResource, logger, cancellationToken); } return; @@ -260,7 +260,7 @@ internal static class Api .FirstOrDefault() : null; } - private static async ValueTask PutApi(ApiName apiName, ApiInformationFile? apiInformationFile, ApiSpecificationFile? specificationFile, JsonObject? configurationApiJson, ServiceUri serviceUri, PutRestResource putRestResource, ILogger logger, CancellationToken cancellationToken) + private static async ValueTask PutApi(ApiName apiName, ApiInformationFile? apiInformationFile, ApiSpecificationFile? specificationFile, JsonObject? configurationApiJson, ServiceUri serviceUri, GetRestResource getRestResource, PutRestResource putRestResource, ILogger logger, CancellationToken cancellationToken) { if (apiInformationFile is null && specificationFile is null && configurationApiJson is null) { @@ -278,7 +278,7 @@ internal static class Api putUri = putUri.SetQueryParam("import", "true").ToUri(); } - var apiJson = await GetApiJson(apiName, apiInformationFile, specificationFile, configurationApiJson, cancellationToken); + var apiJson = await GetApiJson(apiName, apiInformationFile, specificationFile, configurationApiJson, serviceUri, getRestResource, cancellationToken); await putRestResource(putUri, apiJson, cancellationToken); // Handle GraphQL specification @@ -288,7 +288,7 @@ internal static class Api } } - private static async ValueTask GetApiJson(ApiName apiName, ApiInformationFile? apiInformationFile, ApiSpecificationFile? specificationFile, JsonObject? configurationApiJson, CancellationToken cancellationToken) + private static async ValueTask GetApiJson(ApiName apiName, ApiInformationFile? apiInformationFile, ApiSpecificationFile? specificationFile, JsonObject? configurationApiJson, ServiceUri serviceUri, GetRestResource getRestResource, CancellationToken cancellationToken) { var apiJson = new JsonObject(); @@ -301,6 +301,13 @@ internal static class Api if (specificationFile is not null and (ApiSpecificationFile.Wadl or ApiSpecificationFile.Wsdl or ApiSpecificationFile.OpenApi)) { var specificationJson = await GetApiSpecificationJson(specificationFile, cancellationToken); + //If there is not apiInformationFile, retrieve the serviceUrl from the API's service. + if (apiInformationFile is null) + { + // Temporary work around to address the fact the management API will update the serviceURL to the management API's URL. + var propertyName = "serviceUrl"; + apiJson = await GetPropertiesPropertyFronJson(apiName, propertyName, serviceUri, getRestResource, cancellationToken); + } apiJson = apiJson.Merge(specificationJson); } @@ -317,6 +324,52 @@ internal static class Api return apiJson; } + /// + /// This method will call the REST endpoint for the passed in API Name. It then will take that response, parse the properties object + /// and return the propertyName property. + /// + /// Name of the api + /// Name of the property you want to get the value of from the properties object + /// URI of the endpoint you need to get the json from + /// Delegate to call the REST endpoint based on the apiName + /// Cancellation Token + /// + static async Task GetPropertiesPropertyFronJson(ApiName apiName, String propertyName, ServiceUri serviceUri, GetRestResource getRestResource, CancellationToken cancellationToken) + { + // If the API does not have an information file, retrieve the serviceUrl from the API's service. + var apiUri = GetApiUri(apiName, serviceUri); + var tagJsonObject = await getRestResource(apiUri.Uri, cancellationToken); + var propertiesNode = tagJsonObject.GetNullableProperty("properties"); + + if (propertiesNode != null && propertiesNode is JsonObject propertiesObject) + { + var apiServiceUrlNode = propertiesObject.GetNullableProperty(propertyName); + + if (apiServiceUrlNode != null && apiServiceUrlNode is JsonValue apiServiceUrlValue) + { + var apiServiceUrl = apiServiceUrlValue.ToString(); + + JsonObject apiJson = new JsonObject + { + ["properties"] = new JsonObject + { + ["serviceUrl"] = apiServiceUrl + } + }; + + return apiJson; + } + else + { + throw new InvalidOperationException($"Could not find property '{propertyName}' in the properties object of the JSON object."); + } + } + else + { + throw new InvalidOperationException($"Could not find the properties object in JSON object."); + } + } + private static async ValueTask GetApiSpecificationJson(ApiSpecificationFile specificationFile, CancellationToken cancellationToken) { var json = new JsonObject @@ -374,7 +427,7 @@ internal static class Api await putRestResource(schemaUri.Uri, json, cancellationToken); } - public static async ValueTask ProcessArtifactsToPut(IReadOnlyCollection files, JsonObject configurationJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, PutRestResource putRestResource, ILogger logger, CancellationToken cancellationToken) + public static async ValueTask ProcessArtifactsToPut(IReadOnlyCollection files, JsonObject configurationJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, GetRestResource getRestResource, PutRestResource putRestResource, ILogger logger, CancellationToken cancellationToken) { var configurationApis = GetConfigurationApis(configurationJson); @@ -384,7 +437,7 @@ internal static class Api secondKeySelector: configurationArtifact => configurationArtifact.ApiName, firstSelector: api => (api.ApiName, api.InformationFile, api.SpecificationFile, ConfigurationApiJson: (JsonObject?)null), bothSelector: (fileApi, configurationArtifact) => (fileApi.ApiName, fileApi.InformationFile, fileApi.SpecificationFile, ConfigurationApiJson: configurationArtifact.Json)) - .ForEachParallel(async api => await PutApi(api.ApiName, api.InformationFile, api.SpecificationFile, api.ConfigurationApiJson, serviceUri, putRestResource, logger, cancellationToken), + .ForEachParallel(async api => await PutApi(api.ApiName, api.InformationFile, api.SpecificationFile, api.ConfigurationApiJson, serviceUri, getRestResource, putRestResource, logger, cancellationToken), cancellationToken); } } \ No newline at end of file diff --git a/tools/code/publisher/Common.cs b/tools/code/publisher/Common.cs index f97fb5e..347a23d 100644 --- a/tools/code/publisher/Common.cs +++ b/tools/code/publisher/Common.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; namespace publisher; internal delegate IAsyncEnumerable ListRestResources(Uri uri, CancellationToken cancellationToken); +internal delegate ValueTask GetRestResource(Uri uri, CancellationToken cancellationToken); internal delegate ValueTask PutRestResource(Uri uri, JsonObject jsonObject, CancellationToken cancellationToken); diff --git a/tools/code/publisher/Program.cs b/tools/code/publisher/Program.cs index b15f0d1..8988f02 100644 --- a/tools/code/publisher/Program.cs +++ b/tools/code/publisher/Program.cs @@ -51,6 +51,7 @@ public static class Program .AddSingleton(GetHttpPipeline) .AddSingleton(GetDeleteRestResource) .AddSingleton(GetListRestResources) + .AddSingleton(GetGetRestResource) .AddSingleton(GetPutRestResource) .AddSingleton(GetPublisherParameters) .AddHostedService(); @@ -149,6 +150,30 @@ public static class Program }; } + private static GetRestResource GetGetRestResource(IServiceProvider provider) + { + var pipeline = provider.GetRequiredService(); + var logger = provider.GetRequiredService().CreateLogger(nameof(GetRestResource)); + + return async (uri, cancellationToken) => + { + logger.LogDebug("Beginning request to get REST resource at URI {uri}...", uri); + + var json = await pipeline.GetJsonObject(uri, cancellationToken); + + if (logger.IsEnabled(LogLevel.Trace)) + { + logger.LogTrace("Successfully retrieved REST resource {json} at URI {uri}.", json.ToJsonString(), uri); + } + else + { + logger.LogDebug("Successfully retrieved REST resource at URI {uri}.", uri); + } + + return json; + }; + } + private static PutRestResource GetPutRestResource(IServiceProvider provider) { var pipeline = provider.GetRequiredService(); @@ -184,6 +209,7 @@ public static class Program ConfigurationJson = GetConfigurationJson(configuration), DeleteRestResource = provider.GetRequiredService(), ListRestResources = provider.GetRequiredService(), + GetRestResource = provider.GetRequiredService(), Logger = provider.GetRequiredService().CreateLogger(nameof(Publisher)), PutRestResource = provider.GetRequiredService(), ServiceDirectory = GetServiceDirectory(configuration), diff --git a/tools/code/publisher/Publisher.cs b/tools/code/publisher/Publisher.cs index c1e9bd4..00341fa 100644 --- a/tools/code/publisher/Publisher.cs +++ b/tools/code/publisher/Publisher.cs @@ -24,6 +24,7 @@ internal class Publisher : BackgroundService public required DeleteRestResource DeleteRestResource { get; init; } public required ILogger Logger { get; init; } public required ListRestResources ListRestResources { get; init; } + public required GetRestResource GetRestResource { get; init; } public required PutRestResource PutRestResource { get; init; } public required ServiceDirectory ServiceDirectory { get; init; } public required ServiceUri ServiceUri { get; init; } @@ -86,6 +87,7 @@ internal class Publisher : BackgroundService publisherParameters.ServiceDirectory, publisherParameters.ServiceUri, publisherParameters.ListRestResources, + publisherParameters.GetRestResource, publisherParameters.PutRestResource, publisherParameters.DeleteRestResource, logger, @@ -141,6 +143,7 @@ internal class Publisher : BackgroundService publisherParameters.ServiceDirectory, publisherParameters.ServiceUri, publisherParameters.ListRestResources, + publisherParameters.GetRestResource, publisherParameters.PutRestResource, publisherParameters.DeleteRestResource, publisherParameters.Logger, @@ -154,6 +157,7 @@ internal class Publisher : BackgroundService publisherParameters.ServiceDirectory, publisherParameters.ServiceUri, publisherParameters.ListRestResources, + publisherParameters.GetRestResource, publisherParameters.PutRestResource, publisherParameters.DeleteRestResource, publisherParameters.Logger, diff --git a/tools/code/publisher/Service.cs b/tools/code/publisher/Service.cs index 47c8c64..8057917 100644 --- a/tools/code/publisher/Service.cs +++ b/tools/code/publisher/Service.cs @@ -10,7 +10,7 @@ namespace publisher; internal static class Service { - public static async ValueTask ProcessDeletedArtifacts(IReadOnlyCollection files, JsonObject configurationJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, ListRestResources listRestResources, PutRestResource putRestResource, DeleteRestResource deleteRestResource, ILogger logger, CancellationToken cancellationToken) + public static async ValueTask ProcessDeletedArtifacts(IReadOnlyCollection files, JsonObject configurationJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, ListRestResources listRestResources, GetRestResource getRestResource, PutRestResource putRestResource, DeleteRestResource deleteRestResource, ILogger logger, CancellationToken cancellationToken) { await GatewayApi.ProcessDeletedArtifacts(files, configurationJson, serviceDirectory, serviceUri, listRestResources, putRestResource, deleteRestResource, logger, cancellationToken); await ProductApi.ProcessDeletedArtifacts(files, configurationJson, serviceDirectory, serviceUri, listRestResources, putRestResource, deleteRestResource, logger, cancellationToken); @@ -18,7 +18,7 @@ internal static class Service await ApiTag.ProcessDeletedArtifacts(files, configurationJson, serviceDirectory, serviceUri, listRestResources, putRestResource, deleteRestResource, logger, cancellationToken); await ApiDiagnostic.ProcessDeletedArtifacts(files, serviceDirectory, serviceUri, deleteRestResource, logger, cancellationToken); await ApiPolicy.ProcessDeletedArtifacts(files, serviceDirectory, serviceUri, deleteRestResource, logger, cancellationToken); - await Api.ProcessDeletedArtifacts(files, configurationJson, serviceDirectory, serviceUri, putRestResource, deleteRestResource, logger, cancellationToken); + await Api.ProcessDeletedArtifacts(files, configurationJson, serviceDirectory, serviceUri, getRestResource, putRestResource, deleteRestResource, logger, cancellationToken); await Subscription.ProcessDeletedArtifacts(files, serviceDirectory, serviceUri, deleteRestResource, logger, cancellationToken); await ProductTag.ProcessDeletedArtifacts(files, configurationJson, serviceDirectory, serviceUri, listRestResources, putRestResource, deleteRestResource, logger, cancellationToken); await ProductGroup.ProcessDeletedArtifacts(files, configurationJson, serviceDirectory, serviceUri, listRestResources, putRestResource, deleteRestResource, logger, cancellationToken); @@ -35,7 +35,7 @@ internal static class Service await NamedValue.ProcessDeletedArtifacts(files, serviceDirectory, serviceUri, deleteRestResource, logger, cancellationToken); } - public static async ValueTask ProcessArtifactsToPut(IReadOnlyCollection files, JsonObject configurationJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, ListRestResources listRestResources, PutRestResource putRestResource, DeleteRestResource deleteRestResource, ILogger logger, CancellationToken cancellationToken) + public static async ValueTask ProcessArtifactsToPut(IReadOnlyCollection files, JsonObject configurationJson, ServiceDirectory serviceDirectory, ServiceUri serviceUri, ListRestResources listRestResources, GetRestResource getRestResource, PutRestResource putRestResource, DeleteRestResource deleteRestResource, ILogger logger, CancellationToken cancellationToken) { await NamedValue.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, putRestResource, logger, cancellationToken); await Tag.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, putRestResource, logger, cancellationToken); @@ -50,7 +50,7 @@ internal static class Service await ProductPolicy.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, putRestResource, logger, cancellationToken); await ProductGroup.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, listRestResources, putRestResource, deleteRestResource, logger, cancellationToken); await ProductTag.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, listRestResources, putRestResource, deleteRestResource, logger, cancellationToken); - await Api.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, putRestResource, logger, cancellationToken); + await Api.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, getRestResource, putRestResource, logger, cancellationToken); await ApiPolicy.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, putRestResource, logger, cancellationToken); await ApiDiagnostic.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, putRestResource, logger, cancellationToken); await ApiTag.ProcessArtifactsToPut(files, configurationJson, serviceDirectory, serviceUri, listRestResources, putRestResource, deleteRestResource, logger, cancellationToken);