Skip to content

Commit

Permalink
Added converters for AzureDevOpsProjectUrl hence use as the type in t…
Browse files Browse the repository at this point in the history
…he database
  • Loading branch information
mburumaxwell committed Sep 21, 2023
1 parent 606d2d8 commit 9165ccf
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 15 deletions.
6 changes: 3 additions & 3 deletions server/Tingle.Dependabot/AppSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ internal static class AppSetup
{
private class ProjectSetupInfo
{
public required Uri Url { get; set; }
public required AzureDevOpsProjectUrl Url { get; set; }
public required string Token { get; set; }
public bool AutoComplete { get; set; }
public List<int>? AutoCompleteIgnoreConfigs { get; set; }
Expand Down Expand Up @@ -50,8 +50,8 @@ public static async Task SetupAsync(WebApplication app, CancellationToken cancel
var projects = await context.Projects.ToListAsync(cancellationToken);
foreach (var setup in setups)
{
var url = (AzureDevOpsProjectUrl)setup.Url;
var project = projects.SingleOrDefault(p => new Uri(p.Url!) == setup.Url);
var url = setup.Url;
var project = projects.SingleOrDefault(p => p.Url == setup.Url);
if (project is null)
{
project = new Models.Management.Project
Expand Down
24 changes: 24 additions & 0 deletions server/Tingle.Dependabot/Models/MainDbContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Tingle.Dependabot.Models.Management;
using Tingle.Dependabot.Workflow;

namespace Tingle.Dependabot.Models;

Expand All @@ -14,6 +17,13 @@ public MainDbContext(DbContextOptions<MainDbContext> options) : base(options) {

public DbSet<DataProtectionKey> DataProtectionKeys => Set<DataProtectionKey>();

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
base.ConfigureConventions(configurationBuilder);

configurationBuilder.Properties<AzureDevOpsProjectUrl>().HaveConversion<AzureDevOpsProjectUrlConverter, AzureDevOpsProjectUrlComparer>();
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
Expand Down Expand Up @@ -60,4 +70,18 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
builder.OwnsOne(j => j.Resources);
});
}

private class AzureDevOpsProjectUrlConverter : ValueConverter<AzureDevOpsProjectUrl, string>
{
public AzureDevOpsProjectUrlConverter() : base(convertToProviderExpression: v => v.ToString(),
convertFromProviderExpression: v => v == null ? default : new AzureDevOpsProjectUrl(v))
{ }
}
private class AzureDevOpsProjectUrlComparer : ValueComparer<AzureDevOpsProjectUrl>
{
public AzureDevOpsProjectUrlComparer() : base(equalsExpression: (l, r) => l == r,
hashCodeExpression: v => v.GetHashCode(),
snapshotExpression: v => new AzureDevOpsProjectUrl(v.ToString()))
{ }
}
}
4 changes: 2 additions & 2 deletions server/Tingle.Dependabot/Models/Management/Project.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using Tingle.Dependabot.Workflow;

namespace Tingle.Dependabot.Models.Management;

Expand Down Expand Up @@ -29,8 +30,7 @@ public class Project
/// <summary>URL for the project.</summary>
/// <example>https://dev.azure.com/tingle/dependabot</example>
[Url]
[Required]
public string? Url { get; set; } // TODO: change this to AzureDevOpsProjectUrl when we have converters for JSON and EfCore hence reduce the conversions all over the code
public AzureDevOpsProjectUrl Url { get; set; }

/// <summary>
/// Token for accessing the project with permissions for repositories, pull requests, and service hooks.
Expand Down
23 changes: 23 additions & 0 deletions server/Tingle.Dependabot/Workflow/AzureDevOpsProjectUrl.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using System.ComponentModel;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Tingle.Dependabot.Workflow;

/// <summary>Easier manager and parser for URLs of projects on Azure DevOps.</summary>
[JsonConverter(typeof(AzureDevOpsProjectUrlJsonConverter))]
[TypeConverter(typeof(AzureDevOpsProjectUrlTypeConverter))]
public readonly struct AzureDevOpsProjectUrl : IEquatable<AzureDevOpsProjectUrl>
{
Expand Down Expand Up @@ -112,4 +115,24 @@ private class AzureDevOpsProjectUrlTypeConverter : TypeConverter
return base.ConvertTo(context, culture, value, destinationType);
}
}

private class AzureDevOpsProjectUrlJsonConverter : JsonConverter<AzureDevOpsProjectUrl>
{
public override AzureDevOpsProjectUrl Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null) return default;
if (reader.TokenType != JsonTokenType.String)
{
throw new InvalidOperationException("Only strings are supported");
}

var str = reader.GetString();
return new AzureDevOpsProjectUrl(str!);
}

public override void Write(Utf8JsonWriter writer, AzureDevOpsProjectUrl value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}
}
10 changes: 5 additions & 5 deletions server/Tingle.Dependabot/Workflow/AzureDevOpsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public async Task<List<string>> CreateOrUpdateSubscriptionsAsync(Project project
};

