From 52c8e3b9a3127793bbf53248b4a90c6fa74baa16 Mon Sep 17 00:00:00 2001 From: Maxwell Weru Date: Mon, 20 Nov 2023 07:14:48 +0300 Subject: [PATCH] Upgrade to .NET 8 and latest C# language features --- .github/workflows/server.yml | 2 +- server/Directory.Build.props | 4 +- .../Models/DependabotConfigurationTests.cs | 16 +++---- .../MissedTriggerCheckerTaskTests.cs | 6 +-- .../UpdateJobsCleanerTaskTests.cs | 6 +-- .../WebhooksControllerIntegrationTests.cs | 6 +-- .../Workflow/UpdateRunnerTests.cs | 44 +++++++++---------- server/Tingle.Dependabot/ApiKeyProvider.cs | 24 +++------- .../InsightsFilteringProcessor.cs | 4 +- .../Consumers/UpdateJobEventsConsumer.cs | 1 - .../Controllers/UpdateJobsController.cs | 2 +- server/Tingle.Dependabot/Dockerfile | 24 +++++----- server/Tingle.Dependabot/Dockerfile.CI | 8 ++-- .../Extensions/PropertyBuilderExtensions.cs | 2 +- .../Models/Azure/AzdoSubscriptionsQuery.cs | 4 +- .../Dependabot/DependabotConfiguration.cs | 6 +-- .../Tingle.Dependabot/Models/MainDbContext.cs | 4 +- .../Models/Management/Project.cs | 2 +- .../Models/Management/Repository.cs | 4 +- .../Models/Management/RepositoryUpdate.cs | 2 +- .../PeriodicTasks/MissedTriggerCheckerTask.cs | 15 ++----- .../PeriodicTasks/SynchronizationTask.cs | 12 ++--- server/Tingle.Dependabot/Program.cs | 40 ++++++++--------- .../Properties/launchSettings.json | 9 ++-- .../Workflow/AzureDevOpsProvider.cs | 16 +++---- .../Workflow/Synchronizer.cs | 2 +- .../Workflow/UpdateRunner.cs | 6 +-- 27 files changed, 123 insertions(+), 148 deletions(-) diff --git a/.github/workflows/server.yml b/.github/workflows/server.yml index 524fe93fb..03c5b0f35 100644 --- a/.github/workflows/server.yml +++ b/.github/workflows/server.yml @@ -45,7 +45,7 @@ jobs: - name: Setup .NET SDK uses: actions/setup-dotnet@v3 with: - dotnet-version: '7.x' + dotnet-version: '8.x' - name: Test run: dotnet test -c $buildConfiguration --verbosity normal --collect "Code coverage" diff --git a/server/Directory.Build.props b/server/Directory.Build.props index 2c6ee45d8..ffab359d4 100644 --- a/server/Directory.Build.props +++ b/server/Directory.Build.props @@ -2,11 +2,11 @@ - net7.0 + net8.0 - 11.0 + latest enable enable diff --git a/server/Tingle.Dependabot.Tests/Models/DependabotConfigurationTests.cs b/server/Tingle.Dependabot.Tests/Models/DependabotConfigurationTests.cs index 3b1b3caf7..cd2ee46ec 100644 --- a/server/Tingle.Dependabot.Tests/Models/DependabotConfigurationTests.cs +++ b/server/Tingle.Dependabot.Tests/Models/DependabotConfigurationTests.cs @@ -42,7 +42,7 @@ public void Deserialization_Works() Assert.Equal(DependabotScheduleDay.Monday, second.Schedule?.Day); Assert.Equal("Etc/UTC", second.Schedule?.Timezone); Assert.Equal("deny", second.InsecureExternalCodeExecution); - Assert.Equal(new[] { "reg1", "reg2", }, second.Registries); + Assert.Equal(["reg1", "reg2"], second.Registries); } [Fact] @@ -51,15 +51,15 @@ public void Validation_Works() var configuration = new DependabotConfiguration { Version = 2, - Updates = new List - { + Updates = + [ new DependabotUpdate { PackageEcosystem = "npm", Directory = "/", - Registries = new List { "dummy1", "dummy2", }, + Registries = ["dummy1", "dummy2",], }, - }, + ], Registries = new Dictionary { ["dummy1"] = new DependabotRegistry @@ -87,7 +87,7 @@ public void Validation_Works() // fails: registry not referenced configuration.Updates[0].Registries?.Clear(); - results = new List(); + results = []; actual = RecursiveValidator.TryValidateObject(configuration, results); Assert.False(actual); var val = Assert.Single(results); @@ -96,8 +96,8 @@ public void Validation_Works() Assert.Equal("Registries: 'dummy1,dummy2' have not been referenced by any update", val.ErrorMessage); // fails: registrynot configured - configuration.Updates[0].Registries?.AddRange(new[] { "dummy1", "dummy2", "dummy3" }); - results = new List(); + configuration.Updates[0].Registries?.AddRange(["dummy1", "dummy2", "dummy3"]); + results = []; actual = RecursiveValidator.TryValidateObject(configuration, results); Assert.False(actual); val = Assert.Single(results); diff --git a/server/Tingle.Dependabot.Tests/PeriodicTasks/MissedTriggerCheckerTaskTests.cs b/server/Tingle.Dependabot.Tests/PeriodicTasks/MissedTriggerCheckerTaskTests.cs index df2285f22..e9d152ae1 100644 --- a/server/Tingle.Dependabot.Tests/PeriodicTasks/MissedTriggerCheckerTaskTests.cs +++ b/server/Tingle.Dependabot.Tests/PeriodicTasks/MissedTriggerCheckerTaskTests.cs @@ -120,8 +120,8 @@ await context.Repositories.AddAsync(new Repository ProviderId = Guid.NewGuid().ToString(), Name = "test-repo", ConfigFileContents = "", - Updates = new List - { + Updates = + [ new RepositoryUpdate { PackageEcosystem = "npm", @@ -144,7 +144,7 @@ await context.Repositories.AddAsync(new Repository }, LatestUpdate = lastUpdate1, }, - }, + ], }); await context.SaveChangesAsync(); diff --git a/server/Tingle.Dependabot.Tests/PeriodicTasks/UpdateJobsCleanerTaskTests.cs b/server/Tingle.Dependabot.Tests/PeriodicTasks/UpdateJobsCleanerTaskTests.cs index 241ac77fa..dee57b93a 100644 --- a/server/Tingle.Dependabot.Tests/PeriodicTasks/UpdateJobsCleanerTaskTests.cs +++ b/server/Tingle.Dependabot.Tests/PeriodicTasks/UpdateJobsCleanerTaskTests.cs @@ -169,8 +169,8 @@ await context.Repositories.AddAsync(new Repository ProviderId = Guid.NewGuid().ToString(), Name = "test-repo", ConfigFileContents = "", - Updates = new List - { + Updates = + [ new RepositoryUpdate { PackageEcosystem = "npm", @@ -191,7 +191,7 @@ await context.Repositories.AddAsync(new Repository Time = new(3, 30), }, }, - }, + ], }); await context.SaveChangesAsync(); diff --git a/server/Tingle.Dependabot.Tests/WebhooksControllerIntegrationTests.cs b/server/Tingle.Dependabot.Tests/WebhooksControllerIntegrationTests.cs index 640c6a65d..36ef84831 100644 --- a/server/Tingle.Dependabot.Tests/WebhooksControllerIntegrationTests.cs +++ b/server/Tingle.Dependabot.Tests/WebhooksControllerIntegrationTests.cs @@ -61,7 +61,7 @@ await TestAsync(async (harness, client) => var response = await client.SendAsync(request); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); var body = await response.Content.ReadAsStringAsync(); - Assert.Contains("\"type\":\"https://tools.ietf.org/html/rfc7231#section-6.5.1\"", body); + Assert.Contains("\"type\":\"https://tools.ietf.org/html/rfc9110#section-15.5.1\"", body); Assert.Contains("\"title\":\"One or more validation errors occurred.\"", body); Assert.Contains("\"status\":400", body); Assert.Contains("\"errors\":{\"\":[\"A non-empty request body is required.\"],\"model\":[\"The model field is required.\"]}", body); @@ -80,7 +80,7 @@ await TestAsync(async (harness, client) => var response = await client.SendAsync(request); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); var body = await response.Content.ReadAsStringAsync(); - Assert.Contains("\"type\":\"https://tools.ietf.org/html/rfc7231#section-6.5.1\"", body); + Assert.Contains("\"type\":\"https://tools.ietf.org/html/rfc9110#section-15.5.1\"", body); Assert.Contains("\"title\":\"One or more validation errors occurred.\"", body); Assert.Contains("\"status\":400", body); Assert.Contains("\"SubscriptionId\":[\"The SubscriptionId field is required.\"]", body); @@ -102,7 +102,7 @@ await TestAsync(async (harness, client) => var response = await client.SendAsync(request); Assert.Equal(HttpStatusCode.UnsupportedMediaType, response.StatusCode); var body = await response.Content.ReadAsStringAsync(); - Assert.Contains("\"type\":\"https://tools.ietf.org/html/rfc7231#section-6.5.13\"", body); + Assert.Contains("\"type\":\"https://tools.ietf.org/html/rfc9110#section-15.5.16\"", body); Assert.Contains("\"title\":\"Unsupported Media Type\"", body); Assert.Contains("\"status\":415", body); Assert.Empty(await harness.PublishedAsync()); diff --git a/server/Tingle.Dependabot.Tests/Workflow/UpdateRunnerTests.cs b/server/Tingle.Dependabot.Tests/Workflow/UpdateRunnerTests.cs index 63915c5d9..b074410cd 100644 --- a/server/Tingle.Dependabot.Tests/Workflow/UpdateRunnerTests.cs +++ b/server/Tingle.Dependabot.Tests/Workflow/UpdateRunnerTests.cs @@ -35,58 +35,58 @@ public void MakeCredentialsMetadata_Works() // composer-repository var metadata = metadatas[0]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "composer_repository", "repo.packagist.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["composer_repository", "repo.packagist.com"], metadata.Values); // docker-registry metadata = metadatas[1]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "docker_registry", "registry.hub.docker.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["docker_registry", "registry.hub.docker.com"], metadata.Values); // git metadata = metadatas[2]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "git", "github.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["git", "github.com"], metadata.Values); // hex-organization metadata = metadatas[3]; - Assert.Equal(new[] { "type", }, metadata.Keys); - Assert.Equal(new[] { "hex_organization", }, metadata.Values); + Assert.Equal(["type"], metadata.Keys); + Assert.Equal(["hex_organization"], metadata.Values); // hex-repository metadata = metadatas[4]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "hex_repository", "private-repo.example.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["hex_repository", "private-repo.example.com"], metadata.Values); // maven-repository metadata = metadatas[5]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "maven_repository", "artifactory.example.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["maven_repository", "artifactory.example.com"], metadata.Values); // npm-registry metadata = metadatas[6]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "npm_registry", "npm.pkg.github.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["npm_registry", "npm.pkg.github.com"], metadata.Values); // nuget-feed metadata = metadatas[7]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "nuget_feed", "pkgs.dev.azure.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["nuget_feed", "pkgs.dev.azure.com"], metadata.Values); // python-index metadata = metadatas[8]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "python_index", "pkgs.dev.azure.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["python_index", "pkgs.dev.azure.com"], metadata.Values); // rubygems-server metadata = metadatas[9]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "rubygems_server", "rubygems.pkg.github.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["rubygems_server", "rubygems.pkg.github.com"], metadata.Values); // terraform-registry metadata = metadatas[10]; - Assert.Equal(new[] { "type", "host", }, metadata.Keys); - Assert.Equal(new[] { "terraform_registry", "terraform.example.com", }, metadata.Values); + Assert.Equal(["type", "host"], metadata.Keys); + Assert.Equal(["terraform_registry", "terraform.example.com"], metadata.Values); } [Fact] diff --git a/server/Tingle.Dependabot/ApiKeyProvider.cs b/server/Tingle.Dependabot/ApiKeyProvider.cs index 17923cf9c..483163b1b 100644 --- a/server/Tingle.Dependabot/ApiKeyProvider.cs +++ b/server/Tingle.Dependabot/ApiKeyProvider.cs @@ -5,15 +5,8 @@ namespace Tingle.Dependabot; -internal class ApiKeyProvider : IApiKeyProvider +internal class ApiKeyProvider(MainDbContext dbContext) : IApiKeyProvider { - private readonly MainDbContext dbContext; - - public ApiKeyProvider(MainDbContext dbContext) - { - this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); - } - public async Task ProvideAsync(string key) { var job = await dbContext.UpdateJobs.SingleOrDefaultAsync(j => j.AuthKey == key); @@ -25,17 +18,10 @@ public ApiKeyProvider(MainDbContext dbContext) return null; } - class ApiKey : IApiKey + class ApiKey(string key, string owner, IReadOnlyCollection? claims = null) : IApiKey { - public ApiKey(string key, string owner, IReadOnlyCollection? claims = null) - { - Key = key; - OwnerName = owner; - Claims = claims ?? new List(); - } - - public string Key { get; } - public string OwnerName { get; } - public IReadOnlyCollection Claims { get; } + public string Key { get; } = key; + public string OwnerName { get; } = owner; + public IReadOnlyCollection Claims { get; } = claims ?? new List(); } } diff --git a/server/Tingle.Dependabot/ApplicationInsights/InsightsFilteringProcessor.cs b/server/Tingle.Dependabot/ApplicationInsights/InsightsFilteringProcessor.cs index 58eb46306..49802789c 100644 --- a/server/Tingle.Dependabot/ApplicationInsights/InsightsFilteringProcessor.cs +++ b/server/Tingle.Dependabot/ApplicationInsights/InsightsFilteringProcessor.cs @@ -10,10 +10,10 @@ namespace Tingle.Dependabot.ApplicationInsights; internal class InsightsFilteringProcessor : ITelemetryProcessor { private static readonly string[] excludedRequestNames = - { + [ "ServiceBusReceiver.Receive", "ServiceBusProcessor.ProcessMessage", - }; + ]; private readonly ITelemetryProcessor next; diff --git a/server/Tingle.Dependabot/Consumers/UpdateJobEventsConsumer.cs b/server/Tingle.Dependabot/Consumers/UpdateJobEventsConsumer.cs index d6f9e96b9..67897dc26 100644 --- a/server/Tingle.Dependabot/Consumers/UpdateJobEventsConsumer.cs +++ b/server/Tingle.Dependabot/Consumers/UpdateJobEventsConsumer.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; using Tingle.Dependabot.Events; using Tingle.Dependabot.Models; using Tingle.Dependabot.Models.Management; diff --git a/server/Tingle.Dependabot/Controllers/UpdateJobsController.cs b/server/Tingle.Dependabot/Controllers/UpdateJobsController.cs index 38ffa8953..185fe0303 100644 --- a/server/Tingle.Dependabot/Controllers/UpdateJobsController.cs +++ b/server/Tingle.Dependabot/Controllers/UpdateJobsController.cs @@ -117,7 +117,7 @@ public async Task UpdateDependencyListAsync([FromRoute, Required] var update = repository.Updates.SingleOrDefault(u => u.PackageEcosystem == job.PackageEcosystem && u.Directory == job.Directory); if (update is not null) { - update.Files = model.Data?.DependencyFiles ?? new(); + update.Files = model.Data?.DependencyFiles ?? []; } await dbContext.SaveChangesAsync(); diff --git a/server/Tingle.Dependabot/Dockerfile b/server/Tingle.Dependabot/Dockerfile index aa028e58f..74e737680 100644 --- a/server/Tingle.Dependabot/Dockerfile +++ b/server/Tingle.Dependabot/Dockerfile @@ -1,21 +1,25 @@ -#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim AS base +FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim AS base LABEL org.opencontainers.image.source="https://github.com/tinglesoftware/dependabot-azure-devops" +USER app WORKDIR /app -EXPOSE 80 -EXPOSE 443 +EXPOSE 8080 +EXPOSE 8081 -FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim AS build +ARG BUILD_CONFIGURATION=Release WORKDIR /src -COPY ["Tingle.Dependabot/Tingle.Dependabot.csproj", "Tingle.Dependabot/"] -RUN dotnet restore "Tingle.Dependabot/Tingle.Dependabot.csproj" +COPY ["server/Directory.Build.props", "server/"] +COPY ["server/Tingle.Dependabot/Tingle.Dependabot.csproj", "server/Tingle.Dependabot/"] +RUN dotnet restore "./server/Tingle.Dependabot/./Tingle.Dependabot.csproj" COPY . . -WORKDIR "/src/Tingle.Dependabot" -RUN dotnet build "Tingle.Dependabot.csproj" -c Release -o /app/build +WORKDIR "/src/server/Tingle.Dependabot" +RUN dotnet build "./Tingle.Dependabot.csproj" -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish -RUN dotnet publish "Tingle.Dependabot.csproj" -c Release -o /app/publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./Tingle.Dependabot.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app diff --git a/server/Tingle.Dependabot/Dockerfile.CI b/server/Tingle.Dependabot/Dockerfile.CI index 63fd0fb4b..96024f38a 100644 --- a/server/Tingle.Dependabot/Dockerfile.CI +++ b/server/Tingle.Dependabot/Dockerfile.CI @@ -4,10 +4,12 @@ # # As a result, we only copy publish output and put it in the container -FROM mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim AS base +FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim AS base LABEL org.opencontainers.image.source="https://github.com/tinglesoftware/dependabot-azure-devops" -EXPOSE 80 -EXPOSE 443 +USER app WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + COPY . . ENTRYPOINT ["dotnet", "Tingle.Dependabot.dll"] \ No newline at end of file diff --git a/server/Tingle.Dependabot/Extensions/PropertyBuilderExtensions.cs b/server/Tingle.Dependabot/Extensions/PropertyBuilderExtensions.cs index fb798fee6..69db7d16a 100644 --- a/server/Tingle.Dependabot/Extensions/PropertyBuilderExtensions.cs +++ b/server/Tingle.Dependabot/Extensions/PropertyBuilderExtensions.cs @@ -105,7 +105,7 @@ public static PropertyBuilder HasJsonConversion(this PropertyBuilder pr private static List ConvertFromString(string? value, string separator, JsonSerializerOptions? serializerOptions) where T : IConvertible { - if (string.IsNullOrWhiteSpace(value)) return new List(); + if (string.IsNullOrWhiteSpace(value)) return []; if (string.IsNullOrWhiteSpace(separator)) { throw new ArgumentException($"'{nameof(separator)}' cannot be null or whitespace.", nameof(separator)); diff --git a/server/Tingle.Dependabot/Models/Azure/AzdoSubscriptionsQuery.cs b/server/Tingle.Dependabot/Models/Azure/AzdoSubscriptionsQuery.cs index ec0d3c176..d3970c8d3 100644 --- a/server/Tingle.Dependabot/Models/Azure/AzdoSubscriptionsQuery.cs +++ b/server/Tingle.Dependabot/Models/Azure/AzdoSubscriptionsQuery.cs @@ -75,7 +75,7 @@ public class AzdoSubscription public required string PublisherId { get; set; } [JsonPropertyName("publisherInputs")] - public Dictionary PublisherInputs { get; set; } = new(); + public Dictionary PublisherInputs { get; set; } = []; [JsonPropertyName("consumerId")] public string? ConsumerId { get; set; } @@ -84,7 +84,7 @@ public class AzdoSubscription public string? ConsumerActionId { get; set; } [JsonPropertyName("consumerInputs")] - public Dictionary ConsumerInputs { get; set; } = new(); + public Dictionary ConsumerInputs { get; set; } = []; [JsonPropertyName("eventType")] public required string EventType { get; set; } diff --git a/server/Tingle.Dependabot/Models/Dependabot/DependabotConfiguration.cs b/server/Tingle.Dependabot/Models/Dependabot/DependabotConfiguration.cs index 9db71fe12..1786e58e8 100644 --- a/server/Tingle.Dependabot/Models/Dependabot/DependabotConfiguration.cs +++ b/server/Tingle.Dependabot/Models/Dependabot/DependabotConfiguration.cs @@ -14,13 +14,13 @@ public class DependabotConfiguration : IValidatableObject public List? Updates { get; set; } [JsonPropertyName("registries")] - public Dictionary Registries { get; set; } = new(); + public Dictionary Registries { get; set; } = []; public IEnumerable Validate(ValidationContext validationContext) { - var updates = Updates ?? new(); + var updates = Updates ?? []; var configured = Registries.Keys; - var referenced = updates.SelectMany(r => r.Registries ?? new()).ToList(); + var referenced = updates.SelectMany(r => r.Registries ?? []).ToList(); // ensure there are no configured registries that have not been referenced var missingConfiguration = referenced.Except(configured).ToList(); diff --git a/server/Tingle.Dependabot/Models/MainDbContext.cs b/server/Tingle.Dependabot/Models/MainDbContext.cs index 455ba3b05..bdf236bbc 100644 --- a/server/Tingle.Dependabot/Models/MainDbContext.cs +++ b/server/Tingle.Dependabot/Models/MainDbContext.cs @@ -7,10 +7,8 @@ namespace Tingle.Dependabot.Models; -public class MainDbContext : DbContext, IDataProtectionKeyContext +public class MainDbContext(DbContextOptions options) : DbContext(options), IDataProtectionKeyContext { - public MainDbContext(DbContextOptions options) : base(options) { } - public DbSet Projects => Set(); public DbSet Repositories => Set(); public DbSet UpdateJobs => Set(); diff --git a/server/Tingle.Dependabot/Models/Management/Project.cs b/server/Tingle.Dependabot/Models/Management/Project.cs index 822ea9480..ee6325a2c 100644 --- a/server/Tingle.Dependabot/Models/Management/Project.cs +++ b/server/Tingle.Dependabot/Models/Management/Project.cs @@ -89,7 +89,7 @@ public class Project public string? Location { get; set; } [JsonIgnore] // only for internal use - public List Repositories { get; set; } = new(); + public List Repositories { get; set; } = []; /// Time at which the synchronization was last done for the project. public DateTimeOffset? Synchronized { get; set; } diff --git a/server/Tingle.Dependabot/Models/Management/Repository.cs b/server/Tingle.Dependabot/Models/Management/Repository.cs index d52a417f2..703cb239f 100644 --- a/server/Tingle.Dependabot/Models/Management/Repository.cs +++ b/server/Tingle.Dependabot/Models/Management/Repository.cs @@ -51,14 +51,14 @@ public class Repository /// Updates for the repository, extracted from the configuration file. /// When null or empty, there was a parsing exception. /// - public List Updates { get; set; } = new List(); + public List Updates { get; set; } = []; /// /// Registries for the repository, extracted from the configuration file. /// When null or empty, there was a parsing exception. /// [JsonIgnore] // only for internal use - public Dictionary Registries { get; set; } = new(); + public Dictionary Registries { get; set; } = []; [Timestamp] public byte[]? Etag { get; set; } diff --git a/server/Tingle.Dependabot/Models/Management/RepositoryUpdate.cs b/server/Tingle.Dependabot/Models/Management/RepositoryUpdate.cs index b8b4b77cb..21445bb04 100644 --- a/server/Tingle.Dependabot/Models/Management/RepositoryUpdate.cs +++ b/server/Tingle.Dependabot/Models/Management/RepositoryUpdate.cs @@ -11,7 +11,7 @@ public RepositoryUpdate(DependabotUpdate update) : base(update) { } /// The dependency files. [JsonPropertyName("files")] - public List Files { get; set; } = new List(); + public List Files { get; set; } = []; /// Identifier of the latest job. [JsonPropertyName("latest-job-id")] diff --git a/server/Tingle.Dependabot/PeriodicTasks/MissedTriggerCheckerTask.cs b/server/Tingle.Dependabot/PeriodicTasks/MissedTriggerCheckerTask.cs index 204cb93c5..4216f3ec7 100644 --- a/server/Tingle.Dependabot/PeriodicTasks/MissedTriggerCheckerTask.cs +++ b/server/Tingle.Dependabot/PeriodicTasks/MissedTriggerCheckerTask.cs @@ -8,18 +8,11 @@ namespace Tingle.Dependabot.PeriodicTasks; -internal class MissedTriggerCheckerTask : IPeriodicTask +internal class MissedTriggerCheckerTask(MainDbContext dbContext, IEventPublisher publisher, ILogger logger) : IPeriodicTask { - private readonly MainDbContext dbContext; - private readonly IEventPublisher publisher; - private readonly ILogger logger; - - public MissedTriggerCheckerTask(MainDbContext dbContext, IEventPublisher publisher, ILogger logger) - { - this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); - this.publisher = publisher ?? throw new ArgumentNullException(nameof(publisher)); - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + private readonly MainDbContext dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); + private readonly IEventPublisher publisher = publisher ?? throw new ArgumentNullException(nameof(publisher)); + private readonly ILogger logger = logger ?? throw new ArgumentNullException(nameof(logger)); public async Task ExecuteAsync(PeriodicTaskExecutionContext context, CancellationToken cancellationToken) { diff --git a/server/Tingle.Dependabot/PeriodicTasks/SynchronizationTask.cs b/server/Tingle.Dependabot/PeriodicTasks/SynchronizationTask.cs index f62249a26..fa2cfaba7 100644 --- a/server/Tingle.Dependabot/PeriodicTasks/SynchronizationTask.cs +++ b/server/Tingle.Dependabot/PeriodicTasks/SynchronizationTask.cs @@ -6,16 +6,10 @@ namespace Tingle.Dependabot.Workflow; -internal class SynchronizationTask : IPeriodicTask +internal class SynchronizationTask(MainDbContext dbContext, IEventPublisher publisher) : IPeriodicTask { - private readonly MainDbContext dbContext; - private readonly IEventPublisher publisher; - - public SynchronizationTask(MainDbContext dbContext, IEventPublisher publisher) - { - this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); - this.publisher = publisher ?? throw new ArgumentNullException(nameof(publisher)); - } + private readonly MainDbContext dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); + private readonly IEventPublisher publisher = publisher ?? throw new ArgumentNullException(nameof(publisher)); public async Task ExecuteAsync(PeriodicTaskExecutionContext context, CancellationToken cancellationToken) { diff --git a/server/Tingle.Dependabot/Program.cs b/server/Tingle.Dependabot/Program.cs index a9aa42df9..6e8e94295 100644 --- a/server/Tingle.Dependabot/Program.cs +++ b/server/Tingle.Dependabot/Program.cs @@ -24,12 +24,12 @@ { builder.ConfigureSensitiveDataMasking(options => { - options.ExcludeProperties.AddRange(new[] { + options.ExcludeProperties.AddRange([ "ExecutionId", "JobDefinitionPath", "UpdateJobId", "RepositoryUrl", - }); + ]); }); }); @@ -72,26 +72,22 @@ .AddApiKeyInAuthorizationHeader(AuthConstants.SchemeNameUpdater, options => options.Realm = "Dependabot") .AddBasic(AuthConstants.SchemeNameServiceHooks, options => options.Realm = "Dependabot"); -builder.Services.AddAuthorization(options => -{ - options.AddPolicy(AuthConstants.PolicyNameManagement, policy => - { - policy.AddAuthenticationSchemes(AuthConstants.SchemeNameManagement) - .RequireAuthenticatedUser(); - }); - - options.AddPolicy(AuthConstants.PolicyNameServiceHooks, policy => - { - policy.AddAuthenticationSchemes(AuthConstants.SchemeNameServiceHooks) - .RequireAuthenticatedUser(); - }); - - options.AddPolicy(AuthConstants.PolicyNameUpdater, policy => - { - policy.AddAuthenticationSchemes(AuthConstants.SchemeNameUpdater) - .RequireAuthenticatedUser(); - }); -}); +builder.Services.AddAuthorizationBuilder() + .AddPolicy(AuthConstants.PolicyNameManagement, policy => + { + policy.AddAuthenticationSchemes(AuthConstants.SchemeNameManagement) + .RequireAuthenticatedUser(); + }) + .AddPolicy(AuthConstants.PolicyNameServiceHooks, policy => + { + policy.AddAuthenticationSchemes(AuthConstants.SchemeNameServiceHooks) + .RequireAuthenticatedUser(); + }) + .AddPolicy(AuthConstants.PolicyNameUpdater, policy => + { + policy.AddAuthenticationSchemes(AuthConstants.SchemeNameUpdater) + .RequireAuthenticatedUser(); + }); // Configure other services builder.Services.AddMemoryCache(); diff --git a/server/Tingle.Dependabot/Properties/launchSettings.json b/server/Tingle.Dependabot/Properties/launchSettings.json index 40bb847cf..32bf3c926 100644 --- a/server/Tingle.Dependabot/Properties/launchSettings.json +++ b/server/Tingle.Dependabot/Properties/launchSettings.json @@ -17,9 +17,12 @@ "commandName": "Docker", "launchBrowser": true, "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/health", - "environmentVariables": {}, - "useSSL": true, - "publishAllPorts": true + "environmentVariables": { + "ASPNETCORE_HTTPS_PORTS": "8081", + "ASPNETCORE_HTTP_PORTS": "8080" + }, + "publishAllPorts": true, + "useSSL": true } } } \ No newline at end of file diff --git a/server/Tingle.Dependabot/Workflow/AzureDevOpsProvider.cs b/server/Tingle.Dependabot/Workflow/AzureDevOpsProvider.cs index 4a1dbb715..c4d71c492 100644 --- a/server/Tingle.Dependabot/Workflow/AzureDevOpsProvider.cs +++ b/server/Tingle.Dependabot/Workflow/AzureDevOpsProvider.cs @@ -19,12 +19,12 @@ public class AzureDevOpsProvider }; private static readonly (string, string)[] SubscriptionEventTypes = - { + [ ("git.push", "1.0"), ("git.pullrequest.updated", "1.0"), ("git.pullrequest.merged", "1.0"), ("ms.vss-code.git-pullrequest-comment-event", "2.0"), - }; + ]; private readonly HttpClient httpClient; private readonly WorkflowOptions options; @@ -42,21 +42,21 @@ public async Task> CreateOrUpdateSubscriptionsAsync(Project project var query = new AzdoSubscriptionsQuery { PublisherId = "tfs", - PublisherInputFilters = new List - { + PublisherInputFilters = + [ new AzdoSubscriptionsQueryInputFilter { - Conditions = new List - { + Conditions = + [ new AzdoSubscriptionsQueryInputFilterCondition { InputId = "projectId", Operator = AzdoSubscriptionsQueryInputFilterOperator.Equals, InputValue = projectId, }, - }, + ], }, - }, + ], ConsumerId = "webHooks", ConsumerActionId = "httpRequest", diff --git a/server/Tingle.Dependabot/Workflow/Synchronizer.cs b/server/Tingle.Dependabot/Workflow/Synchronizer.cs index e5057569a..818233cae 100644 --- a/server/Tingle.Dependabot/Workflow/Synchronizer.cs +++ b/server/Tingle.Dependabot/Workflow/Synchronizer.cs @@ -231,7 +231,7 @@ internal async Task SynchronizeAsync(Project project, var updates = configuration.Updates!; repository.Updates = updates.Select(update => new RepositoryUpdate(update) { - Files = new List(), // files are populated by an API call from Ruby during job execution + Files = [], // files are populated by an API call from Ruby during job execution LatestJobId = null, LatestJobStatus = null, diff --git a/server/Tingle.Dependabot/Workflow/UpdateRunner.cs b/server/Tingle.Dependabot/Workflow/UpdateRunner.cs index 36742a4e7..e5ed7eaf9 100644 --- a/server/Tingle.Dependabot/Workflow/UpdateRunner.cs +++ b/server/Tingle.Dependabot/Workflow/UpdateRunner.cs @@ -286,7 +286,7 @@ internal async Task> CreateEnvironmentVariables(Proj .AddIfNotDefault("AZURE_REPOSITORY", Uri.EscapeDataString(repository.Name!)) .AddIfNotDefault("AZURE_ACCESS_TOKEN", project.Token) .AddIfNotDefault("AZURE_SET_AUTO_COMPLETE", project.AutoComplete.Enabled.ToString().ToLowerInvariant()) - .AddIfNotDefault("AZURE_AUTO_COMPLETE_IGNORE_CONFIG_IDS", ToJson(project.AutoComplete.IgnoreConfigs ?? new())) + .AddIfNotDefault("AZURE_AUTO_COMPLETE_IGNORE_CONFIG_IDS", ToJson(project.AutoComplete.IgnoreConfigs ?? [])) .AddIfNotDefault("AZURE_MERGE_STRATEGY", project.AutoComplete.MergeStrategy?.ToString()) .AddIfNotDefault("AZURE_AUTO_APPROVE_PR", project.AutoApprove.Enabled.ToString().ToLowerInvariant()); @@ -315,13 +315,13 @@ internal async Task WriteJobDefinitionAsync(Project project, { ["job"] = new JsonObject { - ["allowed-updates"] = ToJsonNode(update.Allow ?? new()), + ["allowed-updates"] = ToJsonNode(update.Allow ?? []), ["credentials-metadata"] = ToJsonNode(credentialsMetadata).AsArray(), // ["dependencies"] = null, // object array ["directory"] = job.Directory, // ["existing-pull-requests"] = null, // object array ["experiments"] = ToJsonNode(experiments), - ["ignore-conditions"] = ToJsonNode(update.Ignore ?? new()), + ["ignore-conditions"] = ToJsonNode(update.Ignore ?? []), // ["security-advisories"] = null, // object array ["package_manager"] = ConvertEcosystemToPackageManager(job.PackageEcosystem!), ["repo-name"] = job.RepositorySlug,