Skip to content

Commit

Permalink
Upgrade to .NET 8 and latest C# language features (#881)
Browse files Browse the repository at this point in the history
  • Loading branch information
mburumaxwell authored Nov 20, 2023
1 parent 5d60bfc commit c67c7a2
Show file tree
Hide file tree
Showing 29 changed files with 129 additions and 154 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions server/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
<!-- There is nothing else to import. -->

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<PropertyGroup>
<LangVersion>11.0</LangVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -51,15 +51,15 @@ public void Validation_Works()
var configuration = new DependabotConfiguration
{
Version = 2,
Updates = new List<DependabotUpdate>
{
Updates =
[
new DependabotUpdate
{
PackageEcosystem = "npm",
Directory = "/",
Registries = new List<string> { "dummy1", "dummy2", },
Registries = ["dummy1", "dummy2",],
},
},
],
Registries = new Dictionary<string, DependabotRegistry>
{
["dummy1"] = new DependabotRegistry
Expand Down Expand Up @@ -87,7 +87,7 @@ public void Validation_Works()

// fails: registry not referenced
configuration.Updates[0].Registries?.Clear();
results = new List<ValidationResult>();
results = [];
actual = RecursiveValidator.TryValidateObject(configuration, results);
Assert.False(actual);
var val = Assert.Single(results);
Expand All @@ -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<ValidationResult>();
configuration.Updates[0].Registries?.AddRange(["dummy1", "dummy2", "dummy3"]);
results = [];
actual = RecursiveValidator.TryValidateObject(configuration, results);
Assert.False(actual);
val = Assert.Single(results);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ await context.Repositories.AddAsync(new Repository
ProviderId = Guid.NewGuid().ToString(),
Name = "test-repo",
ConfigFileContents = "",
Updates = new List<RepositoryUpdate>
{
Updates =
[
new RepositoryUpdate
{
PackageEcosystem = "npm",
Expand All @@ -144,7 +144,7 @@ await context.Repositories.AddAsync(new Repository
},
LatestUpdate = lastUpdate1,
},
},
],
});
await context.SaveChangesAsync();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ await context.Repositories.AddAsync(new Repository
ProviderId = Guid.NewGuid().ToString(),
Name = "test-repo",
ConfigFileContents = "",
Updates = new List<RepositoryUpdate>
{
Updates =
[
new RepositoryUpdate
{
PackageEcosystem = "npm",
Expand All @@ -191,7 +191,7 @@ await context.Repositories.AddAsync(new Repository
Time = new(3, 30),
},
},
},
],
});
await context.SaveChangesAsync();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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());
Expand Down
44 changes: 22 additions & 22 deletions server/Tingle.Dependabot.Tests/Workflow/UpdateRunnerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["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<string>(["type", "host"], metadata.Keys);
Assert.Equal<string>(["terraform_registry", "terraform.example.com"], metadata.Values);
}

[Fact]
Expand Down
24 changes: 5 additions & 19 deletions server/Tingle.Dependabot/ApiKeyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IApiKey?> ProvideAsync(string key)
{
var job = await dbContext.UpdateJobs.SingleOrDefaultAsync(j => j.AuthKey == key);
Expand All @@ -25,17 +18,10 @@ public ApiKeyProvider(MainDbContext dbContext)
return null;
}

class ApiKey : IApiKey
class ApiKey(string key, string owner, IReadOnlyCollection<Claim>? claims = null) : IApiKey
{
public ApiKey(string key, string owner, IReadOnlyCollection<Claim>? claims = null)
{
Key = key;
OwnerName = owner;
Claims = claims ?? new List<Claim>();
}

public string Key { get; }
public string OwnerName { get; }
public IReadOnlyCollection<Claim> Claims { get; }
public string Key { get; } = key;
public string OwnerName { get; } = owner;
public IReadOnlyCollection<Claim> Claims { get; } = claims ?? new List<Claim>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Tingle.Dependabot.Events;
using Tingle.Dependabot.Models;
using Tingle.Dependabot.Models.Management;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public async Task<IActionResult> 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();

Expand Down
24 changes: 14 additions & 10 deletions server/Tingle.Dependabot/Dockerfile
Original file line number Diff line number Diff line change
@@ -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
Expand Down
8 changes: 5 additions & 3 deletions server/Tingle.Dependabot/Dockerfile.CI
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public static PropertyBuilder<T> HasJsonConversion<T>(this PropertyBuilder<T> pr

private static List<T> ConvertFromString<T>(string? value, string separator, JsonSerializerOptions? serializerOptions) where T : IConvertible
{
if (string.IsNullOrWhiteSpace(value)) return new List<T>();
if (string.IsNullOrWhiteSpace(value)) return [];
if (string.IsNullOrWhiteSpace(separator))
{
throw new ArgumentException($"'{nameof(separator)}' cannot be null or whitespace.", nameof(separator));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public class AzdoSubscription
public required string PublisherId { get; set; }

[JsonPropertyName("publisherInputs")]
public Dictionary<string, string> PublisherInputs { get; set; } = new();
public Dictionary<string, string> PublisherInputs { get; set; } = [];

[JsonPropertyName("consumerId")]
public string? ConsumerId { get; set; }
Expand All @@ -84,7 +84,7 @@ public class AzdoSubscription
public string? ConsumerActionId { get; set; }

[JsonPropertyName("consumerInputs")]
public Dictionary<string, string> ConsumerInputs { get; set; } = new();
public Dictionary<string, string> ConsumerInputs { get; set; } = [];

[JsonPropertyName("eventType")]
public required string EventType { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ public class DependabotConfiguration : IValidatableObject
public List<DependabotUpdate>? Updates { get; set; }

[JsonPropertyName("registries")]
public Dictionary<string, DependabotRegistry> Registries { get; set; } = new();
public Dictionary<string, DependabotRegistry> Registries { get; set; } = [];

public IEnumerable<ValidationResult> 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();
Expand Down
4 changes: 1 addition & 3 deletions server/Tingle.Dependabot/Models/MainDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@

namespace Tingle.Dependabot.Models;

public class MainDbContext : DbContext, IDataProtectionKeyContext
public class MainDbContext(DbContextOptions<MainDbContext> options) : DbContext(options), IDataProtectionKeyContext
{
public MainDbContext(DbContextOptions<MainDbContext> options) : base(options) { }

public DbSet<Project> Projects => Set<Project>();
public DbSet<Repository> Repositories => Set<Repository>();
public DbSet<UpdateJob> UpdateJobs => Set<UpdateJob>();
Expand Down
Loading

0 comments on commit c67c7a2

Please sign in to comment.