// fetch the subscriptions
var url = (AzureDevOpsProjectUrl)project.Url!;
var url = project.Url;
var uri = new UriBuilder
{
Scheme = url.Scheme,
Expand Down Expand Up @@ -133,7 +133,7 @@ public async Task<List<string>> CreateOrUpdateSubscriptionsAsync(Project project

public async Task<AzdoProject> GetProjectAsync(Project project, CancellationToken cancellationToken)
{
var url = (AzureDevOpsProjectUrl)project.Url!;
var url = project.Url;
var uri = new UriBuilder
{
Scheme = url.Scheme,
Expand All @@ -148,7 +148,7 @@ public async Task<AzdoProject> GetProjectAsync(Project project, CancellationToke

public async Task<List<AzdoRepository>> GetRepositoriesAsync(Project project, CancellationToken cancellationToken)
{
var url = (AzureDevOpsProjectUrl)project.Url!;
var url = project.Url;
var uri = new UriBuilder
{
Scheme = url.Scheme,
Expand All @@ -164,7 +164,7 @@ public async Task<List<AzdoRepository>> GetRepositoriesAsync(Project project, Ca

public async Task<AzdoRepository> GetRepositoryAsync(Project project, string repositoryIdOrName, CancellationToken cancellationToken)
{
var url = (AzureDevOpsProjectUrl)project.Url!;
var url = project.Url;
var uri = new UriBuilder
{
Scheme = url.Scheme,
Expand All @@ -179,7 +179,7 @@ public async Task<AzdoRepository> GetRepositoryAsync(Project project, string rep

public async Task<AzdoRepositoryItem?> GetConfigurationFileAsync(Project project, string repositoryIdOrName, CancellationToken cancellationToken = default)
{
var url = (AzureDevOpsProjectUrl)project.Url!;
var url = project.Url;

// Try all known paths
foreach (var path in ConfigurationFilePaths)
Expand Down
6 changes: 3 additions & 3 deletions server/Tingle.Dependabot/Workflow/Synchronizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public async Task SynchronizeAsync(Project project, bool trigger, CancellationTo
cancellationToken: cancellationToken);

// Track for further synchronization
var sci = new SynchronizerConfigurationItem(((AzureDevOpsProjectUrl)project.Url!).MakeRepositorySlug(adoRepo.Name), adoRepo, item);
var sci = new SynchronizerConfigurationItem(project.Url.MakeRepositorySlug(adoRepo.Name), adoRepo, item);
syncPairs.Add((sci, repository));
}

Expand Down Expand Up @@ -126,7 +126,7 @@ public async Task SynchronizeAsync(Project project, Repository repository, bool
cancellationToken: cancellationToken);

// perform synchronization
var sci = new SynchronizerConfigurationItem(((AzureDevOpsProjectUrl)project.Url!).MakeRepositorySlug(adoRepo.Name), adoRepo, item);
var sci = new SynchronizerConfigurationItem(project.Url.MakeRepositorySlug(adoRepo.Name), adoRepo, item);
await SynchronizeAsync(project, repository, sci, trigger, cancellationToken);
}

Expand Down Expand Up @@ -154,7 +154,7 @@ public async Task SynchronizeAsync(Project project, string? repositoryProviderId
select r).SingleOrDefaultAsync(cancellationToken);

// perform synchronization
var sci = new SynchronizerConfigurationItem(((AzureDevOpsProjectUrl)project.Url!).MakeRepositorySlug(adoRepo.Name), adoRepo, item);
var sci = new SynchronizerConfigurationItem(project.Url.MakeRepositorySlug(adoRepo.Name), adoRepo, item);
await SynchronizeAsync(project, repository, sci, trigger, cancellationToken);
}

Expand Down
4 changes: 2 additions & 2 deletions server/Tingle.Dependabot/Workflow/UpdateRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ internal async Task<IDictionary<string, string>> CreateEnvironmentVariables(Proj
.AddIfNotDefault("DEPENDABOT_MILESTONE", update.Milestone?.ToString());

// Add values for Azure DevOps
var url = (AzureDevOpsProjectUrl)project.Url!;
var url = project.Url;
values.AddIfNotDefault("AZURE_HOSTNAME", url.Hostname)
.AddIfNotDefault("AZURE_ORGANIZATION", url.OrganizationName)
.AddIfNotDefault("AZURE_PROJECT", url.ProjectName)
Expand All @@ -300,7 +300,7 @@ internal async Task<string> WriteJobDefinitionAsync(Project project,
[return: NotNullIfNotNull(nameof(value))]
static JsonNode? ToJsonNode<T>(T? value) => value is null ? null : JsonSerializer.SerializeToNode(value, serializerOptions); // null ensures we do not add to the values

var url = (AzureDevOpsProjectUrl)project.Url!;
var url = project.Url;
var credentialsMetadata = MakeCredentialsMetadata(credentials);

// check if debug is enabled for the project via Feature Management
Expand Down

0 comments on commit 9165ccf

Please sign in to comment.