From 067cda668ff182a66995c6dea7a540984eb8ef34 Mon Sep 17 00:00:00 2001 From: Charles d'Avernas Date: Wed, 22 Jan 2025 10:47:42 +0100 Subject: [PATCH 1/2] feat(Solution): Update solution to .NET 9 feat(Gateway): Add a new `DatabaseProvisioner` service, used to seed the database using supplied files Closes #75 Signed-off-by: Charles d'Avernas --- .github/ISSUE_TEMPLATE/bug.yml | 82 +++++++ .github/ISSUE_TEMPLATE/bug_report.md | 38 --- .github/ISSUE_TEMPLATE/config.yml | 2 + .github/ISSUE_TEMPLATE/feature.yml | 47 ++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 -- CloudStreams.sln | 12 +- deployments/docker-compose/docker-compose.yml | 19 +- .../CloudStreams.Broker.Api.csproj | 12 +- src/broker/CloudStreams.Broker.Api/Dockerfile | 4 +- .../CloudStreams.Broker.Application.csproj | 10 +- .../CloudStreams.Core.Api.Client.csproj | 4 +- .../CloudStreams.Core.Api.csproj | 30 +-- src/core/CloudStreams.Core.Api/Dockerfile | 4 +- .../CloudStreams.Core.Application.csproj | 8 +- .../CloudStreams.Core.csproj | 8 +- ...udStreams.Dashboard.StateManagement.csproj | 8 +- .../CloudStreams.Dashboard.csproj | 14 +- .../CloudStreams.Gateway.Api.csproj | 10 +- .../CloudStreams.Gateway.Api/Dockerfile | 4 +- .../CloudStreams.Gateway.Api/Program.cs | 1 + .../CloudStreams.Gateway.Application.csproj | 6 +- .../Services/DatabaseProvisioner.cs | 222 ++++++++++++++++++ 22 files changed, 436 insertions(+), 129 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 src/gateway/CloudStreams.Gateway.Application/Services/DatabaseProvisioner.cs diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 00000000..65c9d67f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,82 @@ +name: Bug Report +description: Create a bug report +labels: ["bug"] +body: +- type: markdown + attributes: + value: | + :pray: Thanks for taking the time to fill out this bug report! + +- type: markdown + attributes: + value: | + ## Bug Report + +- type: textarea + id: i-tried-this + attributes: + label: "I tried this:" + placeholder: "What did you try to do? A code snippet or example helps." + validations: + required: true + +- type: textarea + id: instead-what-happened + attributes: + label: "This happened:" + placeholder: "What happened instead of what you've expected?" + validations: + required: true + +- type: textarea + id: what-did-you-expect + attributes: + label: "I expected this:" + placeholder: "What did you expect to happen? Describe the output or behavior you expected to see (unless it's obvious)." + +- type: textarea + id: workaround + attributes: + label: "Is there a workaround?" + placeholder: "What's the workaround to avoid this issue?" + +- type: textarea + attributes: + label: Anything else? + placeholder: | + Links? References? Logs? Anything that will give us more context about the issue you are encountering. + Tip: You can attach images or log files by dragging files in. + +- type: markdown + attributes: + value: | + ## Environment + +- type: dropdown + id: component + attributes: + label: "Component(s)" + multiple: true + options: + - Api + - Broker + - Gateway + +- type: dropdown + id: platform + attributes: + label: "Platform(s)" + multiple: true + options: + - MacOS + - Linux + - Windows + - Other + +- type: textarea + attributes: + label: Community Notes + value: | + + * Please vote by adding a 👍 reaction to the issue to help us prioritize. + * If you are interested to work on this issue, please leave a comment.name: Bug Report 🐞 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index dd84ea78..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..8005e322 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,2 @@ +blank_issues_enabled: false +contact_links: [] diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 00000000..d505615c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,47 @@ +name: Feature Request +description: Create a feature request +labels: ["enhancement"] +body: +- type: markdown + attributes: + value: | + :pray: Thanks for taking the time to fill out this feature request! + +- type: markdown + attributes: + value: | + ## Feature Request + +- type: textarea + id: what-would-you-like-to-be-added + attributes: + label: "What would you like to be added?" + placeholder: "Description of the feature you'd like to see." + validations: + required: true + +- type: textarea + id: proposals + attributes: + label: "Proposal(s):" + placeholder: "Describe your proposal(s) and any relevant details here." + +- type: textarea + id: alternatives + attributes: + label: "Alternative(s):" + placeholder: "Describe any alternative approaches, options, or suggestions you’d like to consider." + +- type: textarea + id: additional-info + attributes: + label: "Additional info:" + placeholder: "Provide any supplementary details, context, or supporting information here." + +- type: textarea + attributes: + label: Community Notes + value: | + + * Please vote by adding a 👍 reaction to the feature to help us prioritize. + * If you are interested to work on this feature, please leave a comment. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7d..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/CloudStreams.sln b/CloudStreams.sln index 37660a7a..b3ffca96 100644 --- a/CloudStreams.sln +++ b/CloudStreams.sln @@ -35,8 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudStreams.Dashboard.Stat EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{129B2507-0C27-4324-AFC9-2C802E25E51D}" ProjectSection(SolutionItems) = preProject - LICENSE = LICENSE code-of-conduct.md = code-of-conduct.md + LICENSE = LICENSE README.md = README.md EndProjectSection EndProject @@ -44,6 +44,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deployments", "deployments" EndProject Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "deployments\docker-compose\docker-compose.dcproj", "{0050C106-97E3-40BD-8C2C-34503B5757DF}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{9EDAC21F-3617-413B-8C54-469851036E9B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issue_template", "issue_template", "{63F334BA-8ECE-42CC-8948-A15E9CCFF4CE}" + ProjectSection(SolutionItems) = preProject + .github\ISSUE_TEMPLATE\bug.yml = .github\ISSUE_TEMPLATE\bug.yml + .github\ISSUE_TEMPLATE\config.yml = .github\ISSUE_TEMPLATE\config.yml + .github\ISSUE_TEMPLATE\feature.yml = .github\ISSUE_TEMPLATE\feature.yml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -114,6 +123,7 @@ Global {DEF277AF-8024-49D8-BD80-338A79431F8C} = {BDA26004-D077-442C-A4F7-F389D5AC9FE5} {7BD5FCBA-1D5A-4DF2-BDC3-5672D3507C06} = {BDA26004-D077-442C-A4F7-F389D5AC9FE5} {0050C106-97E3-40BD-8C2C-34503B5757DF} = {990DE5C0-9BDB-417C-91D9-B3883C5FCA3E} + {63F334BA-8ECE-42CC-8948-A15E9CCFF4CE} = {9EDAC21F-3617-413B-8C54-469851036E9B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5E10D9D7-D5B5-4C0B-B7AC-AC10FF33DA3F} diff --git a/deployments/docker-compose/docker-compose.yml b/deployments/docker-compose/docker-compose.yml index 16dfd866..5dde1977 100644 --- a/deployments/docker-compose/docker-compose.yml +++ b/deployments/docker-compose/docker-compose.yml @@ -18,11 +18,11 @@ services: image: redis:latest gateway: - image: cloud-streams/gateway - # image: ${DOCKER_REGISTRY-}gateway - # build: - # context: ../../ - # dockerfile: ./src/gateway/CloudStreams.Gateway.Api/Dockerfile + # image: cloud-streams/gateway + image: ${DOCKER_REGISTRY-}gateway + build: + context: ../../ + dockerfile: ./src/gateway/CloudStreams.Gateway.Api/Dockerfile environment: ASPNETCORE_ENVIRONMENT: Development ASPNETCORE_HTTP_PORTS: 80 @@ -36,10 +36,11 @@ services: - eventstore broker: - image: ${DOCKER_REGISTRY-}broker - build: - context: ../../ - dockerfile: ./src/broker/CloudStreams.Broker.Api/Dockerfile + image: cloud-streams/broker + # image: ${DOCKER_REGISTRY-}broker + # build: + # context: ../../ + # dockerfile: ./src/broker/CloudStreams.Broker.Api/Dockerfile environment: ASPNETCORE_ENVIRONMENT: Development ASPNETCORE_HTTP_PORTS: 80 diff --git a/src/broker/CloudStreams.Broker.Api/CloudStreams.Broker.Api.csproj b/src/broker/CloudStreams.Broker.Api/CloudStreams.Broker.Api.csproj index 2f0ca0a7..3d2e7647 100644 --- a/src/broker/CloudStreams.Broker.Api/CloudStreams.Broker.Api.csproj +++ b/src/broker/CloudStreams.Broker.Api/CloudStreams.Broker.Api.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -25,12 +25,12 @@ - + - - - - + + + + diff --git a/src/broker/CloudStreams.Broker.Api/Dockerfile b/src/broker/CloudStreams.Broker.Api/Dockerfile index ea8f105f..5e3e3f83 100644 --- a/src/broker/CloudStreams.Broker.Api/Dockerfile +++ b/src/broker/CloudStreams.Broker.Api/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base USER root RUN apt-get update RUN apt-get install -y jq @@ -6,7 +6,7 @@ USER app WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["src/broker/CloudStreams.Broker.Api/CloudStreams.Broker.Api.csproj", "src/broker/CloudStreams.Broker.Api/"] diff --git a/src/broker/CloudStreams.Broker.Application/CloudStreams.Broker.Application.csproj b/src/broker/CloudStreams.Broker.Application/CloudStreams.Broker.Application.csproj index 81854147..6beffb6f 100644 --- a/src/broker/CloudStreams.Broker.Application/CloudStreams.Broker.Application.csproj +++ b/src/broker/CloudStreams.Broker.Application/CloudStreams.Broker.Application.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -19,10 +19,10 @@ - - - - + + + + diff --git a/src/core/CloudStreams.Core.Api.Client/CloudStreams.Core.Api.Client.csproj b/src/core/CloudStreams.Core.Api.Client/CloudStreams.Core.Api.Client.csproj index 5e881f54..ef4ed4fb 100644 --- a/src/core/CloudStreams.Core.Api.Client/CloudStreams.Core.Api.Client.csproj +++ b/src/core/CloudStreams.Core.Api.Client/CloudStreams.Core.Api.Client.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -19,7 +19,7 @@ - + diff --git a/src/core/CloudStreams.Core.Api/CloudStreams.Core.Api.csproj b/src/core/CloudStreams.Core.Api/CloudStreams.Core.Api.csproj index fcb3d2c9..009c7f05 100644 --- a/src/core/CloudStreams.Core.Api/CloudStreams.Core.Api.csproj +++ b/src/core/CloudStreams.Core.Api/CloudStreams.Core.Api.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -24,21 +24,21 @@ - - - + + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/src/core/CloudStreams.Core.Api/Dockerfile b/src/core/CloudStreams.Core.Api/Dockerfile index 589c8583..2b37d013 100644 --- a/src/core/CloudStreams.Core.Api/Dockerfile +++ b/src/core/CloudStreams.Core.Api/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base USER app WORKDIR /app EXPOSE 80 @@ -6,7 +6,7 @@ USER root RUN apt-get update RUN apt-get install -y jq -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["src/core/CloudStreams.Core.Api/CloudStreams.Core.Api.csproj", "src/core/CloudStreams.Core.Api/"] diff --git a/src/core/CloudStreams.Core.Application/CloudStreams.Core.Application.csproj b/src/core/CloudStreams.Core.Application/CloudStreams.Core.Application.csproj index e3321594..812c7644 100644 --- a/src/core/CloudStreams.Core.Application/CloudStreams.Core.Application.csproj +++ b/src/core/CloudStreams.Core.Application/CloudStreams.Core.Application.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -19,9 +19,9 @@ - - - + + + diff --git a/src/core/CloudStreams.Core/CloudStreams.Core.csproj b/src/core/CloudStreams.Core/CloudStreams.Core.csproj index 63a42b5a..329096f6 100644 --- a/src/core/CloudStreams.Core/CloudStreams.Core.csproj +++ b/src/core/CloudStreams.Core/CloudStreams.Core.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -31,9 +31,9 @@ - - - + + + diff --git a/src/dashboard/CloudStreams.Dashboard.StateManagement/CloudStreams.Dashboard.StateManagement.csproj b/src/dashboard/CloudStreams.Dashboard.StateManagement/CloudStreams.Dashboard.StateManagement.csproj index 7cf9e808..e7839ca4 100644 --- a/src/dashboard/CloudStreams.Dashboard.StateManagement/CloudStreams.Dashboard.StateManagement.csproj +++ b/src/dashboard/CloudStreams.Dashboard.StateManagement/CloudStreams.Dashboard.StateManagement.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -19,9 +19,9 @@ - - - + + + diff --git a/src/dashboard/CloudStreams.Dashboard/CloudStreams.Dashboard.csproj b/src/dashboard/CloudStreams.Dashboard/CloudStreams.Dashboard.csproj index 75f5e519..ff68aa45 100644 --- a/src/dashboard/CloudStreams.Dashboard/CloudStreams.Dashboard.csproj +++ b/src/dashboard/CloudStreams.Dashboard/CloudStreams.Dashboard.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -19,13 +19,13 @@ - - + + - - - - + + + + diff --git a/src/gateway/CloudStreams.Gateway.Api/CloudStreams.Gateway.Api.csproj b/src/gateway/CloudStreams.Gateway.Api/CloudStreams.Gateway.Api.csproj index 451c2339..f3594158 100644 --- a/src/gateway/CloudStreams.Gateway.Api/CloudStreams.Gateway.Api.csproj +++ b/src/gateway/CloudStreams.Gateway.Api/CloudStreams.Gateway.Api.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -26,10 +26,10 @@ - - - - + + + + diff --git a/src/gateway/CloudStreams.Gateway.Api/Dockerfile b/src/gateway/CloudStreams.Gateway.Api/Dockerfile index 35edcddd..8cb81684 100644 --- a/src/gateway/CloudStreams.Gateway.Api/Dockerfile +++ b/src/gateway/CloudStreams.Gateway.Api/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base USER app WORKDIR /app EXPOSE 80 @@ -6,7 +6,7 @@ USER root RUN apt-get update RUN apt-get install -y jq -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["src/gateway/CloudStreams.Gateway.Api/CloudStreams.Gateway.Api.csproj", "src/gateway/CloudStreams.Gateway.Api/"] diff --git a/src/gateway/CloudStreams.Gateway.Api/Program.cs b/src/gateway/CloudStreams.Gateway.Api/Program.cs index 9e4b437a..0a1f5e27 100644 --- a/src/gateway/CloudStreams.Gateway.Api/Program.cs +++ b/src/gateway/CloudStreams.Gateway.Api/Program.cs @@ -37,6 +37,7 @@ }); builder.Services.Configure(builder.Configuration); +builder.Services.AddHostedService(); builder.Services.AddSingleton(); builder.Services.AddSingleton(provider => provider.GetRequiredService()); builder.Services.AddSingleton(provider => provider.GetRequiredService()); diff --git a/src/gateway/CloudStreams.Gateway.Application/CloudStreams.Gateway.Application.csproj b/src/gateway/CloudStreams.Gateway.Application/CloudStreams.Gateway.Application.csproj index ae0b9056..deaeb470 100644 --- a/src/gateway/CloudStreams.Gateway.Application/CloudStreams.Gateway.Application.csproj +++ b/src/gateway/CloudStreams.Gateway.Application/CloudStreams.Gateway.Application.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable 0.28.0 @@ -19,8 +19,8 @@ - - + + diff --git a/src/gateway/CloudStreams.Gateway.Application/Services/DatabaseProvisioner.cs b/src/gateway/CloudStreams.Gateway.Application/Services/DatabaseProvisioner.cs new file mode 100644 index 00000000..49cc066b --- /dev/null +++ b/src/gateway/CloudStreams.Gateway.Application/Services/DatabaseProvisioner.cs @@ -0,0 +1,222 @@ +// Copyright © 2024-Present The Cloud Streams Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"), +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using CloudStreams.Core.Resources; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Neuroglia.Data.Infrastructure.ResourceOriented; +using Neuroglia.Data.Infrastructure.ResourceOriented.Services; +using Neuroglia.Serialization; +using System.Diagnostics; + +namespace CloudStreams.Gateway.Application.Services; + +/// +/// Represents the service used to provision the solution's database +/// +/// The current +/// The service used to perform logging +/// The service used to serialize/deserialize data to/from JSON +/// The service used to serialize/deserialize data to/from YAML +public class DatabaseProvisioner(IServiceProvider serviceProvider, ILogger logger, IJsonSerializer jsonSerializer, IYamlSerializer yamlSerializer) + : IHostedService +{ + + /// + /// Gets the current + /// + protected IServiceProvider ServiceProvider { get; } = serviceProvider; + + /// + /// Gets the service used to perform logging + /// + protected ILogger Logger { get; } = logger; + + /// + /// Gets the service used to serialize/deserialize data to/from JSON + /// + protected IJsonSerializer JsonSerializer { get; } = jsonSerializer; + + /// + /// Gets the service used to serialize/deserialize data to/from YAML + /// + protected IYamlSerializer YamlSerializer { get; } = yamlSerializer; + + /// + public virtual async Task StartAsync(CancellationToken cancellationToken) + { + using var scope = this.ServiceProvider.CreateScope(); + var resources = scope.ServiceProvider.GetRequiredService(); + await this.ProvisionGatewaysAsync(resources, cancellationToken).ConfigureAwait(false); + await this.ProvisionBrokersAsync(resources, cancellationToken).ConfigureAwait(false); + await this.ProvisionSubscriptionAsync(resources, cancellationToken).ConfigureAwait(false); + } + + /// + /// Provisions the solution's database with gateways + /// + /// The to provision + /// A + /// A new awaitable + protected virtual async Task ProvisionGatewaysAsync(IResourceRepository resources, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(resources); + var stopwatch = new Stopwatch(); + var directory = new DirectoryInfo(Path.Combine(AppContext.BaseDirectory, "data", "seed", "gateways")); + if (!directory.Exists) return; + this.Logger.LogInformation("Starting importing gateways from directory '{directory}'...", directory.FullName); + var pattern = "*.*"; + var files = directory.GetFiles(pattern, SearchOption.AllDirectories).Where(f => f.FullName.EndsWith(".json", StringComparison.OrdinalIgnoreCase) || f.FullName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase) || f.FullName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase)); + if (!files.Any()) + { + this.Logger.LogWarning("No gateway static resource files matching search pattern '{pattern}' found in directory '{directory}'. Skipping import.", pattern, directory.FullName); + return; + } + stopwatch.Restart(); + var count = 0; + foreach (var file in files) + { + try + { + var extension = file.FullName.Split('.', StringSplitOptions.RemoveEmptyEntries).LastOrDefault(); + var serializer = extension?.ToLowerInvariant() switch + { + "json" => (ITextSerializer)this.JsonSerializer, + "yml" or "yaml" => this.YamlSerializer, + _ => throw new NotSupportedException($"The specified extension '{extension}' is not supported for static resource files") + }; + using var stream = file.OpenRead(); + using var streamReader = new StreamReader(stream); + var text = await streamReader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + var gateway = serializer.Deserialize(text)!; + await resources.AddAsync(gateway, false, cancellationToken).ConfigureAwait(false); + this.Logger.LogInformation("Successfully imported gateway '{subscription}' from file '{file}'", $"{gateway.Metadata.Name}", file.FullName); + count++; + } + catch (Exception ex) + { + this.Logger.LogError("An error occurred while reading a gateway from file '{file}': {ex}", file.FullName, ex); + continue; + } + } + stopwatch.Stop(); + this.Logger.LogInformation("Completed importing {count} gateway in {ms} milliseconds", count, stopwatch.Elapsed.TotalMilliseconds); + } + + /// + /// Provisions the solution's database with brokers + /// + /// The to provision + /// A + /// A new awaitable + protected virtual async Task ProvisionBrokersAsync(IResourceRepository resources, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(resources); + var stopwatch = new Stopwatch(); + var directory = new DirectoryInfo(Path.Combine(AppContext.BaseDirectory, "data", "seed", "gateways")); + if (!directory.Exists) return; + this.Logger.LogInformation("Starting importing brokers from directory '{directory}'...", directory.FullName); + var pattern = "*.*"; + var files = directory.GetFiles(pattern, SearchOption.AllDirectories).Where(f => f.FullName.EndsWith(".json", StringComparison.OrdinalIgnoreCase) || f.FullName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase) || f.FullName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase)); + if (!files.Any()) + { + this.Logger.LogWarning("No broker static resource files matching search pattern '{pattern}' found in directory '{directory}'. Skipping import.", pattern, directory.FullName); + return; + } + stopwatch.Restart(); + var count = 0; + foreach (var file in files) + { + try + { + var extension = file.FullName.Split('.', StringSplitOptions.RemoveEmptyEntries).LastOrDefault(); + var serializer = extension?.ToLowerInvariant() switch + { + "json" => (ITextSerializer)this.JsonSerializer, + "yml" or "yaml" => this.YamlSerializer, + _ => throw new NotSupportedException($"The specified extension '{extension}' is not supported for static resource files") + }; + using var stream = file.OpenRead(); + using var streamReader = new StreamReader(stream); + var text = await streamReader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + var broker = serializer.Deserialize(text)!; + await resources.AddAsync(broker, false, cancellationToken).ConfigureAwait(false); + this.Logger.LogInformation("Successfully imported broker '{subscription}' from file '{file}'", $"{broker.Metadata.Name}", file.FullName); + count++; + } + catch (Exception ex) + { + this.Logger.LogError("An error occurred while reading a broker from file '{file}': {ex}", file.FullName, ex); + continue; + } + } + stopwatch.Stop(); + this.Logger.LogInformation("Completed importing {count} broker in {ms} milliseconds", count, stopwatch.Elapsed.TotalMilliseconds); + } + + /// + /// Provisions the solution's database with subscriptions + /// + /// The to provision + /// A + /// A new awaitable + protected virtual async Task ProvisionSubscriptionAsync(IResourceRepository resources, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(resources); + var stopwatch = new Stopwatch(); + var directory = new DirectoryInfo(Path.Combine(AppContext.BaseDirectory, "data", "seed", "subscriptions")); + if (!directory.Exists) return; + this.Logger.LogInformation("Starting importing subscriptions from directory '{directory}'...", directory.FullName); + var pattern = "*.*"; + var files = directory.GetFiles(pattern, SearchOption.AllDirectories).Where(f => f.FullName.EndsWith(".json", StringComparison.OrdinalIgnoreCase) || f.FullName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase) || f.FullName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase)); + if (!files.Any()) + { + this.Logger.LogWarning("No subscription static resource files matching search pattern '{pattern}' found in directory '{directory}'. Skipping import.", pattern, directory.FullName); + return; + } + stopwatch.Restart(); + var count = 0; + foreach (var file in files) + { + try + { + var extension = file.FullName.Split('.', StringSplitOptions.RemoveEmptyEntries).LastOrDefault(); + var serializer = extension?.ToLowerInvariant() switch + { + "json" => (ITextSerializer)this.JsonSerializer, + "yml" or "yaml" => this.YamlSerializer, + _ => throw new NotSupportedException($"The specified extension '{extension}' is not supported for static resource files") + }; + using var stream = file.OpenRead(); + using var streamReader = new StreamReader(stream); + var text = await streamReader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + var subscription = serializer.Deserialize(text)!; + await resources.AddAsync(subscription, false, cancellationToken).ConfigureAwait(false); + this.Logger.LogInformation("Successfully imported subscription '{subscription}' from file '{file}'", $"{subscription.Metadata.Name}", file.FullName); + count++; + } + catch (Exception ex) + { + this.Logger.LogError("An error occurred while reading a subscription from file '{file}': {ex}", file.FullName, ex); + continue; + } + } + stopwatch.Stop(); + this.Logger.LogInformation("Completed importing {count} subscription in {ms} milliseconds", count, stopwatch.Elapsed.TotalMilliseconds); + } + + /// + public virtual Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + +} From 9e1d18bbb6433aabd87a7dc9611f2e2179acc284 Mon Sep 17 00:00:00 2001 From: Charles d'Avernas Date: Wed, 22 Jan 2025 10:50:50 +0100 Subject: [PATCH 2/2] feat(CICD): Add PR template Signed-off-by: Charles d'Avernas --- .github/PULL_REQUEST_TEMPLATE.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..157cd18e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ +**Many thanks for submitting your Pull Request :heart:!** + +**What this PR does / why we need it**: + +**Special notes for reviewers**: + +**Additional information (if needed):** \ No newline at end of file